diff -Nru pytest-2.4.2/CHANGELOG pytest-2.5.1/CHANGELOG --- pytest-2.4.2/CHANGELOG 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/CHANGELOG 2013-12-17 08:00:02.000000000 +0000 @@ -1,4 +1,161 @@ -Changes between 2.4.1 and 2.4.2 +2.5.1 +----------------------------------- + +- merge new documentation styling PR from Tobias Bieniek. + +- fix issue403: allow parametrize of multiple same-name functions within + a collection node. Thanks Andreas Kloeckner and Alex Gaynor for reporting + and analysis. + +- Allow parameterized fixtures to specify the ID of the parameters by + adding an ids argument to pytest.fixture() and pytest.yield_fixture(). + Thanks Floris Bruynooghe. + +- fix issue404 by always using the binary xml escape in the junitxml + plugin. Thanks Ronny Pfannschmidt. + +- fix issue407: fix addoption docstring to point to argparse instead of + optparse. Thanks Daniel D. Wright. + + + +2.5.0 +----------------------------------- + +- dropped python2.5 from automated release testing of pytest itself + which means it's probably going to break soon (but still works + with this release we believe). + +- simplified and fixed implementation for calling finalizers when + parametrized fixtures or function arguments are involved. finalization + is now performed lazily at setup time instead of in the "teardown phase". + While this might sound odd at first, it helps to ensure that we are + correctly handling setup/teardown even in complex code. User-level code + should not be affected unless it's implementing the pytest_runtest_teardown + hook and expecting certain fixture instances are torn down within (very + unlikely and would have been unreliable anyway). + +- PR90: add --color=yes|no|auto option to force terminal coloring + mode ("auto" is default). Thanks Marc Abramowitz. + +- fix issue319 - correctly show unicode in assertion errors. Many + thanks to Floris Bruynooghe for the complete PR. Also means + we depend on py>=1.4.19 now. + +- fix issue396 - correctly sort and finalize class-scoped parametrized + tests independently from number of methods on the class. + +- refix issue323 in a better way -- parametrization should now never + cause Runtime Recursion errors because the underlying algorithm + for re-ordering tests per-scope/per-fixture is not recursive + anymore (it was tail-call recursive before which could lead + to problems for more than >966 non-function scoped parameters). + +- fix issue290 - there is preliminary support now for parametrizing + with repeated same values (sometimes useful to to test if calling + a second time works as with the first time). + +- close issue240 - document precisely how pytest module importing + works, discuss the two common test directory layouts, and how it + interacts with PEP420-namespace packages. + +- fix issue246 fix finalizer order to be LIFO on independent fixtures + depending on a parametrized higher-than-function scoped fixture. + (was quite some effort so please bear with the complexity of this sentence :) + Thanks Ralph Schmitt for the precise failure example. + +- fix issue244 by implementing special index for parameters to only use + indices for paramentrized test ids + +- fix issue287 by running all finalizers but saving the exception + from the first failing finalizer and re-raising it so teardown will + still have failed. We reraise the first failing exception because + it might be the cause for other finalizers to fail. + +- fix ordering when mock.patch or other standard decorator-wrappings + are used with test methods. This fixues issue346 and should + help with random "xdist" collection failures. Thanks to + Ronny Pfannschmidt and Donald Stufft for helping to isolate it. + +- fix issue357 - special case "-k" expressions to allow for + filtering with simple strings that are not valid python expressions. + Examples: "-k 1.3" matches all tests parametrized with 1.3. + "-k None" filters all tests that have "None" in their name + and conversely "-k 'not None'". + Previously these examples would raise syntax errors. + +- fix issue384 by removing the trial support code + since the unittest compat enhancements allow + trial to handle it on its own + +- don't hide an ImportError when importing a plugin produces one. + fixes issue375. + +- fix issue275 - allow usefixtures and autouse fixtures + for running doctest text files. + +- fix issue380 by making --resultlog only rely on longrepr instead + of the "reprcrash" attribute which only exists sometimes. + +- address issue122: allow @pytest.fixture(params=iterator) by exploding + into a list early on. + +- fix pexpect-3.0 compatibility for pytest's own tests. + (fixes issue386) + +- allow nested parametrize-value markers, thanks James Lan for the PR. + +- fix unicode handling with new monkeypatch.setattr(import_path, value) + API. Thanks Rob Dennis. Fixes issue371. + +- fix unicode handling with junitxml, fixes issue368. + +- In assertion rewriting mode on Python 2, fix the detection of coding + cookies. See issue #330. + +- make "--runxfail" turn imperative pytest.xfail calls into no ops + (it already did neutralize pytest.mark.xfail markers) + +- refine pytest / pkg_resources interactions: The AssertionRewritingHook + PEP302 compliant loader now registers itself with setuptools/pkg_resources + properly so that the pkg_resources.resource_stream method works properly. + Fixes issue366. Thanks for the investigations and full PR to Jason R. Coombs. + +- pytestconfig fixture is now session-scoped as it is the same object during the + whole test run. Fixes issue370. + +- avoid one surprising case of marker malfunction/confusion:: + + @pytest.mark.some(lambda arg: ...) + def test_function(): + + would not work correctly because pytest assumes @pytest.mark.some + gets a function to be decorated already. We now at least detect if this + arg is an lambda and thus the example will work. Thanks Alex Gaynor + for bringing it up. + +- xfail a test on pypy that checks wrong encoding/ascii (pypy does + not error out). fixes issue385. + +- internally make varnames() deal with classes's __init__, + although it's not needed by pytest itself atm. Also + fix caching. Fixes issue376. + +- fix issue221 - handle importing of namespace-package with no + __init__.py properly. + +- refactor internal FixtureRequest handling to avoid monkeypatching. + One of the positive user-facing effects is that the "request" object + can now be used in closures. + +- fixed version comparison in pytest.importskip(modname, minverstring) + +- fix issue377 by clarifying in the nose-compat docs that pytest + does not duplicate the unittest-API into the "plain" namespace. + +- fix verbose reporting for @mock'd test functions + +v2.4.2 ----------------------------------- - on Windows require colorama and a newer py lib so that py.io.TerminalWriter() @@ -24,19 +181,19 @@ - remove attempt to "dup" stdout at startup as it's icky. the normal capturing should catch enough possibilities - of tests messing up standard FDs. + of tests messing up standard FDs. -- add pluginmanager.do_configure(config) as a link to +- add pluginmanager.do_configure(config) as a link to config.do_configure() for plugin-compatibility -Changes between 2.4.0 and 2.4.1 +v2.4.1 ----------------------------------- - When using parser.addoption() unicode arguments to the "type" keyword should also be converted to the respective types. thanks Floris Bruynooghe, @dnozay. (fixes issue360 and issue362) -- fix dotted filename completion when using argcomplete +- fix dotted filename completion when using argcomplete thanks Anthon van der Neuth. (fixes issue361) - fix regression when a 1-tuple ("arg",) is used for specifying @@ -45,7 +202,7 @@ - merge doc typo fixes, thanks Andy Dirnberger -Changes between 2.3.5 and 2.4 +v2.4 ----------------------------------- known incompatibilities: @@ -92,12 +249,12 @@ - make "import pdb ; pdb.set_trace()" work natively wrt capturing (no "-s" needed anymore), making ``pytest.set_trace()`` a mere shortcut. -- fix issue181: --pdb now also works on collect errors (and - on internal errors) . This was implemented by a slight internal - refactoring and the introduction of a new hook +- fix issue181: --pdb now also works on collect errors (and + on internal errors) . This was implemented by a slight internal + refactoring and the introduction of a new hook ``pytest_exception_interact`` hook (see next item). -- fix issue341: introduce new experimental hook for IDEs/terminals to +- fix issue341: introduce new experimental hook for IDEs/terminals to intercept debugging: ``pytest_exception_interact(node, call, report)``. - new monkeypatch.setattr() variant to provide a shorter @@ -115,7 +272,7 @@ phase of a node. - simplify pytest.mark.parametrize() signature: allow to pass a - CSV-separated string to specify argnames. For example: + CSV-separated string to specify argnames. For example: ``pytest.mark.parametrize("input,expected", [(1,2), (2,3)])`` works as well as the previous: ``pytest.mark.parametrize(("input", "expected"), ...)``. @@ -140,10 +297,10 @@ Bug fixes: -- fix issue358 - capturing options are now parsed more properly +- fix issue358 - capturing options are now parsed more properly by using a new parser.parse_known_args method. -- pytest now uses argparse instead of optparse (thanks Anthon) which +- pytest now uses argparse instead of optparse (thanks Anthon) which means that "argparse" is added as a dependency if installing into python2.6 environments or below. @@ -184,7 +341,7 @@ - fix issue323 - sorting of many module-scoped arg parametrizations - make sessionfinish hooks execute with the same cwd-context as at - session start (helps fix plugin behaviour which write output files + session start (helps fix plugin behaviour which write output files with relative path such as pytest-cov) - fix issue316 - properly reference collection hooks in docs @@ -192,7 +349,7 @@ - fix issue 306 - cleanup of -k/-m options to only match markers/test names/keywords respectively. Thanks Wouter van Ackooy. -- improved doctest counting for doctests in python modules -- +- improved doctest counting for doctests in python modules -- files without any doctest items will not show up anymore and doctest examples are counted as separate test items. thanks Danilo Bellini. @@ -202,7 +359,7 @@ mode. Thanks Jason R. Coombs. - fix junitxml generation when test output contains control characters, - addressing issue267, thanks Jaap Broekhuizen + addressing issue267, thanks Jaap Broekhuizen - fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. @@ -211,10 +368,10 @@ - better parametrize error messages, thanks Brianna Laugher - pytest_terminal_summary(terminalreporter) hooks can now use - ".section(title)" and ".line(msg)" methods to print extra + ".section(title)" and ".line(msg)" methods to print extra information at the end of a test run. -Changes between 2.3.4 and 2.3.5 +v2.3.5 ----------------------------------- - fix issue169: respect --tb=style with setup/teardown errors as well. @@ -265,7 +422,7 @@ - fix bug where using capsys with pytest.set_trace() in a test function would break when looking at capsys.readouterr() -- allow to specify prefixes starting with "_" when +- allow to specify prefixes starting with "_" when customizing python_functions test discovery. (thanks Graham Horler) - improve PYTEST_DEBUG tracing output by puting @@ -279,10 +436,10 @@ - fix issue266 - accept unicode in MarkEvaluator expressions -Changes between 2.3.3 and 2.3.4 +v2.3.4 ----------------------------------- -- yielded test functions will now have autouse-fixtures active but +- yielded test functions will now have autouse-fixtures active but cannot accept fixtures as funcargs - it's anyway recommended to rather use the post-2.0 parametrize features instead of yield, see: http://pytest.org/latest/example/parametrize.html @@ -297,9 +454,9 @@ can write: -k "name1 or name2" etc. This is a slight incompatibility if you used special syntax like "TestClass.test_method" which you now need to write as -k "TestClass and test_method" to match a certain - method in a certain test class. + method in a certain test class. -Changes between 2.3.2 and 2.3.3 +v2.3.3 ----------------------------------- - fix issue214 - parse modules that contain special objects like e. g. @@ -331,10 +488,10 @@ - fix issue127 - improve documentation for pytest_addoption() and add a ``config.getoption(name)`` helper function for consistency. -Changes between 2.3.1 and 2.3.2 +v2.3.2 ----------------------------------- -- fix issue208 and fix issue29 use new py version to avoid long pauses +- fix issue208 and fix issue29 use new py version to avoid long pauses when printing tracebacks in long modules - fix issue205 - conftests in subdirs customizing @@ -364,7 +521,7 @@ - add tox.ini to pytest distribution so that ignore-dirs and others config bits are properly distributed for maintainers who run pytest-own tests -Changes between 2.3.0 and 2.3.1 +v2.3.1 ----------------------------------- - fix issue202 - fix regression: using "self" from fixture functions now @@ -377,7 +534,7 @@ - link to web pages from --markers output which provides help for pytest.mark.* usage. -Changes between 2.2.4 and 2.3.0 +v2.3.0 ----------------------------------- - fix issue202 - better automatic names for parametrized test functions @@ -418,7 +575,7 @@ - pluginmanager.register(...) now raises ValueError if the plugin has been already registered or the name is taken -- fix issue159: improve http://pytest.org/latest/faq.html +- fix issue159: improve http://pytest.org/latest/faq.html especially with respect to the "magic" history, also mention pytest-django, trial and unittest integration. @@ -449,14 +606,14 @@ you can use startdir.bestrelpath(yourpath) to show nice relative path - - allow plugins to implement both pytest_report_header and + - allow plugins to implement both pytest_report_header and pytest_sessionstart (sessionstart is invoked first). - don't show deselected reason line if there is none - py.test -vv will show all of assert comparisations instead of truncating -Changes between 2.2.3 and 2.2.4 +v2.2.4 ----------------------------------- - fix error message for rewritten assertions involving the % operator @@ -473,17 +630,17 @@ - fix issue #144: better mangle test ids to junitxml classnames - upgrade distribute_setup.py to 0.6.27 -Changes between 2.2.2 and 2.2.3 +v2.2.3 ---------------------------------------- - fix uploaded package to only include neccesary files -Changes between 2.2.1 and 2.2.2 +v2.2.2 ---------------------------------------- - fix issue101: wrong args to unittest.TestCase test function now produce better output -- fix issue102: report more useful errors and hints for when a +- fix issue102: report more useful errors and hints for when a test directory was renamed and some pyc/__pycache__ remain - fix issue106: allow parametrize to be applied multiple times e.g. from module, class and at function level. @@ -498,11 +655,11 @@ - allow adding of attributes to test reports such that it also works with distributed testing (no upgrade of pytest-xdist needed) -Changes between 2.2.0 and 2.2.1 +v2.2.1 ---------------------------------------- - fix issue99 (in pytest and py) internallerrors with resultlog now - produce better output - fixed by normalizing pytest_internalerror + produce better output - fixed by normalizing pytest_internalerror input arguments. - fix issue97 / traceback issues (in pytest and py) improve traceback output in conjunction with jinja2 and cython which hack tracebacks @@ -510,25 +667,25 @@ the final test in a test node will now run its teardown directly instead of waiting for the end of the session. Thanks Dave Hunt for the good reporting and feedback. The pytest_runtest_protocol as well - as the pytest_runtest_teardown hooks now have "nextitem" available + as the pytest_runtest_teardown hooks now have "nextitem" available which will be None indicating the end of the test run. - fix collection crash due to unknown-source collected items, thanks to Ralf Schmitt (fixed by depending on a more recent pylib) -Changes between 2.1.3 and 2.2.0 +v2.2.0 ---------------------------------------- - fix issue90: introduce eager tearing down of test items so that teardown function are called earlier. -- add an all-powerful metafunc.parametrize function which allows to +- add an all-powerful metafunc.parametrize function which allows to parametrize test function arguments in multiple steps and therefore - from indepdenent plugins and palces. + from indepdenent plugins and palces. - add a @pytest.mark.parametrize helper which allows to easily call a test function with different argument values -- Add examples to the "parametrize" example page, including a quick port +- Add examples to the "parametrize" example page, including a quick port of Test scenarios and the new parametrize function and decorator. - introduce registration for "pytest.mark.*" helpers via ini-files - or through plugin hooks. Also introduce a "--strict" option which + or through plugin hooks. Also introduce a "--strict" option which will treat unregistered markers as errors allowing to avoid typos and maintain a well described set of markers for your test suite. See exaples at http://pytest.org/latest/mark.html @@ -537,12 +694,12 @@ (this is a stricter and more predictable version of '-k' in that "-m" only matches complete markers and has more obvious rules for and/or semantics. -- new feature to help optimizing the speed of your tests: - --durations=N option for displaying N slowest test calls +- new feature to help optimizing the speed of your tests: + --durations=N option for displaying N slowest test calls and setup/teardown methods. - fix issue87: --pastebin now works with python3 - fix issue89: --pdb with unexpected exceptions in doctest work more sensibly -- fix and cleanup pytest's own test suite to not leak FDs +- fix and cleanup pytest's own test suite to not leak FDs - fix issue83: link to generated funcarg list - fix issue74: pyarg module names are now checked against imp.find_module false positives - fix compatibility with twisted/trial-11.1.0 use cases @@ -550,7 +707,7 @@ - simplify junitxml output code by relying on py.xml - add support for skip properties on unittest classes and functions -Changes between 2.1.2 and 2.1.3 +v2.1.3 ---------------------------------------- - fix issue79: assertion rewriting failed on some comparisons in boolops @@ -559,7 +716,7 @@ - fix issue75 / skipping test failure on jython - fix issue77 / Allow assertrepr_compare hook to apply to a subset of tests -Changes between 2.1.1 and 2.1.2 +v2.1.2 ---------------------------------------- - fix assertion rewriting on files with windows newlines on some Python versions @@ -569,7 +726,7 @@ - fix issue66: use different assertion rewriting caches when the -O option is passed - don't try assertion rewriting on Jython, use reinterp -Changes between 2.1.0 and 2.1.1 +v2.1.1 ---------------------------------------------- - fix issue64 / pytest.set_trace now works within pytest_generate_tests hooks @@ -582,7 +739,7 @@ - fix issue61: assertion rewriting on boolean operations with 3 or more operands - you can now build a man page with "cd doc ; make man" -Changes between 2.0.3 and 2.1.0.DEV +v2.1.0 ---------------------------------------------- - fix issue53 call nosestyle setup functions with correct ordering @@ -602,7 +759,7 @@ - report KeyboardInterrupt even if interrupted during session startup - fix issue 35 - provide PDF doc version and download link from index page -Changes between 2.0.2 and 2.0.3 +v2.0.3 ---------------------------------------------- - fix issue38: nicer tracebacks on calls to hooks, particularly early @@ -622,7 +779,7 @@ - fix issue37: avoid invalid characters in junitxml's output -Changes between 2.0.1 and 2.0.2 +v2.0.2 ---------------------------------------------- - tackle issue32 - speed up test runs of very quick test functions @@ -634,17 +791,17 @@ Also you can now access module globals from xfail/skipif expressions so that this for example works now:: - + import pytest import mymodule @pytest.mark.skipif("mymodule.__version__[0] == "1") def test_function(): pass - This will not run the test function if the module's version string + This will not run the test function if the module's version string does not start with a "1". Note that specifying a string instead - of a boolean expressions allows py.test to report meaningful information - when summarizing a test run as to what conditions lead to skipping + of a boolean expressions allows py.test to report meaningful information + when summarizing a test run as to what conditions lead to skipping (or xfail-ing) tests. - fix issue28 - setup_method and pytest_generate_tests work together @@ -667,14 +824,14 @@ - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular thanks to Laura Creighton who also revieved parts of the documentation. -- fix slighly wrong output of verbose progress reporting for classes +- fix slighly wrong output of verbose progress reporting for classes (thanks Amaury) - more precise (avoiding of) deprecation warnings for node.Class|Function accesses - avoid std unittest assertion helper code in tracebacks (thanks Ronny) -Changes between 2.0.0 and 2.0.1 +v2.0.1 ---------------------------------------------- - refine and unify initial capturing so that it works nicely @@ -683,7 +840,7 @@ - allow to omit "()" in test ids to allow for uniform test ids as produced by Alfredo's nice pytest.vim plugin. - fix issue12 - show plugin versions with "--version" and - "--traceconfig" and also document how to add extra information + "--traceconfig" and also document how to add extra information to reporting test header - fix issue17 (import-* reporting issue on python3) by requiring py>1.4.0 (1.4.1 is going to include it) @@ -713,17 +870,17 @@ - fix issue14: no logging errors at process exit - refinements to "collecting" output on non-ttys - refine internal plugin registration and --traceconfig output -- introduce a mechanism to prevent/unregister plugins from the +- introduce a mechanism to prevent/unregister plugins from the command line, see http://pytest.org/plugins.html#cmdunregister - activate resultlog plugin by default - fix regression wrt yielded tests which due to the - collection-before-running semantics were not + collection-before-running semantics were not setup as with pytest 1.3.4. Note, however, that - the recommended and much cleaner way to do test + the recommended and much cleaner way to do test parametraization remains the "pytest_generate_tests" mechanism, see the docs. -Changes between 1.3.4 and 2.0.0 +v2.0.0 ---------------------------------------------- - pytest-2.0 is now its own package and depends on pylib-2.0 @@ -768,7 +925,7 @@ - add ability to use "class" level for cached_setup helper - fix strangeness: mark.* objects are now immutable, create new instances -Changes between 1.3.3 and 1.3.4 +v1.3.4 ---------------------------------------------- - fix issue111: improve install documentation for windows @@ -777,7 +934,7 @@ - fix issue115: unify internal exception passthrough/catching/GeneratorExit - fix issue118: new --tb=native for presenting cpython-standard exceptions -Changes between 1.3.2 and 1.3.3 +v1.3.3 ---------------------------------------------- - fix issue113: assertion representation problem with triple-quoted strings @@ -792,7 +949,7 @@ (thanks Armin Ronacher for reporting) - remove trailing whitespace in all py/text distribution files -Changes between 1.3.1 and 1.3.2 +v1.3.2 ---------------------------------------------- New features @@ -867,7 +1024,7 @@ - fix homedir detection on Windows - ship distribute_setup.py version 0.6.13 -Changes between 1.3.0 and 1.3.1 +v1.3.1 --------------------------------------------- New features @@ -939,7 +1096,7 @@ (and internally be more careful when presenting unexpected byte sequences) -Changes between 1.2.1 and 1.3.0 +v1.3.0 --------------------------------------------- - deprecate --report option in favour of a new shorter and easier to @@ -1004,7 +1161,7 @@ - added links to the new capturelog and coverage plugins -Changes between 1.2.1 and 1.2.0 +v1.2.0 --------------------------------------------- - refined usage and options for "py.cleanup":: @@ -1043,7 +1200,7 @@ - fix plugin links -Changes between 1.2 and 1.1.1 +v1.1.1 --------------------------------------------- - moved dist/looponfailing from py.test core into a new @@ -1127,7 +1284,7 @@ - fix docs, fix internal bin/ script generation -Changes between 1.1.1 and 1.1.0 +v1.1.0 --------------------------------------------- - introduce automatic plugin registration via 'pytest11' @@ -1146,7 +1303,7 @@ - try harder to have deprecation warnings for py.compat.* accesses report a correct location -Changes between 1.1.0 and 1.0.2 +v1.0.2 --------------------------------------------- * adjust and improve docs @@ -1231,7 +1388,7 @@ * simplified internal localpath implementation -Changes between 1.0.1 and 1.0.2 +v1.0.2 ------------------------------------------- * fixing packaging issues, triggered by fedora redhat packaging, @@ -1239,7 +1396,7 @@ * added a documentation link to the new django plugin. -Changes between 1.0.0 and 1.0.1 +v1.0.1 ------------------------------------------- * added a 'pytest_nose' plugin which handles nose.SkipTest, @@ -1273,13 +1430,13 @@ * simplified multicall mechanism and plugin architecture, renamed some internal methods and argnames -Changes between 1.0.0b9 and 1.0.0 +v1.0.0 ------------------------------------------- * more terse reporting try to show filesystem path relatively to current dir * improve xfail output a bit -Changes between 1.0.0b8 and 1.0.0b9 +v1.0.0b9 ------------------------------------------- * cleanly handle and report final teardown of test setup @@ -1313,7 +1470,7 @@ * item.repr_failure(excinfo) instead of item.repr_failure(excinfo, outerr) -Changes between 1.0.0b7 and 1.0.0b8 +v1.0.0b8 ------------------------------------------- * pytest_unittest-plugin is now enabled by default @@ -1342,7 +1499,7 @@ * tweaked doctest output for docstrings in py modules, thanks Radomir. -Changes between 1.0.0b3 and 1.0.0b7 +v1.0.0b7 ------------------------------------------- * renamed py.test.xfail back to py.test.mark.xfail to avoid @@ -1367,7 +1524,7 @@ * make __name__ == "__channelexec__" for remote_exec code -Changes between 1.0.0b1 and 1.0.0b3 +v1.0.0b3 ------------------------------------------- * plugin classes are removed: one now defines @@ -1384,7 +1541,7 @@ well with function arguments. -Changes between 0.9.2 and 1.0.0b1 +v1.0.0b1 ------------------------------------------- * introduced new "funcarg" setup method, @@ -1408,7 +1565,7 @@ XXX lots of things missing here XXX -Changes between 0.9.1 and 0.9.2 +v0.9.2 ------------------------------------------- * refined installation and metadata, created new setup.py, @@ -1441,10 +1598,10 @@ * there now is a py.__version__ attribute -Changes between 0.9.0 and 0.9.1 +v0.9.1 ------------------------------------------- -This is a fairly complete list of changes between 0.9 and 0.9.1, which can +This is a fairly complete list of v0.9.1, which can serve as a reference for developers. * allowing + signs in py.path.svn urls [39106] diff -Nru pytest-2.4.2/PKG-INFO pytest-2.5.1/PKG-INFO --- pytest-2.4.2/PKG-INFO 2013-10-04 12:12:41.000000000 +0000 +++ pytest-2.5.1/PKG-INFO 2013-12-17 08:00:02.000000000 +0000 @@ -1,14 +1,18 @@ Metadata-Version: 1.1 Name: pytest -Version: 2.4.2 +Version: 2.5.1 Summary: py.test: simple powerful testing with Python Home-page: http://pytest.org Author: Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others Author-email: holger at merlinux.eu License: MIT license Description: + Documentation: http://pytest.org/latest/ + Changelog: http://pytest.org/latest/changelog.html + Issues: https://bitbucket.org/hpk42/pytest/issues?status=open + The ``py.test`` testing tool makes it easy to write small tests, yet scales to support complex functional testing. It provides @@ -71,8 +75,6 @@ Classifier: Topic :: Utilities Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.0 diff -Nru pytest-2.4.2/README.rst pytest-2.5.1/README.rst --- pytest-2.4.2/README.rst 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/README.rst 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,10 @@ +Documentation: http://pytest.org/latest/ + Changelog: http://pytest.org/latest/changelog.html +Issues: https://bitbucket.org/hpk42/pytest/issues?status=open + The ``py.test`` testing tool makes it easy to write small tests, yet scales to support complex functional testing. It provides diff -Nru pytest-2.4.2/_pytest/__init__.py pytest-2.5.1/_pytest/__init__.py --- pytest-2.4.2/_pytest/__init__.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/__init__.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,2 +1,2 @@ # -__version__ = '2.4.2' +__version__ = '2.5.1' diff -Nru pytest-2.4.2/_pytest/assertion/__init__.py pytest-2.5.1/_pytest/assertion/__init__.py --- pytest-2.4.2/_pytest/assertion/__init__.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/assertion/__init__.py 2013-12-17 08:00:02.000000000 +0000 @@ -34,7 +34,7 @@ mode = "plain" if mode == "rewrite": try: - import ast + import ast # noqa except ImportError: mode = "reinterp" else: @@ -48,10 +48,10 @@ m = monkeypatch() config._cleanup.append(m.undo) m.setattr(py.builtin.builtins, 'AssertionError', - reinterpret.AssertionError) + reinterpret.AssertionError) # noqa hook = None if mode == "rewrite": - hook = rewrite.AssertionRewritingHook() + hook = rewrite.AssertionRewritingHook() # noqa sys.meta_path.insert(0, hook) warn_about_missing_assertion(mode) config._assertstate = AssertionState(config, mode) @@ -78,10 +78,13 @@ for new_expl in hook_result: if new_expl: - # Don't include pageloads of data unless we are very verbose (-vv) - if len(''.join(new_expl[1:])) > 80*8 and item.config.option.verbose < 2: - new_expl[1:] = ['Detailed information truncated, use "-vv" to see'] - res = '\n~'.join(new_expl) + # Don't include pageloads of data unless we are very + # verbose (-vv) + if (len(py.builtin._totext('').join(new_expl[1:])) > 80*8 + and item.config.option.verbose < 2): + new_expl[1:] = [py.builtin._totext( + 'Detailed information truncated, use "-vv" to see')] + res = py.builtin._totext('\n~').join(new_expl) if item.config.getvalue("assertmode") == "rewrite": # The result will be fed back a python % formatting # operation, which will fail if there are extraneous @@ -101,9 +104,9 @@ def _load_modules(mode): """Lazily import assertion related code.""" global rewrite, reinterpret - from _pytest.assertion import reinterpret + from _pytest.assertion import reinterpret # noqa if mode == "rewrite": - from _pytest.assertion import rewrite + from _pytest.assertion import rewrite # noqa def warn_about_missing_assertion(mode): try: diff -Nru pytest-2.4.2/_pytest/assertion/reinterpret.py pytest-2.5.1/_pytest/assertion/reinterpret.py --- pytest-2.4.2/_pytest/assertion/reinterpret.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/assertion/reinterpret.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,18 +1,26 @@ import sys import py from _pytest.assertion.util import BuiltinAssertionError +u = py.builtin._totext + class AssertionError(BuiltinAssertionError): def __init__(self, *args): BuiltinAssertionError.__init__(self, *args) if args: + # on Python2.6 we get len(args)==2 for: assert 0, (x,y) + # on Python2.7 and above we always get len(args) == 1 + # with args[0] being the (x,y) tuple. + if len(args) > 1: + toprint = args + else: + toprint = args[0] try: - self.msg = str(args[0]) - except py.builtin._sysex: - raise - except: - self.msg = "<[broken __repr__] %s at %0xd>" %( - args[0].__class__, id(args[0])) + self.msg = u(toprint) + except Exception: + self.msg = u( + "<[broken __repr__] %s at %0xd>" + % (toprint.__class__, id(toprint))) else: f = py.code.Frame(sys._getframe(1)) try: diff -Nru pytest-2.4.2/_pytest/assertion/rewrite.py pytest-2.5.1/_pytest/assertion/rewrite.py --- pytest-2.4.2/_pytest/assertion/rewrite.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/assertion/rewrite.py 2013-12-17 08:00:02.000000000 +0000 @@ -41,6 +41,7 @@ def __init__(self): self.session = None self.modules = {} + self._register_with_pkg_resources() def set_session(self, session): self.fnpats = session.config.getini("python_files") @@ -55,8 +56,12 @@ names = name.rsplit(".", 1) lastname = names[-1] pth = None - if path is not None and len(path) == 1: - pth = path[0] + if path is not None: + # Starting with Python 3.3, path is a _NamespacePath(), which + # causes problems if not converted to list. + path = list(path) + if len(path) == 1: + pth = path[0] if pth is None: try: fd, fn, desc = imp.find_module(lastname, path) @@ -169,6 +174,24 @@ tp = desc[2] return tp == imp.PKG_DIRECTORY + @classmethod + def _register_with_pkg_resources(cls): + """ + Ensure package resources can be loaded from this loader. May be called + multiple times, as the operation is idempotent. + """ + try: + import pkg_resources + # access an attribute in case a deferred importer is present + pkg_resources.__name__ + except ImportError: + return + + # Since pytest tests are always located in the file system, the + # DefaultProvider is appropriate. + pkg_resources.register_loader_type(cls, pkg_resources.DefaultProvider) + + def _write_pyc(state, co, source_path, pyc): # Technically, we don't have to have the same pyc format as # (C)Python, since these "pycs" should never be seen by builtin @@ -196,7 +219,7 @@ RN = "\r\n".encode("utf-8") N = "\n".encode("utf-8") -cookie_re = re.compile("coding[:=]\s*[-\w.]+") +cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+") BOM_UTF8 = '\xef\xbb\xbf' def _rewrite_test(state, fn): @@ -220,8 +243,8 @@ end1 = source.find("\n") end2 = source.find("\n", end1 + 1) if (not source.startswith(BOM_UTF8) and - (not cookie_re.match(source[0:end1]) or - not cookie_re.match(source[end1:end2]))): + cookie_re.match(source[0:end1]) is None and + cookie_re.match(source[end1 + 1:end2]) is None): if hasattr(state, "_indecode"): return None # encodings imported us again, we don't rewrite state._indecode = True @@ -300,7 +323,7 @@ _saferepr = py.io.saferepr -from _pytest.assertion.util import format_explanation as _format_explanation +from _pytest.assertion.util import format_explanation as _format_explanation # noqa def _should_repr_global_name(obj): return not hasattr(obj, "__name__") and not py.builtin.callable(obj) @@ -538,7 +561,8 @@ for i, v in enumerate(boolop.values): if i: fail_inner = [] - self.on_failure.append(ast.If(cond, fail_inner, [])) + # cond is set in a prior loop iteration below + self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa self.on_failure = fail_inner self.push_format_context() res, expl = self.visit(v) @@ -631,7 +655,7 @@ res_expr = ast.Compare(left_res, [op], [next_res]) self.statements.append(ast.Assign([store_names[i]], res_expr)) left_res, left_expl = next_res, next_expl - # Use py.code._reprcompare if that's available. + # Use pytest.assertion.util._reprcompare if that's available. expl_call = self.helper("call_reprcompare", ast.Tuple(syms, ast.Load()), ast.Tuple(load_names, ast.Load()), diff -Nru pytest-2.4.2/_pytest/assertion/util.py pytest-2.5.1/_pytest/assertion/util.py --- pytest-2.4.2/_pytest/assertion/util.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/assertion/util.py 2013-12-17 08:00:02.000000000 +0000 @@ -11,6 +11,7 @@ BuiltinAssertionError = py.builtin.builtins.AssertionError +u = py.builtin._totext # The _reprcompare attribute on the util module is used by the new assertion # interpretation code and assertion rewriter to detect this plugin was @@ -29,7 +30,18 @@ for when one explanation needs to span multiple lines, e.g. when displaying diffs. """ - # simplify 'assert False where False = ...' + explanation = _collapse_false(explanation) + lines = _split_explanation(explanation) + result = _format_lines(lines) + return u('\n').join(result) + + +def _collapse_false(explanation): + """Collapse expansions of False + + So this strips out any "assert False\n{where False = ...\n}" + blocks. + """ where = 0 while True: start = where = explanation.find("False\n{False = ", where) @@ -51,28 +63,48 @@ explanation = (explanation[:start] + explanation[start+15:end-1] + explanation[end+1:]) where -= 17 - raw_lines = (explanation or '').split('\n') - # escape newlines not followed by {, } and ~ + return explanation + + +def _split_explanation(explanation): + """Return a list of individual lines in the explanation + + This will return a list of lines split on '\n{', '\n}' and '\n~'. + Any other newlines will be escaped and appear in the line as the + literal '\n' characters. + """ + raw_lines = (explanation or u('')).split('\n') lines = [raw_lines[0]] for l in raw_lines[1:]: if l.startswith('{') or l.startswith('}') or l.startswith('~'): lines.append(l) else: lines[-1] += '\\n' + l + return lines + + +def _format_lines(lines): + """Format the individual lines + This will replace the '{', '}' and '~' characters of our mini + formatting language with the proper 'where ...', 'and ...' and ' + + ...' text, taking care of indentation along the way. + + Return a list of formatted lines. + """ result = lines[:1] stack = [0] stackcnt = [0] for line in lines[1:]: if line.startswith('{'): if stackcnt[-1]: - s = 'and ' + s = u('and ') else: - s = 'where ' + s = u('where ') stack.append(len(result)) stackcnt[-1] += 1 stackcnt.append(0) - result.append(' +' + ' '*(len(stack)-1) + s + line[1:]) + result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:]) elif line.startswith('}'): assert line.startswith('}') stack.pop() @@ -80,9 +112,9 @@ result[stack[-1]] += line[1:] else: assert line.startswith('~') - result.append(' '*len(stack) + line[1:]) + result.append(u(' ')*len(stack) + line[1:]) assert len(stack) == 1 - return '\n'.join(result) + return result # Provide basestring in python3 @@ -97,7 +129,7 @@ width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op left_repr = py.io.saferepr(left, maxsize=int(width/2)) right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) - summary = '%s %s %s' % (left_repr, op, right_repr) + summary = u('%s %s %s') % (left_repr, op, right_repr) issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and not isinstance(x, basestring)) @@ -120,13 +152,12 @@ elif op == 'not in': if istext(left) and istext(right): explanation = _notin_text(left, right, verbose) - except py.builtin._sysex: - raise - except: + except Exception: excinfo = py.code.ExceptionInfo() explanation = [ - '(pytest_assertion plugin: representation of details failed. ' - 'Probably an object has a faulty __repr__.)', str(excinfo)] + u('(pytest_assertion plugin: representation of details failed. ' + 'Probably an object has a faulty __repr__.)'), + u(excinfo)] if not explanation: return None @@ -148,8 +179,8 @@ break if i > 42: i -= 10 # Provide some context - explanation = ['Skipping %s identical leading ' - 'characters in diff, use -v to show' % i] + explanation = [u('Skipping %s identical leading ' + 'characters in diff, use -v to show') % i] left = left[i:] right = right[i:] if len(left) == len(right): @@ -158,8 +189,8 @@ break if i > 42: i -= 10 # Provide some context - explanation += ['Skipping %s identical trailing ' - 'characters in diff, use -v to show' % i] + explanation += [u('Skipping %s identical trailing ' + 'characters in diff, use -v to show') % i] left = left[:-i] right = right[:-i] explanation += [line.strip('\n') @@ -172,16 +203,15 @@ explanation = [] for i in range(min(len(left), len(right))): if left[i] != right[i]: - explanation += ['At index %s diff: %r != %r' % - (i, left[i], right[i])] + explanation += [u('At index %s diff: %r != %r') + % (i, left[i], right[i])] break if len(left) > len(right): - explanation += [ - 'Left contains more items, first extra item: %s' % - py.io.saferepr(left[len(right)],)] + explanation += [u('Left contains more items, first extra item: %s') + % py.io.saferepr(left[len(right)],)] elif len(left) < len(right): explanation += [ - 'Right contains more items, first extra item: %s' % + u('Right contains more items, first extra item: %s') % py.io.saferepr(right[len(left)],)] return explanation # + _diff_text(py.std.pprint.pformat(left), # py.std.pprint.pformat(right)) @@ -192,11 +222,11 @@ diff_left = left - right diff_right = right - left if diff_left: - explanation.append('Extra items in the left set:') + explanation.append(u('Extra items in the left set:')) for item in diff_left: explanation.append(py.io.saferepr(item)) if diff_right: - explanation.append('Extra items in the right set:') + explanation.append(u('Extra items in the right set:')) for item in diff_right: explanation.append(py.io.saferepr(item)) return explanation @@ -207,25 +237,25 @@ common = set(left).intersection(set(right)) same = dict((k, left[k]) for k in common if left[k] == right[k]) if same and not verbose: - explanation += ['Omitting %s identical items, use -v to show' % + explanation += [u('Omitting %s identical items, use -v to show') % len(same)] elif same: - explanation += ['Common items:'] + explanation += [u('Common items:')] explanation += py.std.pprint.pformat(same).splitlines() diff = set(k for k in common if left[k] != right[k]) if diff: - explanation += ['Differing items:'] + explanation += [u('Differing items:')] for k in diff: explanation += [py.io.saferepr({k: left[k]}) + ' != ' + py.io.saferepr({k: right[k]})] extra_left = set(left) - set(right) if extra_left: - explanation.append('Left contains more items:') + explanation.append(u('Left contains more items:')) explanation.extend(py.std.pprint.pformat( dict((k, left[k]) for k in extra_left)).splitlines()) extra_right = set(right) - set(left) if extra_right: - explanation.append('Right contains more items:') + explanation.append(u('Right contains more items:')) explanation.extend(py.std.pprint.pformat( dict((k, right[k]) for k in extra_right)).splitlines()) return explanation @@ -237,14 +267,14 @@ tail = text[index+len(term):] correct_text = head + tail diff = _diff_text(correct_text, text, verbose) - newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)] + newdiff = [u('%s is contained here:') % py.io.saferepr(term, maxsize=42)] for line in diff: - if line.startswith('Skipping'): + if line.startswith(u('Skipping')): continue - if line.startswith('- '): + if line.startswith(u('- ')): continue - if line.startswith('+ '): - newdiff.append(' ' + line[2:]) + if line.startswith(u('+ ')): + newdiff.append(u(' ') + line[2:]) else: newdiff.append(line) return newdiff diff -Nru pytest-2.4.2/_pytest/config.py pytest-2.5.1/_pytest/config.py --- pytest-2.4.2/_pytest/config.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/config.py 2013-12-17 08:00:02.000000000 +0000 @@ -16,8 +16,7 @@ initialization. """ config = _prepareconfig(args, plugins) - exitstatus = config.hook.pytest_cmdline_main(config=config) - return exitstatus + return config.hook.pytest_cmdline_main(config=config) class cmdline: # compatibility namespace main = staticmethod(main) @@ -41,7 +40,7 @@ return _preinit.pop(0) # subsequent calls to main will create a fresh instance pluginmanager = PytestPluginManager() - pluginmanager.config = config = Config(pluginmanager) # XXX attr needed? + pluginmanager.config = Config(pluginmanager) # XXX attr needed? for spec in default_plugins: pluginmanager.import_plugin(spec) return pluginmanager @@ -129,8 +128,8 @@ :opts: option names, can be short or long options. :attrs: same attributes which the ``add_option()`` function of the - `optparse library - `_ + `argparse library + `_ accepts. After command line parsing options are available on the pytest config diff -Nru pytest-2.4.2/_pytest/core.py pytest-2.5.1/_pytest/core.py --- pytest-2.4.2/_pytest/core.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/core.py 2013-12-17 08:00:02.000000000 +0000 @@ -263,20 +263,11 @@ name = importspec try: mod = "_pytest." + name - #print >>sys.stderr, "tryimport", mod __import__(mod) return sys.modules[mod] except ImportError: - #e = py.std.sys.exc_info()[1] - #if str(e).find(name) == -1: - # raise - pass # - try: - #print >>sys.stderr, "tryimport", importspec __import__(importspec) - except ImportError: - raise ImportError(importspec) - return sys.modules[importspec] + return sys.modules[importspec] class MultiCall: """ execute a call into multiple python functions/methods. """ @@ -313,19 +304,36 @@ return kwargs def varnames(func): + """ return argument name tuple for a function, method, class or callable. + + In case of a class, its "__init__" method is considered. + For methods the "self" parameter is not included unless you are passing + an unbound method with Python3 (which has no supports for unbound methods) + """ + cache = getattr(func, "__dict__", {}) try: - return func._varnames - except AttributeError: + return cache["_varnames"] + except KeyError: pass - if not inspect.isfunction(func) and not inspect.ismethod(func): - func = getattr(func, '__call__', func) - ismethod = inspect.ismethod(func) + if inspect.isclass(func): + try: + func = func.__init__ + except AttributeError: + return () + ismethod = True + else: + if not inspect.isfunction(func) and not inspect.ismethod(func): + func = getattr(func, '__call__', func) + ismethod = inspect.ismethod(func) rawcode = py.code.getrawcode(func) try: x = rawcode.co_varnames[ismethod:rawcode.co_argcount] except AttributeError: x = () - py.builtin._getfuncdict(func)['_varnames'] = x + try: + cache["_varnames"] = x + except TypeError: + pass return x class HookRelay: diff -Nru pytest-2.4.2/_pytest/doctest.py pytest-2.5.1/_pytest/doctest.py --- pytest-2.4.2/_pytest/doctest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/doctest.py 2013-12-17 08:00:02.000000000 +0000 @@ -91,8 +91,13 @@ doctest = py.std.doctest # satisfy `FixtureRequest` constructor... self.funcargs = {} - self._fixtureinfo = FuncFixtureInfo((), [], {}) + fm = self.session._fixturemanager + def func(): + pass + self._fixtureinfo = fm.getfixtureinfo(node=self, func=func, + cls=None, funcargs=False) fixture_request = FixtureRequest(self) + fixture_request._fillfixtures() failed, tot = doctest.testfile( str(self.fspath), module_relative=False, optionflags=doctest.ELLIPSIS, diff -Nru pytest-2.4.2/_pytest/helpconfig.py pytest-2.5.1/_pytest/helpconfig.py --- pytest-2.4.2/_pytest/helpconfig.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/helpconfig.py 2013-12-17 08:00:02.000000000 +0000 @@ -120,7 +120,6 @@ if config.option.traceconfig: lines.append("active plugins:") - plugins = [] items = config.pluginmanager._name2plugin.items() for name, plugin in items: if hasattr(plugin, '__file__'): diff -Nru pytest-2.4.2/_pytest/junitxml.py pytest-2.5.1/_pytest/junitxml.py --- pytest-2.4.2/_pytest/junitxml.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/junitxml.py 2013-12-17 08:00:02.000000000 +0000 @@ -9,7 +9,6 @@ import sys import time - # Python 2.X and 3.X compatibility try: unichr(65) @@ -131,36 +130,36 @@ self.skipped += 1 else: fail = Junit.failure(message="test failure") - fail.append(str(report.longrepr)) + fail.append(bin_xml_escape(report.longrepr)) self.append(fail) self.failed += 1 self._write_captured_output(report) def append_collect_failure(self, report): #msg = str(report.longrepr.reprtraceback.extraline) - self.append(Junit.failure(str(report.longrepr), + self.append(Junit.failure(bin_xml_escape(report.longrepr), message="collection failure")) self.errors += 1 def append_collect_skipped(self, report): #msg = str(report.longrepr.reprtraceback.extraline) - self.append(Junit.skipped(str(report.longrepr), + self.append(Junit.skipped(bin_xml_escape(report.longrepr), message="collection skipped")) self.skipped += 1 def append_error(self, report): - self.append(Junit.error(str(report.longrepr), + self.append(Junit.error(bin_xml_escape(report.longrepr), message="test setup failure")) self.errors += 1 def append_skipped(self, report): if hasattr(report, "wasxfail"): - self.append(Junit.skipped(str(report.wasxfail), + self.append(Junit.skipped(bin_xml_escape(report.wasxfail), message="expected test failure")) else: filename, lineno, skipreason = report.longrepr if skipreason.startswith("Skipped: "): - skipreason = skipreason[9:] + skipreason = bin_xml_escape(skipreason[9:]) self.append( Junit.skipped("%s:%s: %s" % report.longrepr, type="pytest.skip", @@ -194,17 +193,17 @@ def pytest_internalerror(self, excrepr): self.errors += 1 - data = py.xml.escape(excrepr) + data = bin_xml_escape(excrepr) self.tests.append( Junit.testcase( Junit.error(data, message="internal error"), classname="pytest", name="internal")) - def pytest_sessionstart(self, session): + def pytest_sessionstart(self): self.suite_start_time = time.time() - def pytest_sessionfinish(self, session, exitstatus, __multicall__): + def pytest_sessionfinish(self): if py.std.sys.version_info[0] < 3: logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8') else: diff -Nru pytest-2.4.2/_pytest/main.py pytest-2.5.1/_pytest/main.py --- pytest-2.4.2/_pytest/main.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/main.py 2013-12-17 08:00:02.000000000 +0000 @@ -230,6 +230,8 @@ #: allow adding of extra keywords to use for matching self.extra_keyword_matches = set() + # used for storing artificial fixturedefs for direct parametrization + self._name2pseudofixturedef = {} #self.extrainit() @property @@ -270,21 +272,11 @@ self._nodeid = x = self._makeid() return x - def _makeid(self): return self.parent.nodeid + "::" + self.name - def __eq__(self, other): - if not isinstance(other, Node): - return False - return (self.__class__ == other.__class__ and - self.name == other.name and self.parent == other.parent) - - def __ne__(self, other): - return not self == other - def __hash__(self): - return hash((self.name, self.parent)) + return hash(self.nodeid) def setup(self): pass @@ -365,6 +357,8 @@ self.session._setupstate.addfinalizer(fin, self) def getparent(self, cls): + """ get the next parent node (including ourself) + which is an instance of the given class""" current = self while current and not isinstance(current, cls): current = current.parent @@ -425,7 +419,6 @@ def _prunetraceback(self, excinfo): if hasattr(self, 'fspath'): - path = self.fspath traceback = excinfo.traceback ntraceback = traceback.cut(path=self.fspath) if ntraceback == traceback: @@ -698,11 +691,4 @@ yield x node.ihook.pytest_collectreport(report=rep) -def getfslineno(obj): - # xxx let decorators etc specify a sane ordering - if hasattr(obj, 'place_as'): - obj = obj.place_as - fslineno = py.code.getfslineno(obj) - assert isinstance(fslineno[1], int), obj - return fslineno diff -Nru pytest-2.4.2/_pytest/mark.py pytest-2.5.1/_pytest/mark.py --- pytest-2.4.2/_pytest/mark.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/mark.py 2013-12-17 08:00:02.000000000 +0000 @@ -140,7 +140,13 @@ for name in colitem.function.__dict__: mapped_names.add(name) - return eval(keywordexpr, {}, KeywordMapping(mapped_names)) + mapping = KeywordMapping(mapped_names) + if " " not in keywordexpr: + # special case to allow for simple "-k pass" and "-k 1.3" + return mapping[keywordexpr] + elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]: + return not mapping[keywordexpr[4:]] + return eval(keywordexpr, {}, mapping) def pytest_configure(config): @@ -182,6 +188,9 @@ if name not in self._markers: raise AttributeError("%r not a registered marker" % (name,)) +def istestfunc(func): + return hasattr(func, "__call__") and \ + getattr(func, "__name__", "") != "" class MarkDecorator: """ A decorator for test functions and test classes. When applied @@ -217,8 +226,8 @@ otherwise add *args/**kwargs in-place to mark information. """ if args: func = args[0] - if len(args) == 1 and hasattr(func, '__call__') or \ - hasattr(func, '__bases__'): + if len(args) == 1 and (istestfunc(func) or + hasattr(func, '__bases__')): if hasattr(func, '__bases__'): if hasattr(func, 'pytestmark'): l = func.pytestmark diff -Nru pytest-2.4.2/_pytest/monkeypatch.py pytest-2.5.1/_pytest/monkeypatch.py --- pytest-2.4.2/_pytest/monkeypatch.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/monkeypatch.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,7 @@ """ monkeypatching and mocking functionality. """ import os, sys +from py.builtin import _basestring def pytest_funcarg__monkeypatch(request): """The returned ``monkeypatch`` funcarg provides these @@ -28,7 +29,7 @@ def derive_importpath(import_path): import pytest - if not isinstance(import_path, str) or "." not in import_path: + if not isinstance(import_path, _basestring) or "." not in import_path: raise TypeError("must be absolute import path string, not %r" % (import_path,)) rest = [] @@ -85,7 +86,7 @@ import inspect if value is notset: - if not isinstance(target, str): + if not isinstance(target, _basestring): raise TypeError("use setattr(target, name, value) or " "setattr(target, value) with target being a dotted " "import string") @@ -115,7 +116,7 @@ """ __tracebackhide__ = True if name is notset: - if not isinstance(target, str): + if not isinstance(target, _basestring): raise TypeError("use delattr(target, name) or " "delattr(target) with target being a dotted " "import string") diff -Nru pytest-2.4.2/_pytest/pytester.py pytest-2.5.1/_pytest/pytester.py --- pytest-2.4.2/_pytest/pytester.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/pytester.py 2013-12-17 08:00:02.000000000 +0000 @@ -26,7 +26,6 @@ def pytest_configure(config): # This might be called multiple times. Only take the first. global _pytest_fullpath - import pytest try: _pytest_fullpath except NameError: @@ -121,7 +120,6 @@ def contains(self, entries): __tracebackhide__ = True - from py.builtin import print_ i = 0 entries = list(entries) backlocals = py.std.sys._getframe(1).f_locals @@ -260,9 +258,6 @@ def makefile(self, ext, *args, **kwargs): return self._makefile(ext, args, kwargs) - def makeini(self, source): - return self.makefile('cfg', setup=source) - def makeconftest(self, source): return self.makepyfile(conftest=source) @@ -475,7 +470,7 @@ # XXX we rely on script refering to the correct environment # we cannot use "(py.std.sys.executable,script)" # becaue on windows the script is e.g. a py.test.exe - return (py.std.sys.executable, _pytest_fullpath,) + return (py.std.sys.executable, _pytest_fullpath,) # noqa else: py.test.skip("cannot run %r with --no-tools-on-path" % scriptname) @@ -521,15 +516,16 @@ return self.spawn(cmd, expect_timeout=expect_timeout) def spawn(self, cmd, expect_timeout=10.0): - pexpect = py.test.importorskip("pexpect", "2.4") + pexpect = py.test.importorskip("pexpect", "3.0") if hasattr(sys, 'pypy_version_info') and '64' in py.std.platform.machine(): pytest.skip("pypy-64 bit not supported") if sys.platform == "darwin": pytest.xfail("pexpect does not work reliably on darwin?!") if sys.platform.startswith("freebsd"): pytest.xfail("pexpect does not work reliably on freebsd") - logfile = self.tmpdir.join("spawn.out") - child = pexpect.spawn(cmd, logfile=logfile.open("w")) + logfile = self.tmpdir.join("spawn.out").open("wb") + child = pexpect.spawn(cmd, logfile=logfile) + self.request.addfinalizer(logfile.close) child.timeout = expect_timeout return child diff -Nru pytest-2.4.2/_pytest/python.py pytest-2.5.1/_pytest/python.py --- pytest-2.4.2/_pytest/python.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/python.py 2013-12-17 08:00:02.000000000 +0000 @@ -3,18 +3,27 @@ import inspect import sys import pytest -from _pytest.main import getfslineno -from _pytest.mark import MarkDecorator, MarkInfo -from _pytest.monkeypatch import monkeypatch +from _pytest.mark import MarkDecorator from py._code.code import TerminalRepr import _pytest cutdir = py.path.local(_pytest.__file__).dirpath() NoneType = type(None) +NOTSET = object() callable = py.builtin.callable +def getfslineno(obj): + # xxx let decorators etc specify a sane ordering + while hasattr(obj, "__wrapped__"): + obj = obj.__wrapped__ + if hasattr(obj, 'place_as'): + obj = obj.place_as + fslineno = py.code.getfslineno(obj) + assert isinstance(fslineno[1], int), obj + return fslineno + def getimfunc(func): try: return func.__func__ @@ -26,11 +35,13 @@ class FixtureFunctionMarker: - def __init__(self, scope, params, autouse=False, yieldctx=False): + def __init__(self, scope, params, + autouse=False, yieldctx=False, ids=None): self.scope = scope self.params = params self.autouse = autouse self.yieldctx = yieldctx + self.ids = ids def __call__(self, function): if inspect.isclass(function): @@ -40,7 +51,7 @@ return function -def fixture(scope="function", params=None, autouse=False): +def fixture(scope="function", params=None, autouse=False, ids=None): """ (return a) decorator to mark a fixture factory function. This decorator can be used (with or or without parameters) to define @@ -62,15 +73,20 @@ can see it. If False (the default) then an explicit reference is needed to activate the fixture. + :arg ids: list of string ids each corresponding to the params + so that they are part of the test id. If no ids are provided + they will be generated automatically from the params. + """ if callable(scope) and params is None and autouse == False: # direct decoration return FixtureFunctionMarker( "function", params, autouse)(scope) - else: - return FixtureFunctionMarker(scope, params, autouse) + if params is not None and not isinstance(params, (list, tuple)): + params = list(params) + return FixtureFunctionMarker(scope, params, autouse, ids=ids) -def yield_fixture(scope="function", params=None, autouse=False): +def yield_fixture(scope="function", params=None, autouse=False, ids=None): """ (return a) decorator to mark a yield-fixture factory function (EXPERIMENTAL). @@ -84,7 +100,8 @@ return FixtureFunctionMarker( "function", params, autouse, yieldctx=True)(scope) else: - return FixtureFunctionMarker(scope, params, autouse, yieldctx=True) + return FixtureFunctionMarker(scope, params, autouse, + yieldctx=True, ids=ids) defaultfuncargprefixmarker = fixture() @@ -130,10 +147,12 @@ def pytest_configure(config): config.addinivalue_line("markers", "parametrize(argnames, argvalues): call a test function multiple " - "times passing in multiple different argument value sets. Example: " - "@parametrize('arg1', [1,2]) would lead to two calls of the decorated " - "test function, one with arg1=1 and another with arg1=2." - " see http://pytest.org/latest/parametrize.html for more info and " + "times passing in different arguments in turn. argvalues generally " + "needs to be a list of values if argnames specifies only one name " + "or a list of tuples of values if argnames specifies multiple names. " + "Example: @parametrize('arg1', [1,2]) would lead to two calls of the " + "decorated test function, one with arg1=1 and another with arg1=2." + "see http://pytest.org/latest/parametrize.html for more info and " "examples." ) config.addinivalue_line("markers", @@ -157,7 +176,7 @@ '_fillfuncargs': fillfixtures} } -@fixture() +@fixture(scope="session") def pytestconfig(request): """ the pytest config object with access to command line opts.""" return request.config @@ -177,7 +196,6 @@ def pytest_collect_file(path, parent): ext = path.ext - pb = path.purebasename if ext == ".py": if not parent.session.isinitpath(path): for pat in parent.config.getini('python_files'): @@ -269,10 +287,9 @@ if fspath.endswith(".pyc"): fspath = fspath[:-1] lineno = obj.compat_co_firstlineno - modpath = obj.__module__ else: fspath, lineno = getfslineno(obj) - modpath = self.getmodpath() + modpath = self.getmodpath() assert isinstance(lineno, int) return fspath, lineno, modpath @@ -334,12 +351,70 @@ if not metafunc._calls: yield Function(name, parent=self) else: + # add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs + add_funcarg_pseudo_fixture_def(self, metafunc, fm) + for callspec in metafunc._calls: subname = "%s[%s]" %(name, callspec.id) yield Function(name=subname, parent=self, callspec=callspec, callobj=funcobj, keywords={callspec.id:True}) +def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager): + # this function will transform all collected calls to a functions + # if they use direct funcargs (i.e. direct parametrization) + # because we want later test execution to be able to rely on + # an existing FixtureDef structure for all arguments. + # XXX we can probably avoid this algorithm if we modify CallSpec2 + # to directly care for creating the fixturedefs within its methods. + if not metafunc._calls[0].funcargs: + return # this function call does not have direct parametrization + # collect funcargs of all callspecs into a list of values + arg2params = {} + arg2scope = {} + arg2fixturedefs = metafunc._arg2fixturedefs + for param_index, callspec in enumerate(metafunc._calls): + for argname, argvalue in callspec.funcargs.items(): + arg2params.setdefault(argname, []).append(argvalue) + if argname not in arg2scope: + scopenum = callspec._arg2scopenum.get(argname, scopenum_function) + arg2scope[argname] = scopes[scopenum] + callspec.indices[argname] = param_index + + for argname in callspec.funcargs: + assert argname not in callspec.params + callspec.params.update(callspec.funcargs) + callspec.funcargs.clear() + + # register artificial FixtureDef's so that later at test execution + # time we can rely on a proper FixtureDef to exist for fixture setup. + for argname, valuelist in arg2params.items(): + # if we have a scope that is higher than function we need + # to make sure we only ever create an according fixturedef on + # a per-scope basis. We thus store and cache the fixturedef on the + # node related to the scope. + scope = arg2scope[argname] + node = None + if scope != "function": + node = get_scope_node(collector, scope) + if node is None: + assert scope == "class" and isinstance(collector, Module) + # use module-level collector for class-scope (for now) + node = collector + if node and argname in node._name2pseudofixturedef: + arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]] + else: + fixturedef = FixtureDef(fixturemanager, '', argname, + get_direct_param_fixture_func, + arg2scope[argname], + valuelist, False, False) + arg2fixturedefs[argname] = [fixturedef] + if node is not None: + node._name2pseudofixturedef[argname] = fixturedef + + +def get_direct_param_fixture_func(request): + return request.param class FuncFixtureInfo: def __init__(self, argnames, names_closure, name2fixturedefs): @@ -553,25 +628,24 @@ def fillfixtures(function): """ fill missing funcargs for a test function. """ - if 1 or getattr(function, "_args", None) is None: # not a yielded function - try: - request = function._request - except AttributeError: - # XXX this special code path is only expected to execute - # with the oejskit plugin. It uses classes with funcargs - # and we thus have to work a bit to allow this. - fm = function.session._fixturemanager - fi = fm.getfixtureinfo(function.parent, function.obj, None) - function._fixtureinfo = fi - request = function._request = FixtureRequest(function) - request._fillfixtures() - # prune out funcargs for jstests - newfuncargs = {} - for name in fi.argnames: - newfuncargs[name] = function.funcargs[name] - function.funcargs = newfuncargs - else: - request._fillfixtures() + try: + request = function._request + except AttributeError: + # XXX this special code path is only expected to execute + # with the oejskit plugin. It uses classes with funcargs + # and we thus have to work a bit to allow this. + fm = function.session._fixturemanager + fi = fm.getfixtureinfo(function.parent, function.obj, None) + function._fixtureinfo = fi + request = function._request = FixtureRequest(function) + request._fillfixtures() + # prune out funcargs for jstests + newfuncargs = {} + for name in fi.argnames: + newfuncargs[name] = function.funcargs[name] + function.funcargs = newfuncargs + else: + request._fillfixtures() _notexists = object() @@ -587,12 +661,14 @@ self._globalparam = _notexists self._arg2scopenum = {} # used for sorting parametrized resources self.keywords = {} + self.indices = {} def copy(self, metafunc): cs = CallSpec2(self.metafunc) cs.funcargs.update(self.funcargs) cs.params.update(self.params) cs.keywords.update(self.keywords) + cs.indices.update(self.indices) cs._arg2scopenum.update(self._arg2scopenum) cs._idlist = list(self._idlist) cs._globalid = self._globalid @@ -616,14 +692,12 @@ def id(self): return "-".join(map(str, filter(None, self._idlist))) - def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0): + def setmulti(self, valtype, argnames, valset, id, keywords, scopenum, + param_index): for arg,val in zip(argnames, valset): self._checkargnotcontained(arg) getattr(self, valtype)[arg] = val - # we want self.params to be always set because of - # parametrize_sorted() which groups tests by params/scope - if valtype == "funcargs": - self.params[arg] = id + self.indices[arg] = param_index self._arg2scopenum[arg] = scopenum if val is _notexists: self._emptyparamspecified = True @@ -639,6 +713,8 @@ if param is not _notexists: assert self._globalparam is _notexists self._globalparam = param + for arg in funcargs: + self._arg2scopenum[arg] = scopenum_function class FuncargnamesCompatAttr: @@ -694,16 +770,17 @@ to set a dynamic scope using test context or configuration. """ - # individual parametrized argument sets can be wrapped in a - # marker in which case we unwrap the values and apply the mark + # individual parametrized argument sets can be wrapped in a series + # of markers in which case we unwrap the values and apply the mark # at Function init newkeywords = {} unwrapped_argvalues = [] for i, argval in enumerate(argvalues): - if isinstance(argval, MarkDecorator): + while isinstance(argval, MarkDecorator): newmark = MarkDecorator(argval.markname, argval.args[:-1], argval.kwargs) - newkeywords[i] = {newmark.markname: newmark} + newmarks = newkeywords.setdefault(i, {}) + newmarks[newmark.markname] = newmark argval = argval.args[-1] unwrapped_argvalues.append(argval) argvalues = unwrapped_argvalues @@ -716,7 +793,7 @@ argvalues = [(_notexists,) * len(argnames)] if scope is None: - scope = "subfunction" + scope = "function" scopenum = scopes.index(scope) if not indirect: #XXX should we also check for the opposite case? @@ -732,11 +809,12 @@ ids = idmaker(argnames, argvalues) newcalls = [] for callspec in self._calls or [CallSpec2(self)]: - for i, valset in enumerate(argvalues): + for param_index, valset in enumerate(argvalues): assert len(valset) == len(argnames) newcallspec = callspec.copy(self) - newcallspec.setmulti(valtype, argnames, valset, ids[i], - newkeywords.get(i, {}), scopenum) + newcallspec.setmulti(valtype, argnames, valset, ids[param_index], + newkeywords.get(param_index, {}), scopenum, + param_index) newcalls.append(newcallspec) self._calls = newcalls @@ -914,10 +992,6 @@ func(*args[1:], **kwargs) except ExpectedException: return py.code.ExceptionInfo() - k = ", ".join(["%s=%r" % x for x in kwargs.items()]) - if k: - k = ', ' + k - expr = '%s(%r%s)' %(getattr(func, '__name__', func), args, k) pytest.fail("DID NOT RAISE") class RaisesContext(object): @@ -939,18 +1013,18 @@ # # the basic py.test Function item # -_dummy = object() + class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr): """ a Function Item is responsible for setting up and executing a Python test function. """ _genid = None def __init__(self, name, parent, args=None, config=None, - callspec=None, callobj=_dummy, keywords=None, session=None): + callspec=None, callobj=NOTSET, keywords=None, session=None): super(Function, self).__init__(name, parent, config=config, session=session) self._args = args - if callobj is not _dummy: + if callobj is not NOTSET: self.obj = callobj for name, val in (py.builtin._getfuncdict(self.obj) or {}).items(): @@ -962,30 +1036,26 @@ for name, val in keywords.items(): self.keywords[name] = val - fm = self.session._fixturemanager isyield = self._isyieldedfunction() - self._fixtureinfo = fi = fm.getfixtureinfo(self.parent, self.obj, - self.cls, - funcargs=not isyield) + self._fixtureinfo = fi = self.session._fixturemanager.getfixtureinfo( + self.parent, self.obj, self.cls, funcargs=not isyield) self.fixturenames = fi.names_closure if callspec is not None: self.callspec = callspec self._initrequest() def _initrequest(self): + self.funcargs = {} if self._isyieldedfunction(): assert not hasattr(self, "callspec"), ( "yielded functions (deprecated) cannot have funcargs") - self.funcargs = {} else: if hasattr(self, "callspec"): callspec = self.callspec - self.funcargs = callspec.funcargs.copy() + assert not callspec.funcargs self._genid = callspec.id if hasattr(callspec, "param"): self.param = callspec.param - else: - self.funcargs = {} self._request = FixtureRequest(self) @property @@ -1015,7 +1085,7 @@ def setup(self): # check if parametrization happend with an empty list try: - empty = self.callspec._emptyparamspecified + self.callspec._emptyparamspecified except AttributeError: pass else: @@ -1025,24 +1095,6 @@ super(Function, self).setup() fillfixtures(self) - def __eq__(self, other): - try: - return (self.name == other.name and - self._args == other._args and - self.parent == other.parent and - self.obj == other.obj and - getattr(self, '_genid', None) == - getattr(other, '_genid', None) - ) - except AttributeError: - pass - return False - - def __ne__(self, other): - return not self == other - - def __hash__(self): - return hash((self.parent, self.name)) scope2props = dict(session=()) scope2props["module"] = ("fspath", "module") @@ -1072,36 +1124,34 @@ def __init__(self, pyfuncitem): self._pyfuncitem = pyfuncitem - if hasattr(pyfuncitem, '_requestparam'): - self.param = pyfuncitem._requestparam #: fixture for which this request is being performed self.fixturename = None #: Scope string, one of "function", "cls", "module", "session" self.scope = "function" - self.getparent = pyfuncitem.getparent - self._funcargs = self._pyfuncitem.funcargs.copy() - self._fixtureinfo = fi = pyfuncitem._fixtureinfo - self._arg2fixturedefs = fi.name2fixturedefs + self._funcargs = {} + self._fixturedefs = {} + fixtureinfo = pyfuncitem._fixtureinfo + self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() self._arg2index = {} - self.fixturenames = self._fixtureinfo.names_closure + self.fixturenames = fixtureinfo.names_closure self._fixturemanager = pyfuncitem.session._fixturemanager - self._parentid = pyfuncitem.parent.nodeid - self._fixturestack = [] @property def node(self): """ underlying collection node (depends on current request scope)""" return self._getscopeitem(self.scope) + def _getnextfixturedef(self, argname): fixturedefs = self._arg2fixturedefs.get(argname, None) if fixturedefs is None: - # we arrive here because of a getfuncargvalue(argname) usage which - # was naturally not knowable at parsing/collection time + # we arrive here because of a a dynamic call to + # getfuncargvalue(argname) usage which was naturally + # not known at parsing/collection time fixturedefs = self._fixturemanager.getfixturedefs( - argname, self._parentid) + argname, self._pyfuncitem.parent.nodeid) self._arg2fixturedefs[argname] = fixturedefs - # fixturedefs is immutable so we maintain a decreasing index + # fixturedefs list is immutable so we maintain a decreasing index index = self._arg2index.get(argname, 0) - 1 if fixturedefs is None or (-index > len(fixturedefs)): raise FixtureLookupError(argname, self) @@ -1133,7 +1183,9 @@ try: return self._pyfuncitem._testcase except AttributeError: - return py.builtin._getimself(self.function) + function = getattr(self, "function", None) + if function is not None: + return py.builtin._getimself(function) @scopeproperty() def module(self): @@ -1163,12 +1215,7 @@ self._addfinalizer(finalizer, scope=self.scope) def _addfinalizer(self, finalizer, scope): - if scope != "function" and hasattr(self, "param"): - # parametrized resources are sorted by param - # so we rather store finalizers per (argname, param) - colitem = (self.fixturename, self.param) - else: - colitem = self._getscopeitem(scope) + colitem = self._getscopeitem(scope) self._pyfuncitem.session._setupstate.addfinalizer( finalizer=finalizer, colitem=colitem) @@ -1242,91 +1289,82 @@ setup time, you may use this function to retrieve it inside a fixture function body. """ + return self._get_active_fixturedef(argname).cached_result[0] + + def _get_active_fixturedef(self, argname): try: - return self._funcargs[argname] + return self._fixturedefs[argname] except KeyError: - pass - try: - fixturedef = self._getnextfixturedef(argname) - except FixtureLookupError: - if argname == "request": - return self - raise - self._fixturestack.append(fixturedef) - try: + try: + fixturedef = self._getnextfixturedef(argname) + except FixtureLookupError: + if argname == "request": + class PseudoFixtureDef: + cached_result = (self, [0]) + return PseudoFixtureDef + raise result = self._getfuncargvalue(fixturedef) self._funcargs[argname] = result - return result - finally: - self._fixturestack.pop() + self._fixturedefs[argname] = fixturedef + return fixturedef - def _getfuncargvalue(self, fixturedef): - try: - return fixturedef.cached_result # set by fixturedef.execute() - except AttributeError: - pass + def _get_fixturestack(self): + current = self + l = [] + while 1: + fixturedef = getattr(current, "_fixturedef", None) + if fixturedef is None: + l.reverse() + return l + l.append(fixturedef) + current = current._parent_request - # prepare request fixturename and param attributes before - # calling into fixture function + def _getfuncargvalue(self, fixturedef): + # prepare a subrequest object before calling fixture function + # (latter managed by fixturedef) argname = fixturedef.argname - node = self._pyfuncitem - mp = monkeypatch() - mp.setattr(self, 'fixturename', argname) - try: - param = node.callspec.getparam(argname) - except (AttributeError, ValueError): - pass - else: - mp.setattr(self, 'param', param, raising=False) - - # if a parametrize invocation set a scope it will override - # the static scope defined with the fixture function + funcitem = self._pyfuncitem scope = fixturedef.scope try: - paramscopenum = node.callspec._arg2scopenum[argname] - except (KeyError, AttributeError): - pass + param = funcitem.callspec.getparam(argname) + except (AttributeError, ValueError): + param = NOTSET + param_index = 0 else: - if paramscopenum != scopenum_subfunction: + # indices might not be set if old-style metafunc.addcall() was used + param_index = funcitem.callspec.indices.get(argname, 0) + # if a parametrize invocation set a scope it will override + # the static scope defined with the fixture function + paramscopenum = funcitem.callspec._arg2scopenum.get(argname) + if paramscopenum is not None: scope = scopes[paramscopenum] + subrequest = SubRequest(self, scope, param, param_index, fixturedef) + # check if a higher-level scoped fixture accesses a lower level one if scope is not None: __tracebackhide__ = True if scopemismatch(self.scope, scope): # try to report something helpful - lines = self._factorytraceback() + lines = subrequest._factorytraceback() raise ScopeMismatchError("You tried to access the %r scoped " - "funcarg %r with a %r scoped request object, " + "fixture %r with a %r scoped request object, " "involved factories\n%s" %( (scope, argname, self.scope, "\n".join(lines)))) __tracebackhide__ = False - mp.setattr(self, "scope", scope) - - # route request.addfinalizer to fixturedef - mp.setattr(self, "addfinalizer", fixturedef.addfinalizer) try: - # perform the fixture call - val = fixturedef.execute(request=self) + # call the fixture function + val = fixturedef.execute(request=subrequest) finally: - # if the fixture function failed it might still have - # registered finalizers so we can register - - # prepare finalization according to scope - # (XXX analyse exact finalizing mechanics / cleanup) + # if fixture function failed it might have registered finalizers self.session._setupstate.addfinalizer(fixturedef.finish, - self.node) - self._fixturemanager.addargfinalizer(fixturedef.finish, argname) - for subargname in fixturedef.argnames: # XXX all deps? - self._fixturemanager.addargfinalizer(fixturedef.finish, - subargname) - mp.undo() + subrequest.node) return val def _factorytraceback(self): lines = [] - for fixturedef in self._fixturestack: + for fixturedef in self._get_fixturestack(): factory = fixturedef.func fs, lineno = getfslineno(factory) p = self._pyfuncitem.session.fspath.bestrelpath(fs) @@ -1337,29 +1375,50 @@ def _getscopeitem(self, scope): if scope == "function": + # this might also be a non-function Item despite its attribute name return self._pyfuncitem - elif scope == "session": - return self.session - elif scope == "class": - x = self._pyfuncitem.getparent(pytest.Class) - if x is not None: - return x - # fallback to function - return self._pyfuncitem - if scope == "module": - return self._pyfuncitem.getparent(pytest.Module) - raise ValueError("unknown finalization scope %r" %(scope,)) + node = get_scope_node(self._pyfuncitem, scope) + if node is None and scope == "class": + # fallback to function item itself + node = self._pyfuncitem + assert node + return node def __repr__(self): return "" %(self.node) + +class SubRequest(FixtureRequest): + """ a sub request for handling getting a fixture from a + test function/fixture. """ + def __init__(self, request, scope, param, param_index, fixturedef): + self._parent_request = request + self.fixturename = fixturedef.argname + if param is not NOTSET: + self.param = param + self.param_index = param_index + self.scope = scope + self._fixturedef = fixturedef + self.addfinalizer = fixturedef.addfinalizer + self._pyfuncitem = request._pyfuncitem + self._funcargs = request._funcargs + self._fixturedefs = request._fixturedefs + self._arg2fixturedefs = request._arg2fixturedefs + self._arg2index = request._arg2index + self.fixturenames = request.fixturenames + self._fixturemanager = request._fixturemanager + + def __repr__(self): + return "" % (self.fixturename, self._pyfuncitem) + + class ScopeMismatchError(Exception): """ A fixture function tries to use a different fixture function which which has a lower scope (e.g. a Session one calls a function one) """ -scopes = "session module class function subfunction".split() -scopenum_subfunction = scopes.index("subfunction") +scopes = "session module class function".split() +scopenum_function = scopes.index("function") def scopemismatch(currentscope, newscope): return scopes.index(newscope) > scopes.index(currentscope) @@ -1368,7 +1427,7 @@ def __init__(self, argname, request, msg=None): self.argname = argname self.request = request - self.fixturestack = list(request._fixturestack) + self.fixturestack = request._get_fixturestack() self.msg = msg def formatrepr(self): @@ -1392,10 +1451,10 @@ if msg is None: fm = self.request._fixturemanager - nodeid = self.request._parentid available = [] for name, fixturedef in fm._arg2fixturedefs.items(): - faclist = list(fm._matchfactories(fixturedef, self.request._parentid)) + parentid = self.request._pyfuncitem.parent.nodeid + faclist = list(fm._matchfactories(fixturedef, parentid)) if faclist: available.append(name) msg = "fixture %r not found" % (self.argname,) @@ -1470,7 +1529,8 @@ self._nodename2fixtureinfo = {} def getfixtureinfo(self, node, func, cls, funcargs=True): - key = (node, func.__name__) + # node is the "collection node" for "func" + key = (node, func) try: return self._nodename2fixtureinfo[key] except KeyError: @@ -1558,57 +1618,28 @@ if argname in arg2fixturedefs: continue fixturedefs = self.getfixturedefs(argname, parentid) - arg2fixturedefs[argname] = fixturedefs - if fixturedefs is not None: - for fixturedef in fixturedefs: - merge(fixturedef.argnames) + if fixturedefs: + arg2fixturedefs[argname] = fixturedefs + merge(fixturedefs[-1].argnames) return fixturenames_closure, arg2fixturedefs def pytest_generate_tests(self, metafunc): for argname in metafunc.fixturenames: - faclist = metafunc._arg2fixturedefs[argname] + faclist = metafunc._arg2fixturedefs.get(argname) if faclist is None: continue # will raise FixtureLookupError at setup time for fixturedef in faclist: if fixturedef.params is not None: - metafunc.parametrize(argname, fixturedef.params, indirect=True, - scope=fixturedef.scope) + metafunc.parametrize(argname, fixturedef.params, + indirect=True, scope=fixturedef.scope, + ids=fixturedef.ids) def pytest_collection_modifyitems(self, items): # separate parametrized setups - items[:] = parametrize_sorted(items, set(), {}, 0) - - def pytest_runtest_teardown(self, item, nextitem): - # XXX teardown needs to be normalized for parametrized and - # no-parametrized functions - try: - cs1 = item.callspec - except AttributeError: - return + items[:] = reorder_items(items) - # determine which fixtures are not needed anymore for the next test - keylist = [] - for name in cs1.params: - try: - if name in nextitem.callspec.params and \ - cs1.params[name] == nextitem.callspec.params[name]: - continue - except AttributeError: - pass - key = (-cs1._arg2scopenum[name], name, cs1.params[name]) - keylist.append(key) - - # sort by scope (function scope first, then higher ones) - keylist.sort() - for (scopenum, name, param) in keylist: - item.session._setupstate._callfinalizers((name, param)) - l = self._arg2finish.pop(name, None) - if l is not None: - for fin in reversed(l): - fin() - - def parsefactories(self, node_or_obj, nodeid=_dummy, unittest=False): - if nodeid is not _dummy: + def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False): + if nodeid is not NOTSET: holderobj = node_or_obj else: holderobj = node_or_obj.obj @@ -1638,17 +1669,17 @@ fixturedef = FixtureDef(self, nodeid, name, obj, marker.scope, marker.params, yieldctx=marker.yieldctx, - unittest=unittest) + unittest=unittest, ids=marker.ids) faclist = self._arg2fixturedefs.setdefault(name, []) - if not fixturedef.has_location: - # All fixturedefs with no location are at the front + if fixturedef.has_location: + faclist.append(fixturedef) + else: + # fixturedefs with no location are at the front # so this inserts the current fixturedef after the # existing fixturedefs from external plugins but # before the fixturedefs provided in conftests. i = len([f for f in faclist if not f.has_location]) - else: - i = len(faclist) # append - faclist.insert(i, fixturedef) + faclist.insert(i, fixturedef) if marker.autouse: autousenames.append(name) if autousenames: @@ -1667,16 +1698,6 @@ if nodeid.startswith(fixturedef.baseid): yield fixturedef - def addargfinalizer(self, finalizer, argname): - l = self._arg2finish.setdefault(argname, []) - l.append(finalizer) - - def removefinalizer(self, finalizer): - for l in self._arg2finish.values(): - try: - l.remove(finalizer) - except ValueError: - pass def fail_fixturefunc(fixturefunc, msg): fs, lineno = getfslineno(fixturefunc) @@ -1716,7 +1737,7 @@ class FixtureDef: """ A container for a factory definition. """ def __init__(self, fixturemanager, baseid, argname, func, scope, params, - yieldctx, unittest=False): + yieldctx, unittest=False, ids=None): self._fixturemanager = fixturemanager self.baseid = baseid or '' self.has_location = baseid is not None @@ -1729,6 +1750,7 @@ self.argnames = getfuncargnames(func, startindex=startindex) self.yieldctx = yieldctx self.unittest = unittest + self.ids = ids self._finalizer = [] def addfinalizer(self, finalizer): @@ -1738,42 +1760,56 @@ while self._finalizer: func = self._finalizer.pop() func() - # check neccesity of next commented call - self._fixturemanager.removefinalizer(self.finish) - #print "finished", self try: del self.cached_result except AttributeError: pass def execute(self, request): + # get required arguments and register our own finish() + # with their finalization kwargs = {} - for newname in self.argnames: - kwargs[newname] = request.getfuncargvalue(newname) + for argname in self.argnames: + fixturedef = request._get_active_fixturedef(argname) + result, arg_cache_key = fixturedef.cached_result + kwargs[argname] = result + if argname != "request": + fixturedef.addfinalizer(self.finish) + + my_cache_key = request.param_index + cached_result = getattr(self, "cached_result", None) + if cached_result is not None: + #print argname, "Found cached_result", cached_result + #print argname, "param_index", param_index + result, cache_key = cached_result + if my_cache_key == cache_key: + #print request.fixturename, "CACHE HIT", repr(my_cache_key) + return result + #print request.fixturename, "CACHE MISS" + # we have a previous but differently parametrized fixture instance + # so we need to tear it down before creating a new one + self.finish() + assert not hasattr(self, "cached_result") + if self.unittest: result = self.func(request.instance, **kwargs) else: fixturefunc = self.func # the fixture function needs to be bound to the actual # request.instance so that code working with "self" behaves - # as expected. XXX request.instance should maybe return None - # instead of raising AttributeError - try: - if request.instance is not None: - fixturefunc = getimfunc(self.func) - if fixturefunc != self.func: - fixturefunc = fixturefunc.__get__(request.instance) - except AttributeError: - pass + # as expected. + if request.instance is not None: + fixturefunc = getimfunc(self.func) + if fixturefunc != self.func: + fixturefunc = fixturefunc.__get__(request.instance) result = call_fixture_func(fixturefunc, request, kwargs, self.yieldctx) - assert not hasattr(self, "cached_result") - self.cached_result = result + self.cached_result = (result, my_cache_key) return result def __repr__(self): - return ("" % - (self.argname, self.scope, self.baseid, self.func.__module__)) + return ("" % + (self.argname, self.scope, self.baseid)) def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames @@ -1795,85 +1831,90 @@ return tuple(argnames[startindex:]) # algorithm for sorting on a per-parametrized resource setup basis +# it is called for scopenum==0 (session) first and performs sorting +# down to the lower scopes such as to minimize number of "high scope" +# setups and teardowns + +def reorder_items(items): + argkeys_cache = {} + for scopenum in range(0, scopenum_function): + argkeys_cache[scopenum] = d = {} + for item in items: + keys = set(get_parametrized_fixture_keys(item, scopenum)) + if keys: + d[item] = keys + return reorder_items_atscope(items, set(), argkeys_cache, 0) -def parametrize_sorted(items, ignore, cache, scopenum): - if scopenum >= 3: +def reorder_items_atscope(items, ignore, argkeys_cache, scopenum): + if scopenum >= scopenum_function or len(items) < 3: return items - - # we pick the first item which has a arg/param combo in the - # requested scope and sort other items with the same combo - # into "newitems" which then is a list of all items using this - # arg/param. - - similar_items = [] - other_items = [] - slicing_argparam = None - slicing_index = 0 - for item in items: - argparamlist = getfuncargparams(item, ignore, scopenum, cache) - if slicing_argparam is None and argparamlist: - slicing_argparam = argparamlist[0] - slicing_index = len(other_items) - if slicing_argparam in argparamlist: - similar_items.append(item) - else: - other_items.append(item) - - if (len(similar_items) + slicing_index) > 1: - newignore = ignore.copy() - newignore.add(slicing_argparam) - part2 = parametrize_sorted( - similar_items + other_items[slicing_index:], - newignore, cache, scopenum) - part1 = parametrize_sorted( - other_items[:slicing_index], newignore, - cache, scopenum+1) - return part1 + part2 - else: - other_items = parametrize_sorted(other_items, ignore, cache, scopenum+1) - return other_items + similar_items - -def getfuncargparams(item, ignore, scopenum, cache): - """ return list of (arg,param) tuple, sorted by broader scope first. """ - assert scopenum < 3 # function + items_done = [] + while 1: + items_before, items_same, items_other, newignore = \ + slice_items(items, ignore, argkeys_cache[scopenum]) + items_before = reorder_items_atscope( + items_before, ignore, argkeys_cache,scopenum+1) + if items_same is None: + # nothing to reorder in this scope + assert items_other is None + return items_done + items_before + items_done.extend(items_before) + items = items_same + items_other + ignore = newignore + + +def slice_items(items, ignore, scoped_argkeys_cache): + # we pick the first item which uses a fixture instance in the + # requested scope and which we haven't seen yet. We slice the input + # items list into a list of items_nomatch, items_same and + # items_other + if scoped_argkeys_cache: # do we need to do work at all? + it = iter(items) + # first find a slicing key + for i, item in enumerate(it): + argkeys = scoped_argkeys_cache.get(item) + if argkeys is not None: + argkeys = argkeys.difference(ignore) + if argkeys: # found a slicing key + slicing_argkey = argkeys.pop() + items_before = items[:i] + items_same = [item] + items_other = [] + # now slice the remainder of the list + for item in it: + argkeys = scoped_argkeys_cache.get(item) + if argkeys and slicing_argkey in argkeys and \ + slicing_argkey not in ignore: + items_same.append(item) + else: + items_other.append(item) + newignore = ignore.copy() + newignore.add(slicing_argkey) + return (items_before, items_same, items_other, newignore) + return items, None, None, None + +def get_parametrized_fixture_keys(item, scopenum): + """ return list of keys for all parametrized arguments which match + the specified scope. """ + assert scopenum < scopenum_function # function try: cs = item.callspec except AttributeError: - return [] - if scopenum == 0: - argparams = [x for x in cs.params.items() if x not in ignore - and cs._arg2scopenum[x[0]] == scopenum] - elif scopenum == 1: # module - argparams = [] - for argname, param in cs.params.items(): - if cs._arg2scopenum[argname] == scopenum: - key = (argname, param, item.fspath) - if key in ignore: - continue - argparams.append(key) - elif scopenum == 2: # class - argparams = [] - for argname, param in cs.params.items(): - if cs._arg2scopenum[argname] == scopenum: - l = cache.setdefault(item.fspath, []) - try: - i = l.index(item.cls) - except ValueError: - i = len(l) - l.append(item.cls) - key = (argname, param, item.fspath, i) - if key in ignore: - continue - argparams.append(key) - #elif scopenum == 3: - # argparams = [] - # for argname, param in cs.params.items(): - # if cs._arg2scopenum[argname] == scopenum: - # key = (argname, param, getfslineno(item.obj)) - # if key in ignore: - # continue - # argparams.append(key) - return argparams + pass + else: + # cs.indictes.items() is random order of argnames but + # then again different functions (items) can change order of + # arguments so it doesn't matter much probably + for argname, param_index in cs.indices.items(): + if cs._arg2scopenum[argname] != scopenum: + continue + if scopenum == 0: # session + key = (argname, param_index) + elif scopenum == 1: # module + key = (argname, param_index, item.fspath) + elif scopenum == 2: # class + key = (argname, param_index, item.fspath, item.cls) + yield key def xunitsetup(obj, name): @@ -1893,3 +1934,15 @@ # we don't expect them to be fixture functions return None +scopename2class = { + 'class': Class, + 'module': Module, + 'function': pytest.Item, +} +def get_scope_node(node, scope): + cls = scopename2class.get(scope) + if cls is None: + if scope == "session": + return node.session + raise ValueError("unknown scope") + return node.getparent(cls) diff -Nru pytest-2.4.2/_pytest/resultlog.py pytest-2.5.1/_pytest/resultlog.py --- pytest-2.4.2/_pytest/resultlog.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/resultlog.py 2013-12-17 08:00:02.000000000 +0000 @@ -6,7 +6,7 @@ def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "resultlog plugin options") - group.addoption('--resultlog', '--result-log', action="store", + group.addoption('--resultlog', '--result-log', action="store", metavar="path", default=None, help="path for machine-readable result log.") @@ -85,7 +85,7 @@ if not report.passed: if report.failed: code = "F" - longrepr = str(report.longrepr.reprcrash) + longrepr = str(report.longrepr) else: assert report.skipped code = "S" diff -Nru pytest-2.4.2/_pytest/runner.py pytest-2.5.1/_pytest/runner.py --- pytest-2.4.2/_pytest/runner.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/runner.py 2013-12-17 08:00:02.000000000 +0000 @@ -193,7 +193,6 @@ outcome = "passed" longrepr = None else: - excinfo = call.excinfo if not isinstance(excinfo, py.code.ExceptionInfo): outcome = "failed" longrepr = excinfo @@ -328,9 +327,18 @@ def _callfinalizers(self, colitem): finalizers = self._finalizers.pop(colitem, None) + exc = None while finalizers: fin = finalizers.pop() - fin() + try: + fin() + except Exception: + # XXX Only first exception will be seen by user, + # ideally all should be reported. + if exc is None: + exc = sys.exc_info() + if exc: + py.builtin._reraise(*exc) def _teardown_with_finalization(self, colitem): self._callfinalizers(colitem) @@ -450,25 +458,25 @@ def importorskip(modname, minversion=None): - """ return imported module if it has a higher __version__ than the - optionally specified 'minversion' - otherwise call py.test.skip() - with a message detailing the mismatch. + """ return imported module if it has at least "minversion" as its + __version__ attribute. If no minversion is specified the a skip + is only triggered if the module can not be imported. + Note that version comparison only works with simple version strings + like "1.2.3" but not "1.2.3.dev1" or others. """ __tracebackhide__ = True compile(modname, '', 'eval') # to catch syntaxerrors try: __import__(modname) except ImportError: - py.test.skip("could not import %r" %(modname,)) + skip("could not import %r" %(modname,)) mod = sys.modules[modname] if minversion is None: return mod verattr = getattr(mod, '__version__', None) - if isinstance(minversion, str): - minver = minversion.split(".") - else: - minver = list(minversion) - if verattr is None or verattr.split(".") < minver: - py.test.skip("module %r has __version__ %r, required is: %r" %( - modname, verattr, minversion)) + def intver(verstring): + return [int(x) for x in verstring.split(".")] + if verattr is None or intver(verattr) < intver(minversion): + skip("module %r has __version__ %r, required is: %r" %( + modname, verattr, minversion)) return mod diff -Nru pytest-2.4.2/_pytest/skipping.py pytest-2.5.1/_pytest/skipping.py --- pytest-2.4.2/_pytest/skipping.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/skipping.py 2013-12-17 08:00:02.000000000 +0000 @@ -10,6 +10,14 @@ help="run tests even if they are marked xfail") def pytest_configure(config): + if config.option.runxfail: + old = pytest.xfail + config._cleanup.append(lambda: setattr(pytest, "xfail", old)) + def nop(*args, **kwargs): + pass + nop.Exception = XFailed + setattr(pytest, "xfail", nop) + config.addinivalue_line("markers", "skipif(condition): skip the given test function if eval(condition) " "results in a True value. Evaluation happens within the " @@ -209,7 +217,6 @@ tr._tw.line(line) def show_simple(terminalreporter, lines, stat, format): - tw = terminalreporter._tw failed = terminalreporter.stats.get(stat) if failed: for rep in failed: diff -Nru pytest-2.4.2/_pytest/standalonetemplate.py pytest-2.5.1/_pytest/standalonetemplate.py --- pytest-2.4.2/_pytest/standalonetemplate.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/standalonetemplate.py 2013-12-17 08:00:02.000000000 +0000 @@ -39,7 +39,7 @@ if is_pkg: module.__path__ = [fullname] - do_exec(co, module.__dict__) + do_exec(co, module.__dict__) # noqa return sys.modules[fullname] def get_source(self, name): @@ -63,4 +63,4 @@ sys.meta_path.insert(0, importer) entry = "@ENTRY@" - do_exec(entry, locals()) + do_exec(entry, locals()) # noqa diff -Nru pytest-2.4.2/_pytest/terminal.py pytest-2.5.1/_pytest/terminal.py --- pytest-2.4.2/_pytest/terminal.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/terminal.py 2013-12-17 08:00:02.000000000 +0000 @@ -5,7 +5,6 @@ import pytest import py import sys -import os def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "reporting", after="general") @@ -30,6 +29,10 @@ group._addoption('--fulltrace', '--full-trace', action="store_true", default=False, help="don't cut any tracebacks (default is to cut).") + group._addoption('--color', metavar="color", + action="store", dest="color", default='auto', + choices=['yes', 'no', 'auto'], + help="color terminal output (yes/no/auto).") def pytest_configure(config): config.option.verbose -= config.option.quiet @@ -86,6 +89,10 @@ if file is None: file = py.std.sys.stdout self._tw = self.writer = py.io.TerminalWriter(file) + if self.config.option.color == 'yes': + self._tw.hasmarkup = True + if self.config.option.color == 'no': + self._tw.hasmarkup = False self.currentfspath = None self.reportchars = getreportopt(config) self.hasmarkup = self._tw.hasmarkup diff -Nru pytest-2.4.2/_pytest/unittest.py pytest-2.5.1/_pytest/unittest.py --- pytest-2.4.2/_pytest/unittest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/_pytest/unittest.py 2013-12-17 08:00:02.000000000 +0000 @@ -50,8 +50,6 @@ x = getattr(self.obj, name) funcobj = getattr(x, 'im_func', x) transfer_markers(funcobj, cls, module) - if hasattr(funcobj, 'todo'): - pytest.mark.xfail(reason=str(funcobj.todo))(funcobj) yield TestCaseFunction(name, parent=self) foundsomething = True @@ -70,10 +68,6 @@ def setup(self): self._testcase = self.parent.obj(self.name) self._obj = getattr(self._testcase, self.name) - if hasattr(self._testcase, 'skip'): - pytest.skip(self._testcase.skip) - if hasattr(self._obj, 'skip'): - pytest.skip(self._obj.skip) if hasattr(self._testcase, 'setup_method'): self._testcase.setup_method(self._obj) if hasattr(self, "_request"): diff -Nru pytest-2.4.2/debian/changelog pytest-2.5.1/debian/changelog --- pytest-2.4.2/debian/changelog 2013-12-05 13:07:24.000000000 +0000 +++ pytest-2.5.1/debian/changelog 2013-12-21 05:05:09.000000000 +0000 @@ -1,8 +1,18 @@ -pytest (2.4.2-1~cloud0) precise-icehouse; urgency=low +pytest (2.5.1-1~cloud0) precise-icehouse; urgency=low * New upstream release for the Ubuntu Cloud Archive. - -- Openstack Ubuntu Testing Bot Thu, 05 Dec 2013 08:07:24 -0500 + -- Openstack Ubuntu Testing Bot Sat, 21 Dec 2013 00:05:09 -0500 + +pytest (2.5.1-1) unstable; urgency=low + + * Team upload. + * New upstream release. + * d/control: Update python-py and python3-py dependency versions. + Closes: #731299 + * d/patches/remove_google_js: Refreshed. + + -- Barry Warsaw Thu, 12 Dec 2013 10:27:41 -0500 pytest (2.4.2-1) unstable; urgency=low diff -Nru pytest-2.4.2/debian/control pytest-2.5.1/debian/control --- pytest-2.4.2/debian/control 2013-11-24 19:25:49.000000000 +0000 +++ pytest-2.5.1/debian/control 2013-12-12 20:16:21.000000000 +0000 @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 8.1), python-all (>= 2.6.6-3~), - python-py (>= 1.4.13), + python-py (>= 1.4.19), python-twisted-core, python-pexpect, python-nose, @@ -14,7 +14,7 @@ python-setuptools, python-sphinx (>= 1.0.7+dfsg), python3-all (>= 3.1.2-6~), - python3-py, + python3-py (>= 1.4.19), python3-nose, python3-mock (>= 1.0.1), python3-setuptools @@ -31,7 +31,7 @@ Architecture: all Depends: python-pkg-resources, - python-py (>= 1.4.13), + python-py (>= 1.4.19), ${misc:Depends}, ${python:Depends} Suggests: python-mock (>= 1.0.1) @@ -46,7 +46,7 @@ Architecture: all Depends: python3-pkg-resources, - python3-py (>= 1.4.11), + python3-py (>= 1.4.19), ${misc:Depends}, ${python3:Depends} Description: Simple, powerful testing in Python3 diff -Nru pytest-2.4.2/debian/patches/remove_google_js pytest-2.5.1/debian/patches/remove_google_js --- pytest-2.4.2/debian/patches/remove_google_js 2013-11-22 17:01:10.000000000 +0000 +++ pytest-2.5.1/debian/patches/remove_google_js 2013-12-19 22:01:55.000000000 +0000 @@ -7,15 +7,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ --- a/doc/en/_templates/layout.html +++ b/doc/en/_templates/layout.html -@@ -2,26 +2,9 @@ - - {% block relbaritems %} - {{ super() }} -- -- -- - - {% endblock %} +@@ -2,18 +2,4 @@ {% block footer %} {{ super() }} @@ -34,3 +26,11 @@ - - {% endblock %} +--- a/doc/en/_templates/links.html ++++ b/doc/en/_templates/links.html +@@ -7,5 +7,3 @@ +
  • Issue Tracker
  • +
  • PDF Documentation + +- +- diff -Nru pytest-2.4.2/doc/en/_static/sphinxdoc.css pytest-2.5.1/doc/en/_static/sphinxdoc.css --- pytest-2.4.2/doc/en/_static/sphinxdoc.css 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/_static/sphinxdoc.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,339 +0,0 @@ -/* - * sphinxdoc.css_t - * ~~~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- sphinxdoc theme. Originally created by - * Armin Ronacher for Werkzeug. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 1.1em; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.related { - font-size: 0.8em; -} - -div.related ul { - background-image: url(navigation.png); - height: 2em; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; -} - -div.related ul li { - margin: 0; - padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; -} - -div.related ul li a:hover { - color: #3CA8E7; -} - -div.sphinxsidebarwrapper { - padding: 0; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - font-size: 1em; - text-align: left; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4 { - margin: 1em 0 0.5em 0; - font-size: 1em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar h3 a { - color: white; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - margin-left: 20px; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -/* -- body styles ----------------------------------------------------------- */ - -p { - margin: 0.8em 0 0.5em 0; -} - -a { - color: #CA7900; - text-decoration: none; -} - -a:hover { - color: #2491CF; -} - -div.body a { - text-decoration: underline; -} - -h1 { - margin: 0; - padding: 0.7em 0 0.3em 0; - font-size: 1.5em; - color: #11557C; -} - -h2 { - margin: 1.3em 0 0.2em 0; - font-size: 1.35em; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.2em; -} - -div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { - display: inline; -} - -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} - -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; -} - -tt.descname, tt.descclassname, tt.xref { - border: 0; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -a tt { - border: 0; - color: #CA7900; -} - -a tt:hover { - color: #2491CF; -} - -pre { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.015em; - line-height: 120%; - padding: 0.5em; - border: 1px solid #ccc; - background-color: #f8f8f8; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -td.linenos pre { - padding: 0.5em 0; -} - -div.quotebar { - background-color: #f8f8f8; - max-width: 250px; - float: right; - padding: 2px 7px; - border: 1px solid #ccc; -} - -div.topic { - background-color: #f8f8f8; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 1em 0; - border: 1px solid #86989B; - background-color: #f7f7f7; - padding: 0; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border-bottom: 1px solid #86989B; - font-weight: bold; - background-color: #AFC1C4; -} - -div.warning { - border: 1px solid #940000; -} - -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; -} - -.viewcode-back { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} diff -Nru pytest-2.4.2/doc/en/_templates/globaltoc.html pytest-2.5.1/doc/en/_templates/globaltoc.html --- pytest-2.4.2/doc/en/_templates/globaltoc.html 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_templates/globaltoc.html 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,17 @@ +

    {{ _('Table Of Contents') }}

    + + + +{%- if display_toc %} +
    + {{ toc }} +{%- endif %} diff -Nru pytest-2.4.2/doc/en/_templates/indexsidebar.html pytest-2.5.1/doc/en/_templates/indexsidebar.html --- pytest-2.4.2/doc/en/_templates/indexsidebar.html 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/_templates/indexsidebar.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -

    Download

    -{% if version.endswith('(hg)') %} -

    This documentation is for version {{ version }}, which is - not released yet.

    -

    You can use it from the - Bitbucket Repo or look for - released versions in the Python - Package Index.

    -{% else %} -

    {{ release }} release -[Changelog]

    -

    -pytest/PyPI -

    -
    easy_install pytest
    -
    pip install pytest
    -{% endif %} - -

    Questions? Suggestions?

    - -

    contact channels -

    diff -Nru pytest-2.4.2/doc/en/_templates/layout.html pytest-2.5.1/doc/en/_templates/layout.html --- pytest-2.4.2/doc/en/_templates/layout.html 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/_templates/layout.html 2013-12-17 08:00:02.000000000 +0000 @@ -1,13 +1,5 @@ {% extends "!layout.html" %} -{% block relbaritems %} -{{ super() }} - - - - -{% endblock %} - {% block footer %} {{ super() }} -{%- endif %} - -

    quicklinks

    -
    - - -
    - home - - TOC/contents -
    - install - - changelog -
    - examples - - customize -
    - issues[bb] - - contact -
    - Talks/Posts -
    -
    -{% extends "basic/localtoc.html" %} - diff -Nru pytest-2.4.2/doc/en/_templates/sidebarintro.html pytest-2.5.1/doc/en/_templates/sidebarintro.html --- pytest-2.4.2/doc/en/_templates/sidebarintro.html 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_templates/sidebarintro.html 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,5 @@ +

    About pytest

    +

    + pytest is a mature full-featured Python testing tool that helps + you write better programs. +

    diff -Nru pytest-2.4.2/doc/en/_themes/.gitignore pytest-2.5.1/doc/en/_themes/.gitignore --- pytest-2.4.2/doc/en/_themes/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/.gitignore 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,3 @@ +*.pyc +*.pyo +.DS_Store diff -Nru pytest-2.4.2/doc/en/_themes/LICENSE pytest-2.5.1/doc/en/_themes/LICENSE --- pytest-2.4.2/doc/en/_themes/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/LICENSE 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,37 @@ +Copyright (c) 2010 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms of the theme, with or +without modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +We kindly ask you to only use these themes in an unmodified manner just +for Flask and Flask-related products, not for unrelated projects. If you +like the visual style and want to use it for your own projects, please +consider making some larger changes to the themes (such as changing +font faces, sizes, colors or margins). + +THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff -Nru pytest-2.4.2/doc/en/_themes/README pytest-2.5.1/doc/en/_themes/README --- pytest-2.4.2/doc/en/_themes/README 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/README 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,31 @@ +Flask Sphinx Styles +=================== + +This repository contains sphinx styles for Flask and Flask related +projects. To use this style in your Sphinx documentation, follow +this guide: + +1. put this folder as _themes into your docs folder. Alternatively + you can also use git submodules to check out the contents there. +2. add this to your conf.py: + + sys.path.append(os.path.abspath('_themes')) + html_theme_path = ['_themes'] + html_theme = 'flask' + +The following themes exist: + +- 'flask' - the standard flask documentation theme for large + projects +- 'flask_small' - small one-page theme. Intended to be used by + very small addon libraries for flask. + +The following options exist for the flask_small theme: + + [options] + index_logo = '' filename of a picture in _static + to be used as replacement for the + h1 in the index.rst file. + index_logo_height = 120px height of the index logo + github_fork = '' repository name on github for the + "fork me" badge diff -Nru pytest-2.4.2/doc/en/_themes/flask/layout.html pytest-2.5.1/doc/en/_themes/flask/layout.html --- pytest-2.4.2/doc/en/_themes/flask/layout.html 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/flask/layout.html 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,25 @@ +{%- extends "basic/layout.html" %} +{%- block extrahead %} + {{ super() }} + {% if theme_touch_icon %} + + {% endif %} + + +{% endblock %} +{%- block relbar2 %}{% endblock %} +{% block header %} + {{ super() }} + {% if pagename == 'index' %} +
    + {% endif %} +{% endblock %} +{%- block footer %} + + {% if pagename == 'index' %} +
    + {% endif %} +{%- endblock %} diff -Nru pytest-2.4.2/doc/en/_themes/flask/relations.html pytest-2.5.1/doc/en/_themes/flask/relations.html --- pytest-2.4.2/doc/en/_themes/flask/relations.html 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/flask/relations.html 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,19 @@ +

    Related Topics

    + diff -Nru pytest-2.4.2/doc/en/_themes/flask/static/flasky.css_t pytest-2.5.1/doc/en/_themes/flask/static/flasky.css_t --- pytest-2.4.2/doc/en/_themes/flask/static/flasky.css_t 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/flask/static/flasky.css_t 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,555 @@ +/* + * flasky.css_t + * ~~~~~~~~~~~~ + * + * :copyright: Copyright 2010 by Armin Ronacher. + * :license: Flask Design License, see LICENSE for details. + */ + +{% set page_width = '940px' %} +{% set sidebar_width = '220px' %} +{% set base_font = '"Gudea", sans-serif' %} +{% set header_font = '"Gudea", sans-serif' %} +{% set link_color = '#490' %} +{% set link_hover_color = '#9c0' %} + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: {{ base_font }}; + font-size: 17px; + background-color: white; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + width: {{ page_width }}; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 {{ sidebar_width }}; +} + +div.sphinxsidebar { + width: {{ sidebar_width }}; +} + +hr { + border: 0; + border-top: 1px solid #B1B4B6; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +img.floatingflask { + padding: 0 0 10px 10px; + float: right; +} + +div.footer { + width: {{ page_width }}; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +div.related { + display: none; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebar { + font-size: 14px; + line-height: 1.5; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0 0 20px 0; + margin: 0; + text-align: center; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: {{ header_font }}; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: {{ base_font }}; + font-size: 1em; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: {{ link_color }}; + text-decoration: underline; +} + +a:hover { + color: {{ link_hover_color }}; + text-decoration: underline; +} + +a.reference.internal em { + font-style: normal; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: {{ header_font }}; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +{% if theme_index_logo %} +div.indexwrapper h1 { + text-indent: -999999px; + background: url({{ theme_index_logo }}) no-repeat center center; + height: {{ theme_index_logo_height }}; +} +{% else %} +div.indexwrapper div.body h1 { + font-size: 200%; +} +{% endif %} +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #ddd; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #eaeaea; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + background: #fafafa; + margin: 20px -30px; + padding: 10px 30px; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +dd div.admonition { + margin-left: -60px; + padding-left: 60px; +} + +div.admonition p.admonition-title { + font-family: {{ header_font }}; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: white; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +img.screenshot { +} + +tt.descname, tt.descclassname { + font-size: 0.95em; +} + +tt.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #eee; + background: #fdfdfd; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #eee; + padding: 7px 30px; + margin: 15px -30px; + line-height: 1.3em; +} + +dl pre, blockquote pre, li pre { + margin-left: -60px; + padding-left: 60px; +} + +dl dl pre { + margin-left: -90px; + padding-left: 90px; +} + +tt { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid white; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted {{ link_color }}; +} + +a.reference:hover { + border-bottom: 1px solid {{ link_hover_color }}; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted {{ link_color }}; +} + +a.footnote-reference:hover { + border-bottom: 1px solid {{ link_hover_color }}; +} + +a:hover tt { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: white; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: white; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a, div.sphinxsidebar ul { + color: white; + } + + div.sphinxsidebar a { + color: #aaa; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.related { + display: block; + margin: 0; + padding: 10px 0 20px 0; + } + + div.related ul, + div.related ul li { + margin: 0; + padding: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + +/* misc. */ + +.revsys-inline { + display: none!important; +} diff -Nru pytest-2.4.2/doc/en/_themes/flask/theme.conf pytest-2.5.1/doc/en/_themes/flask/theme.conf --- pytest-2.4.2/doc/en/_themes/flask/theme.conf 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/flask/theme.conf 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,9 @@ +[theme] +inherit = basic +stylesheet = flasky.css +pygments_style = flask_theme_support.FlaskyStyle + +[options] +index_logo = '' +index_logo_height = 120px +touch_icon = diff -Nru pytest-2.4.2/doc/en/_themes/flask_theme_support.py pytest-2.5.1/doc/en/_themes/flask_theme_support.py --- pytest-2.4.2/doc/en/_themes/flask_theme_support.py 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/_themes/flask_theme_support.py 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,86 @@ +# flasky extensions. flasky pygments style based on tango style +from pygments.style import Style +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Whitespace, Punctuation, Other, Literal + + +class FlaskyStyle(Style): + background_color = "#f8f8f8" + default_style = "" + + styles = { + # No corresponding class for the following: + #Text: "", # class: '' + Whitespace: "underline #f8f8f8", # class: 'w' + Error: "#a40000 border:#ef2929", # class: 'err' + Other: "#000000", # class 'x' + + Comment: "italic #8f5902", # class: 'c' + Comment.Preproc: "noitalic", # class: 'cp' + + Keyword: "bold #004461", # class: 'k' + Keyword.Constant: "bold #004461", # class: 'kc' + Keyword.Declaration: "bold #004461", # class: 'kd' + Keyword.Namespace: "bold #004461", # class: 'kn' + Keyword.Pseudo: "bold #004461", # class: 'kp' + Keyword.Reserved: "bold #004461", # class: 'kr' + Keyword.Type: "bold #004461", # class: 'kt' + + Operator: "#582800", # class: 'o' + Operator.Word: "bold #004461", # class: 'ow' - like keywords + + Punctuation: "bold #000000", # class: 'p' + + # because special names such as Name.Class, Name.Function, etc. + # are not recognized as such later in the parsing, we choose them + # to look the same as ordinary variables. + Name: "#000000", # class: 'n' + Name.Attribute: "#c4a000", # class: 'na' - to be revised + Name.Builtin: "#004461", # class: 'nb' + Name.Builtin.Pseudo: "#3465a4", # class: 'bp' + Name.Class: "#000000", # class: 'nc' - to be revised + Name.Constant: "#000000", # class: 'no' - to be revised + Name.Decorator: "#888", # class: 'nd' - to be revised + Name.Entity: "#ce5c00", # class: 'ni' + Name.Exception: "bold #cc0000", # class: 'ne' + Name.Function: "#000000", # class: 'nf' + Name.Property: "#000000", # class: 'py' + Name.Label: "#f57900", # class: 'nl' + Name.Namespace: "#000000", # class: 'nn' - to be revised + Name.Other: "#000000", # class: 'nx' + Name.Tag: "bold #004461", # class: 'nt' - like a keyword + Name.Variable: "#000000", # class: 'nv' - to be revised + Name.Variable.Class: "#000000", # class: 'vc' - to be revised + Name.Variable.Global: "#000000", # class: 'vg' - to be revised + Name.Variable.Instance: "#000000", # class: 'vi' - to be revised + + Number: "#990000", # class: 'm' + + Literal: "#000000", # class: 'l' + Literal.Date: "#000000", # class: 'ld' + + String: "#4e9a06", # class: 's' + String.Backtick: "#4e9a06", # class: 'sb' + String.Char: "#4e9a06", # class: 'sc' + String.Doc: "italic #8f5902", # class: 'sd' - like a comment + String.Double: "#4e9a06", # class: 's2' + String.Escape: "#4e9a06", # class: 'se' + String.Heredoc: "#4e9a06", # class: 'sh' + String.Interpol: "#4e9a06", # class: 'si' + String.Other: "#4e9a06", # class: 'sx' + String.Regex: "#4e9a06", # class: 'sr' + String.Single: "#4e9a06", # class: 's1' + String.Symbol: "#4e9a06", # class: 'ss' + + Generic: "#000000", # class: 'g' + Generic.Deleted: "#a40000", # class: 'gd' + Generic.Emph: "italic #000000", # class: 'ge' + Generic.Error: "#ef2929", # class: 'gr' + Generic.Heading: "bold #000080", # class: 'gh' + Generic.Inserted: "#00A000", # class: 'gi' + Generic.Output: "#888", # class: 'go' + Generic.Prompt: "#745334", # class: 'gp' + Generic.Strong: "bold #000000", # class: 'gs' + Generic.Subheading: "bold #800080", # class: 'gu' + Generic.Traceback: "bold #a40000", # class: 'gt' + } diff -Nru pytest-2.4.2/doc/en/announce/index.txt pytest-2.5.1/doc/en/announce/index.txt --- pytest-2.4.2/doc/en/announce/index.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/announce/index.txt 2013-12-17 08:00:02.000000000 +0000 @@ -5,6 +5,8 @@ .. toctree:: :maxdepth: 2 + release-2.5.1 + release-2.5.0 release-2.4.2 release-2.4.1 release-2.4.0 diff -Nru pytest-2.4.2/doc/en/announce/release-2.5.0.txt pytest-2.5.1/doc/en/announce/release-2.5.0.txt --- pytest-2.4.2/doc/en/announce/release-2.5.0.txt 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/announce/release-2.5.0.txt 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,175 @@ +pytest-2.5.0: now down to ZERO reported bugs! +=========================================================================== + +pytest-2.5.0 is a big fixing release, the result of two community bug +fixing days plus numerous additional works from many people and +reporters. The release should be fully compatible to 2.4.2, existing +plugins and test suites. We aim at maintaining this level of ZERO reported +bugs because it's no fun if your testing tool has bugs, is it? Under a +condition, though: when submitting a bug report please provide +clear information about the circumstances and a simple example which +reproduces the problem. + +The issue tracker is of course not empty now. We have many remaining +"enhacement" issues which we'll hopefully can tackle in 2014 with your +help. + +For those who use older Python versions, please note that pytest is not +automatically tested on python2.5 due to virtualenv, setuptools and tox +not supporting it anymore. Manual verification shows that it mostly +works fine but it's not going to be part of the automated release +process and thus likely to break in the future. + +As usual, current docs are at + + http://pytest.org + +and you can upgrade from pypi via:: + + pip install -U pytest + +Particular thanks for helping with this release go to Anatoly Bubenkoff, +Floris Bruynooghe, Marc Abramowitz, Ralph Schmitt, Ronny Pfannschmidt, +Donald Stufft, James Lan, Rob Dennis, Jason R. Coombs, Mathieu Agopian, +Virgil Dupras, Bruno Oliveira, Alex Gaynor and others. + +have fun, +holger krekel + + +2.5.0 +----------------------------------- + +- dropped python2.5 from automated release testing of pytest itself + which means it's probably going to break soon (but still works + with this release we believe). + +- simplified and fixed implementation for calling finalizers when + parametrized fixtures or function arguments are involved. finalization + is now performed lazily at setup time instead of in the "teardown phase". + While this might sound odd at first, it helps to ensure that we are + correctly handling setup/teardown even in complex code. User-level code + should not be affected unless it's implementing the pytest_runtest_teardown + hook and expecting certain fixture instances are torn down within (very + unlikely and would have been unreliable anyway). + +- PR90: add --color=yes|no|auto option to force terminal coloring + mode ("auto" is default). Thanks Marc Abramowitz. + +- fix issue319 - correctly show unicode in assertion errors. Many + thanks to Floris Bruynooghe for the complete PR. Also means + we depend on py>=1.4.19 now. + +- fix issue396 - correctly sort and finalize class-scoped parametrized + tests independently from number of methods on the class. + +- refix issue323 in a better way -- parametrization should now never + cause Runtime Recursion errors because the underlying algorithm + for re-ordering tests per-scope/per-fixture is not recursive + anymore (it was tail-call recursive before which could lead + to problems for more than >966 non-function scoped parameters). + +- fix issue290 - there is preliminary support now for parametrizing + with repeated same values (sometimes useful to to test if calling + a second time works as with the first time). + +- close issue240 - document precisely how pytest module importing + works, discuss the two common test directory layouts, and how it + interacts with PEP420-namespace packages. + +- fix issue246 fix finalizer order to be LIFO on independent fixtures + depending on a parametrized higher-than-function scoped fixture. + (was quite some effort so please bear with the complexity of this sentence :) + Thanks Ralph Schmitt for the precise failure example. + +- fix issue244 by implementing special index for parameters to only use + indices for paramentrized test ids + +- fix issue287 by running all finalizers but saving the exception + from the first failing finalizer and re-raising it so teardown will + still have failed. We reraise the first failing exception because + it might be the cause for other finalizers to fail. + +- fix ordering when mock.patch or other standard decorator-wrappings + are used with test methods. This fixues issue346 and should + help with random "xdist" collection failures. Thanks to + Ronny Pfannschmidt and Donald Stufft for helping to isolate it. + +- fix issue357 - special case "-k" expressions to allow for + filtering with simple strings that are not valid python expressions. + Examples: "-k 1.3" matches all tests parametrized with 1.3. + "-k None" filters all tests that have "None" in their name + and conversely "-k 'not None'". + Previously these examples would raise syntax errors. + +- fix issue384 by removing the trial support code + since the unittest compat enhancements allow + trial to handle it on its own + +- don't hide an ImportError when importing a plugin produces one. + fixes issue375. + +- fix issue275 - allow usefixtures and autouse fixtures + for running doctest text files. + +- fix issue380 by making --resultlog only rely on longrepr instead + of the "reprcrash" attribute which only exists sometimes. + +- address issue122: allow @pytest.fixture(params=iterator) by exploding + into a list early on. + +- fix pexpect-3.0 compatibility for pytest's own tests. + (fixes issue386) + +- allow nested parametrize-value markers, thanks James Lan for the PR. + +- fix unicode handling with new monkeypatch.setattr(import_path, value) + API. Thanks Rob Dennis. Fixes issue371. + +- fix unicode handling with junitxml, fixes issue368. + +- In assertion rewriting mode on Python 2, fix the detection of coding + cookies. See issue #330. + +- make "--runxfail" turn imperative pytest.xfail calls into no ops + (it already did neutralize pytest.mark.xfail markers) + +- refine pytest / pkg_resources interactions: The AssertionRewritingHook + PEP302 compliant loader now registers itself with setuptools/pkg_resources + properly so that the pkg_resources.resource_stream method works properly. + Fixes issue366. Thanks for the investigations and full PR to Jason R. Coombs. + +- pytestconfig fixture is now session-scoped as it is the same object during the + whole test run. Fixes issue370. + +- avoid one surprising case of marker malfunction/confusion:: + + @pytest.mark.some(lambda arg: ...) + def test_function(): + + would not work correctly because pytest assumes @pytest.mark.some + gets a function to be decorated already. We now at least detect if this + arg is an lambda and thus the example will work. Thanks Alex Gaynor + for bringing it up. + +- xfail a test on pypy that checks wrong encoding/ascii (pypy does + not error out). fixes issue385. + +- internally make varnames() deal with classes's __init__, + although it's not needed by pytest itself atm. Also + fix caching. Fixes issue376. + +- fix issue221 - handle importing of namespace-package with no + __init__.py properly. + +- refactor internal FixtureRequest handling to avoid monkeypatching. + One of the positive user-facing effects is that the "request" object + can now be used in closures. + +- fixed version comparison in pytest.importskip(modname, minverstring) + +- fix issue377 by clarifying in the nose-compat docs that pytest + does not duplicate the unittest-API into the "plain" namespace. + +- fix verbose reporting for @mock'd test functions + diff -Nru pytest-2.4.2/doc/en/announce/release-2.5.1.txt pytest-2.5.1/doc/en/announce/release-2.5.1.txt --- pytest-2.4.2/doc/en/announce/release-2.5.1.txt 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/announce/release-2.5.1.txt 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,47 @@ +pytest-2.5.1: fixes and new home page styling +=========================================================================== + +pytest is a mature Python testing tool with more than a 1000 tests +against itself, passing on many different interpreters and platforms. + +The 2.5.1 release maintains the "zero-reported-bugs" promise by fixing +the three bugs reported since the last release a few days ago. It also +features a new home page styling implemented by Tobias Bieniek, based on +the flask theme from Armin Ronacher: + + http://pytest.org + +If you have anything more to improve styling and docs, +we'd be very happy to merge further pull requests. + +On the coding side, the release also contains a little enhancement to +fixture decorators allowing to directly influence generation of test +ids, thanks to Floris Bruynooghe. Other thanks for helping with +this release go to Anatoly Bubenkoff and Ronny Pfannschmidt. + +As usual, you can upgrade from pypi via:: + + pip install -U pytest + +have fun and a nice remaining "bug-free" time of the year :) +holger krekel + +2.5.1 +----------------------------------- + +- merge new documentation styling PR from Tobias Bieniek. + +- fix issue403: allow parametrize of multiple same-name functions within + a collection node. Thanks Andreas Kloeckner and Alex Gaynor for reporting + and analysis. + +- Allow parameterized fixtures to specify the ID of the parameters by + adding an ids argument to pytest.fixture() and pytest.yield_fixture(). + Thanks Floris Bruynooghe. + +- fix issue404 by always using the binary xml escape in the junitxml + plugin. Thanks Ronny Pfannschmidt. + +- fix issue407: fix addoption docstring to point to argparse instead of + optparse. Thanks Daniel D. Wright. + diff -Nru pytest-2.4.2/doc/en/assert.txt pytest-2.5.1/doc/en/assert.txt --- pytest-2.4.2/doc/en/assert.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/assert.txt 2013-12-17 08:00:02.000000000 +0000 @@ -26,7 +26,7 @@ $ py.test test_assert1.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_assert1.py F @@ -116,7 +116,7 @@ $ py.test test_assert2.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_assert2.py F diff -Nru pytest-2.4.2/doc/en/capture.txt pytest-2.5.1/doc/en/capture.txt --- pytest-2.4.2/doc/en/capture.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/capture.txt 2013-12-17 08:00:02.000000000 +0000 @@ -64,7 +64,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_module.py .F @@ -78,7 +78,7 @@ test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ - setting up + setting up ==================== 1 failed, 1 passed in 0.01 seconds ==================== Accessing captured output from a test function diff -Nru pytest-2.4.2/doc/en/conf.py pytest-2.5.1/doc/en/conf.py --- pytest-2.4.2/doc/en/conf.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/conf.py 2013-12-17 08:00:02.000000000 +0000 @@ -17,8 +17,8 @@ # # The full version, including alpha/beta/rc tags. # The short X.Y version. -version = "2.4.2" -release = "2.4.2" +version = "2.5.1" +release = "2.5.1" import sys, os @@ -105,14 +105,19 @@ # -- Options for HTML output --------------------------------------------------- +sys.path.append(os.path.abspath('_themes')) +html_theme_path = ['_themes'] + # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinxdoc' +html_theme = 'flask' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = {} +html_theme_options = { + 'index_logo': None +} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -150,6 +155,23 @@ #html_sidebars = {} #html_sidebars = {'index': 'indexsidebar.html'} +html_sidebars = { + 'index': [ + 'sidebarintro.html', + 'globaltoc.html', + 'links.html', + 'sourcelink.html', + 'searchbox.html' + ], + '**': [ + 'globaltoc.html', + 'relations.html', + 'links.html', + 'sourcelink.html', + 'searchbox.html' + ] +} + # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} diff -Nru pytest-2.4.2/doc/en/customize.txt pytest-2.5.1/doc/en/customize.txt --- pytest-2.4.2/doc/en/customize.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/customize.txt 2013-12-17 08:00:02.000000000 +0000 @@ -121,6 +121,8 @@ .. confval:: python_functions One or more name prefixes determining which test functions - and methods are considered as test modules. + and methods are considered as test modules. Note that this + has no effect on methods that live on a ``unittest.TestCase`` + derived class. See :ref:`change naming conventions` for examples. diff -Nru pytest-2.4.2/doc/en/doctest.txt pytest-2.5.1/doc/en/doctest.txt --- pytest-2.4.2/doc/en/doctest.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/doctest.txt 2013-12-17 08:00:02.000000000 +0000 @@ -44,7 +44,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items mymodule.py . @@ -56,3 +56,7 @@ # content of example.rst >>> tmp = getfixture('tmpdir') >>> ... + >>> + +Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported +when executing text doctest files. diff -Nru pytest-2.4.2/doc/en/example/markers.txt pytest-2.5.1/doc/en/example/markers.txt --- pytest-2.4.2/doc/en/example/markers.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/markers.txt 2013-12-17 08:00:02.000000000 +0000 @@ -28,7 +28,7 @@ $ py.test -v -m webtest =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items test_server.py:3: test_send_http PASSED @@ -40,7 +40,7 @@ $ py.test -v -m "not webtest" =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items test_server.py:6: test_something_quick PASSED @@ -61,7 +61,7 @@ $ py.test -v -k http # running with the above defined example module =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items test_server.py:3: test_send_http PASSED @@ -73,7 +73,7 @@ $ py.test -k "not send_http" -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items test_server.py:6: test_something_quick PASSED @@ -86,7 +86,7 @@ $ py.test -k "http or quick" -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 3 items test_server.py:3: test_send_http PASSED @@ -95,6 +95,17 @@ ================= 1 tests deselected by '-khttp or quick' ================== ================== 2 passed, 1 deselected in 0.01 seconds ================== +.. note:: + + If you are using expressions such as "X and Y" then both X and Y + need to be simple non-keyword names. For example, "pass" or "from" + will result in SyntaxErrors because "-k" evaluates the expression. + + However, if the "-k" argument is a simple string, no such restrictions + apply. Also "-k 'not STRING'" has no restrictions. You can also + specify numbers like "-k 1.3" to match tests which are parametrized + with the float "1.3". + Registering markers ------------------------------------- @@ -118,7 +129,7 @@ @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2. see http://pytest.org/latest/parametrize.html for more info and examples. + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures @@ -255,7 +266,7 @@ $ py.test -E stage2 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_someenv.py s @@ -266,7 +277,7 @@ $ py.test -E stage1 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_someenv.py . @@ -282,7 +293,7 @@ @pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html - @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in multiple different argument value sets. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2. see http://pytest.org/latest/parametrize.html for more info and examples. + @pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples. @pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures @@ -384,12 +395,12 @@ $ py.test -rs # this option reports skip reasons =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_plat.py s.s. ========================= short test summary info ========================== - SKIP [2] /tmp/doc-exec-598/conftest.py:12: cannot run on platform linux2 + SKIP [2] /tmp/doc-exec-63/conftest.py:12: cannot run on platform linux2 =================== 2 passed, 2 skipped in 0.01 seconds ==================== @@ -397,7 +408,7 @@ $ py.test -m linux2 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_plat.py . @@ -448,7 +459,7 @@ $ py.test -m interface --tb=short =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_module.py FF @@ -469,7 +480,7 @@ $ py.test -m "interface or event" --tb=short =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_module.py FFF @@ -488,4 +499,4 @@ > assert 0 E assert 0 ============= 1 tests deselected by "-m 'interface or event'" ============== - ================== 3 failed, 1 deselected in 0.02 seconds ================== + ================== 3 failed, 1 deselected in 0.01 seconds ================== diff -Nru pytest-2.4.2/doc/en/example/nonpython.txt pytest-2.5.1/doc/en/example/nonpython.txt --- pytest-2.4.2/doc/en/example/nonpython.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/nonpython.txt 2013-12-17 08:00:02.000000000 +0000 @@ -27,7 +27,7 @@ nonpython $ py.test test_simple.yml =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_simple.yml .F @@ -56,7 +56,7 @@ nonpython $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 2 items test_simple.yml:1: usecase: ok PASSED @@ -74,10 +74,10 @@ nonpython $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items - ============================= in 0.03 seconds ============================= + ============================= in 0.02 seconds ============================= diff -Nru pytest-2.4.2/doc/en/example/parametrize.txt pytest-2.5.1/doc/en/example/parametrize.txt --- pytest-2.4.2/doc/en/example/parametrize.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/parametrize.txt 2013-12-17 08:00:02.000000000 +0000 @@ -106,7 +106,7 @@ $ py.test test_scenarios.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_scenarios.py .... @@ -118,7 +118,7 @@ $ py.test --collect-only test_scenarios.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items @@ -182,7 +182,7 @@ $ py.test test_backends.py --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items @@ -197,7 +197,7 @@ ================================= FAILURES ================================= _________________________ test_db_initialized[d2] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -251,16 +251,16 @@ $ py.test -q F.. ================================= FAILURES ================================= - ________________________ TestClass.test_equals[1-2] ________________________ + ________________________ TestClass.test_equals[2-1] ________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 def test_equals(self, a, b): > assert a == b E assert 1 == 2 test_parametrize.py:18: AssertionError - 1 failed, 2 passed in 0.02 seconds + 1 failed, 2 passed in 0.01 seconds Indirect parametrization with multiple fixtures -------------------------------------------------------------- @@ -282,7 +282,7 @@ ............sss............sss............sss............ssssssssssssssssss ========================= short test summary info ========================== SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:21: 'python2.8' not found - 48 passed, 27 skipped in 1.37 seconds + 48 passed, 27 skipped in 1.34 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- @@ -329,12 +329,12 @@ $ py.test -rs test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items - test_module.py s. + test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-600/conftest.py:10: could not import 'opt2' + SKIP [1] /tmp/doc-exec-65/conftest.py:10: could not import 'opt2' =================== 1 passed, 1 skipped in 0.01 seconds ==================== diff -Nru pytest-2.4.2/doc/en/example/pythoncollection.txt pytest-2.5.1/doc/en/example/pythoncollection.txt --- pytest-2.4.2/doc/en/example/pythoncollection.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/pythoncollection.txt 2013-12-17 08:00:02.000000000 +0000 @@ -43,7 +43,7 @@ $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items @@ -53,6 +53,12 @@ ============================= in 0.01 seconds ============================= +.. note:: + + the ``python_functions`` and ``python_classes`` has no effect + for ``unittest.TestCase`` test discovery because pytest delegates + detection of test case methods to unittest code. + Interpreting cmdline arguments as Python packages ----------------------------------------------------- @@ -82,7 +88,7 @@ . $ py.test --collect-only pythoncollection.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 3 items @@ -135,7 +141,7 @@ $ py.test --collect-only =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items diff -Nru pytest-2.4.2/doc/en/example/reportingdemo.txt pytest-2.5.1/doc/en/example/reportingdemo.txt --- pytest-2.4.2/doc/en/example/reportingdemo.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/reportingdemo.txt 2013-12-17 08:00:02.000000000 +0000 @@ -13,7 +13,7 @@ assertion $ py.test failure_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 39 items failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF @@ -30,7 +30,7 @@ failure_demo.py:15: AssertionError _________________________ TestFailing.test_simple __________________________ - self = + self = def test_simple(self): def f(): @@ -40,13 +40,13 @@ > assert f() == g() E assert 42 == 43 - E + where 42 = () - E + and 43 = () + E + where 42 = () + E + and 43 = () failure_demo.py:28: AssertionError ____________________ TestFailing.test_simple_multiline _____________________ - self = + self = def test_simple_multiline(self): otherfunc_multi( @@ -66,19 +66,19 @@ failure_demo.py:11: AssertionError ___________________________ TestFailing.test_not ___________________________ - self = + self = def test_not(self): def f(): return 42 > assert not f() E assert not 42 - E + where 42 = () + E + where 42 = () failure_demo.py:38: AssertionError _________________ TestSpecialisedExplanations.test_eq_text _________________ - self = + self = def test_eq_text(self): > assert 'spam' == 'eggs' @@ -89,7 +89,7 @@ failure_demo.py:42: AssertionError _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ - self = + self = def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' @@ -102,7 +102,7 @@ failure_demo.py:45: AssertionError ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ - self = + self = def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' @@ -115,7 +115,7 @@ failure_demo.py:48: AssertionError ______________ TestSpecialisedExplanations.test_eq_long_text _______________ - self = + self = def test_eq_long_text(self): a = '1'*100 + 'a' + '2'*100 @@ -132,7 +132,7 @@ failure_demo.py:53: AssertionError _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ - self = + self = def test_eq_long_text_multiline(self): a = '1\n'*100 + 'a' + '2\n'*100 @@ -156,7 +156,7 @@ failure_demo.py:58: AssertionError _________________ TestSpecialisedExplanations.test_eq_list _________________ - self = + self = def test_eq_list(self): > assert [0, 1, 2] == [0, 1, 3] @@ -166,7 +166,7 @@ failure_demo.py:61: AssertionError ______________ TestSpecialisedExplanations.test_eq_list_long _______________ - self = + self = def test_eq_list_long(self): a = [0]*100 + [1] + [3]*100 @@ -178,7 +178,7 @@ failure_demo.py:66: AssertionError _________________ TestSpecialisedExplanations.test_eq_dict _________________ - self = + self = def test_eq_dict(self): > assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0} @@ -194,7 +194,7 @@ failure_demo.py:69: AssertionError _________________ TestSpecialisedExplanations.test_eq_set __________________ - self = + self = def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) @@ -210,7 +210,7 @@ failure_demo.py:72: AssertionError _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ - self = + self = def test_eq_longer_list(self): > assert [1,2] == [1,2,3] @@ -220,7 +220,7 @@ failure_demo.py:75: AssertionError _________________ TestSpecialisedExplanations.test_in_list _________________ - self = + self = def test_in_list(self): > assert 1 in [0, 2, 3, 4, 5] @@ -229,7 +229,7 @@ failure_demo.py:78: AssertionError __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ - self = + self = def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' @@ -247,7 +247,7 @@ failure_demo.py:82: AssertionError ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ - self = + self = def test_not_in_text_single(self): text = 'single foo line' @@ -260,7 +260,7 @@ failure_demo.py:86: AssertionError _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ - self = + self = def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 @@ -273,7 +273,7 @@ failure_demo.py:90: AssertionError ______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______ - self = + self = def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 @@ -292,7 +292,7 @@ i = Foo() > assert i.b == 2 E assert 1 == 2 - E + where 1 = .b + E + where 1 = .b failure_demo.py:101: AssertionError _________________________ test_attribute_instance __________________________ @@ -302,8 +302,8 @@ b = 1 > assert Foo().b == 2 E assert 1 == 2 - E + where 1 = .b - E + where = () + E + where 1 = .b + E + where = () failure_demo.py:107: AssertionError __________________________ test_attribute_failure __________________________ @@ -319,7 +319,7 @@ failure_demo.py:116: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - self = + self = def _get_b(self): > raise Exception('Failed to get attrib') @@ -335,15 +335,15 @@ b = 2 > assert Foo().b == Bar().b E assert 1 == 2 - E + where 1 = .b - E + where = () - E + and 2 = .b - E + where = () + E + where 1 = .b + E + where = () + E + and 2 = .b + E + where = () failure_demo.py:124: AssertionError __________________________ TestRaises.test_raises __________________________ - self = + self = def test_raises(self): s = 'qwe' @@ -355,10 +355,10 @@ > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:905>:1: ValueError + <0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:983>:1: ValueError ______________________ TestRaises.test_raises_doesnt _______________________ - self = + self = def test_raises_doesnt(self): > raises(IOError, "int('3')") @@ -367,7 +367,7 @@ failure_demo.py:136: Failed __________________________ TestRaises.test_raise ___________________________ - self = + self = def test_raise(self): > raise ValueError("demo error") @@ -376,7 +376,7 @@ failure_demo.py:139: ValueError ________________________ TestRaises.test_tupleerror ________________________ - self = + self = def test_tupleerror(self): > a,b = [1] @@ -385,7 +385,7 @@ failure_demo.py:142: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ - self = + self = def test_reinterpret_fails_with_print_for_the_fun_of_it(self): l = [1,2,3] @@ -398,7 +398,7 @@ l is [1, 2, 3] ________________________ TestRaises.test_some_error ________________________ - self = + self = def test_some_error(self): > if namenotexi: @@ -426,7 +426,7 @@ <2-codegen 'abc-123' /home/hpk/p/pytest/doc/en/example/assertion/failure_demo.py:162>:2: AssertionError ____________________ TestMoreErrors.test_complex_error _____________________ - self = + self = def test_complex_error(self): def f(): @@ -455,7 +455,7 @@ failure_demo.py:5: AssertionError ___________________ TestMoreErrors.test_z1_unpack_error ____________________ - self = + self = def test_z1_unpack_error(self): l = [] @@ -465,7 +465,7 @@ failure_demo.py:179: ValueError ____________________ TestMoreErrors.test_z2_type_error _____________________ - self = + self = def test_z2_type_error(self): l = 3 @@ -475,19 +475,19 @@ failure_demo.py:183: TypeError ______________________ TestMoreErrors.test_startswith ______________________ - self = + self = def test_startswith(self): s = "123" g = "456" > assert s.startswith(g) - E assert ('456') - E + where = '123'.startswith + E assert ('456') + E + where = '123'.startswith failure_demo.py:188: AssertionError __________________ TestMoreErrors.test_startswith_nested ___________________ - self = + self = def test_startswith_nested(self): def f(): @@ -495,15 +495,15 @@ def g(): return "456" > assert f().startswith(g()) - E assert ('456') - E + where = '123'.startswith - E + where '123' = () - E + and '456' = () + E assert ('456') + E + where = '123'.startswith + E + where '123' = () + E + and '456' = () failure_demo.py:195: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - self = + self = def test_global_func(self): > assert isinstance(globf(42), float) @@ -513,18 +513,18 @@ failure_demo.py:198: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - self = + self = def test_instance(self): self.x = 6*7 > assert self.x != 42 E assert 42 != 42 - E + where 42 = .x + E + where 42 = .x failure_demo.py:202: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - self = + self = def test_compare(self): > assert globf(10) < 5 @@ -534,7 +534,7 @@ failure_demo.py:205: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - self = + self = def test_try_finally(self): x = 1 @@ -543,4 +543,4 @@ E assert 1 == 0 failure_demo.py:210: AssertionError - ======================== 39 failed in 0.26 seconds ========================= + ======================== 39 failed in 0.20 seconds ========================= diff -Nru pytest-2.4.2/doc/en/example/simple.txt pytest-2.5.1/doc/en/example/simple.txt --- pytest-2.4.2/doc/en/example/simple.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/simple.txt 2013-12-17 08:00:02.000000000 +0000 @@ -108,7 +108,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 0 items ============================= in 0.00 seconds ============================= @@ -152,12 +152,12 @@ $ py.test -rs # "-rs" means report details on the little 's' =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-603/conftest.py:9: need --runslow option to run + SKIP [1] /tmp/doc-exec-68/conftest.py:9: need --runslow option to run =================== 1 passed, 1 skipped in 0.01 seconds ==================== @@ -165,7 +165,7 @@ $ py.test --runslow =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_module.py .. @@ -256,7 +256,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 project deps: mylib-1.1 collected 0 items @@ -279,7 +279,7 @@ $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python info1: did you know that ... did you? collecting ... collected 0 items @@ -290,7 +290,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 0 items ============================= in 0.00 seconds ============================= @@ -322,7 +322,7 @@ $ py.test --durations=3 =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 3 items test_some_are_slow.py ... @@ -383,7 +383,7 @@ $ py.test -rx =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 4 items test_step.py .Fx. @@ -391,7 +391,7 @@ ================================= FAILURES ================================= ____________________ TestUserHandling.test_modification ____________________ - self = + self = def test_modification(self): > assert 0 @@ -401,7 +401,7 @@ ========================= short test summary info ========================== XFAIL test_step.py::TestUserHandling::()::test_deletion reason: previous test failed (test_modification) - ============== 1 failed, 2 passed, 1 xfailed in 0.02 seconds =============== + ============== 1 failed, 2 passed, 1 xfailed in 0.01 seconds =============== We'll see that ``test_deletion`` was not executed because ``test_modification`` failed. It is reported as an "expected failure". @@ -453,7 +453,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 7 items test_step.py .Fx. @@ -463,17 +463,17 @@ ================================== ERRORS ================================== _______________________ ERROR at setup of test_root ________________________ - file /tmp/doc-exec-603/b/test_error.py, line 1 + file /tmp/doc-exec-68/b/test_error.py, line 1 def test_root(db): # no db here, will error out fixture 'db' not found - available fixtures: pytestconfig, recwarn, monkeypatch, capfd, capsys, tmpdir + available fixtures: recwarn, capfd, pytestconfig, capsys, tmpdir, monkeypatch use 'py.test --fixtures [testpath]' for help on them. - /tmp/doc-exec-603/b/test_error.py:1 + /tmp/doc-exec-68/b/test_error.py:1 ================================= FAILURES ================================= ____________________ TestUserHandling.test_modification ____________________ - self = + self = def test_modification(self): > assert 0 @@ -482,20 +482,20 @@ test_step.py:9: AssertionError _________________________________ test_a1 __________________________________ - db = + db = def test_a1(db): > assert 0, db # to show value - E AssertionError: + E AssertionError: a/test_db.py:2: AssertionError _________________________________ test_a2 __________________________________ - db = + db = def test_a2(db): > assert 0, db # to show value - E AssertionError: + E AssertionError: a/test_db2.py:2: AssertionError ========== 3 failed, 2 passed, 1 xfailed, 1 error in 0.03 seconds ========== @@ -553,7 +553,7 @@ $ py.test test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_module.py FF @@ -561,7 +561,7 @@ ================================= FAILURES ================================= ________________________________ test_fail1 ________________________________ - tmpdir = local('/tmp/pytest-190/test_fail10') + tmpdir = local('/tmp/pytest-42/test_fail10') def test_fail1(tmpdir): > assert 0 @@ -580,7 +580,7 @@ you will have a "failures" file which contains the failing test ids:: $ cat failures - test_module.py::test_fail1 (/tmp/pytest-190/test_fail10) + test_module.py::test_fail1 (/tmp/pytest-42/test_fail10) test_module.py::test_fail2 Making test result information available in fixtures @@ -643,7 +643,7 @@ $ py.test -s test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 3 items test_module.py Esetting up a test failed! test_module.py::test_setup_fails @@ -676,7 +676,7 @@ E assert 0 test_module.py:15: AssertionError - ==================== 2 failed, 1 error in 0.02 seconds ===================== + ==================== 2 failed, 1 error in 0.01 seconds ===================== You'll see that the fixture finalizers could use the precise reporting information. diff -Nru pytest-2.4.2/doc/en/example/special.txt pytest-2.5.1/doc/en/example/special.txt --- pytest-2.4.2/doc/en/example/special.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/example/special.txt 2013-12-17 08:00:02.000000000 +0000 @@ -70,4 +70,4 @@ .test other .test_unit1 method called . - 4 passed in 0.02 seconds + 4 passed in 0.01 seconds diff -Nru pytest-2.4.2/doc/en/fixture.txt pytest-2.5.1/doc/en/fixture.txt --- pytest-2.4.2/doc/en/fixture.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/fixture.txt 2013-12-17 08:00:02.000000000 +0000 @@ -76,7 +76,7 @@ $ py.test test_smtpsimple.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_smtpsimple.py F @@ -84,7 +84,7 @@ ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - smtp = + smtp = def test_ehlo(smtp): response, msg = smtp.ehlo() @@ -94,7 +94,7 @@ E assert 0 test_smtpsimple.py:12: AssertionError - ========================= 1 failed in 0.18 seconds ========================= + ========================= 1 failed in 0.21 seconds ========================= In the failure traceback we see that the test function was called with a ``smtp`` argument, the ``smtplib.SMTP()`` instance created by the fixture @@ -194,7 +194,7 @@ $ py.test test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_module.py FF @@ -202,7 +202,7 @@ ================================= FAILURES ================================= ________________________________ test_ehlo _________________________________ - smtp = + smtp = def test_ehlo(smtp): response = smtp.ehlo() @@ -214,7 +214,7 @@ test_module.py:6: AssertionError ________________________________ test_noop _________________________________ - smtp = + smtp = def test_noop(smtp): response = smtp.noop() @@ -223,7 +223,7 @@ E assert 0 test_module.py:11: AssertionError - ========================= 2 failed in 0.16 seconds ========================= + ========================= 2 failed in 0.17 seconds ========================= You see the two ``assert 0`` failing and more importantly you can also see that the same (module-scoped) ``smtp`` object was passed into the two @@ -234,7 +234,7 @@ If you decide that you rather want to have a session-scoped ``smtp`` instance, you can simply declare it:: - @pytest.fixture(scope=``session``) + @pytest.fixture(scope="session") def smtp(...): # the returned fixture value will be shared for # all tests needing it @@ -271,7 +271,7 @@ $ py.test -s -q --tb=no FFteardown smtp - 2 failed in 0.15 seconds + 2 failed in 0.17 seconds We see that the ``smtp`` instance is finalized after the two tests finished execution. Note that if we decorated our fixture @@ -312,7 +312,7 @@ $ py.test -s -q --tb=no FF - 2 failed in 0.16 seconds + 2 failed in 0.21 seconds Let's quickly create another test module that actually sets the server URL in its module namespace:: @@ -379,7 +379,7 @@ ================================= FAILURES ================================= __________________________ test_ehlo[merlinux.eu] __________________________ - smtp = + smtp = def test_ehlo(smtp): response = smtp.ehlo() @@ -391,7 +391,7 @@ test_module.py:6: AssertionError __________________________ test_noop[merlinux.eu] __________________________ - smtp = + smtp = def test_noop(smtp): response = smtp.noop() @@ -402,7 +402,7 @@ test_module.py:11: AssertionError ________________________ test_ehlo[mail.python.org] ________________________ - smtp = + smtp = def test_ehlo(smtp): response = smtp.ehlo() @@ -411,9 +411,11 @@ E assert 'merlinux' in 'mail.python.org\nSIZE 25600000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN' test_module.py:5: AssertionError + ----------------------------- Captured stdout ------------------------------ + finalizing ________________________ test_noop[mail.python.org] ________________________ - smtp = + smtp = def test_noop(smtp): response = smtp.noop() @@ -422,7 +424,7 @@ E assert 0 test_module.py:11: AssertionError - 4 failed in 6.32 seconds + 4 failed in 6.58 seconds We see that our two test functions each ran twice, against the different ``smtp`` instances. Note also, that with the ``mail.python.org`` @@ -462,13 +464,13 @@ $ py.test -v test_appsetup.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 2 items - test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED test_appsetup.py:12: test_smtp_exists[merlinux.eu] PASSED + test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED - ========================= 2 passed in 5.75 seconds ========================= + ========================= 2 passed in 5.95 seconds ========================= Due to the parametrization of ``smtp`` the test will run twice with two different ``App`` instances and respective smtp servers. There is no @@ -526,7 +528,7 @@ $ py.test -v -s test_module.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 -- /home/hpk/p/pytest/.tox/regen/bin/python + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 -- /home/hpk/p/pytest/.tox/regen/bin/python collecting ... collected 8 items test_module.py:15: test_0[1] test0 1 @@ -624,6 +626,7 @@ usefixtures = cleandir +.. _`autouse`: .. _`autouse fixtures`: autouse fixtures (xUnit setup on steroids) diff -Nru pytest-2.4.2/doc/en/getting-started.txt pytest-2.5.1/doc/en/getting-started.txt --- pytest-2.4.2/doc/en/getting-started.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/getting-started.txt 2013-12-17 08:00:02.000000000 +0000 @@ -1,7 +1,7 @@ Installation and Getting Started =================================== -**Pythons**: Python 2.4-3.3, Jython, PyPy +**Pythons**: Python 2.5-3.3, Jython, PyPy **Platforms**: Unix/Posix and Windows @@ -23,7 +23,7 @@ To check your installation has installed the correct version:: $ py.test --version - This is py.test version 2.4.2, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc + This is py.test version 2.5.1, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc If you get an error checkout :ref:`installation issues`. @@ -45,7 +45,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_sample.py F @@ -93,7 +93,7 @@ $ py.test -q test_sysexit.py . - 1 passed in 0.01 seconds + 1 passed in 0.00 seconds .. todo:: For further ways to assert exceptions see the `raises` @@ -123,7 +123,7 @@ ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - self = + self = def test_two(self): x = "hello" @@ -159,7 +159,7 @@ ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - tmpdir = local('/tmp/pytest-186/test_needsfiles0') + tmpdir = local('/tmp/pytest-38/test_needsfiles0') def test_needsfiles(tmpdir): print tmpdir @@ -168,8 +168,8 @@ test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ - /tmp/pytest-186/test_needsfiles0 - 1 failed in 0.01 seconds + /tmp/pytest-38/test_needsfiles0 + 1 failed in 0.04 seconds Before the test runs, a unique-per-test-invocation temporary directory was created. More info at :ref:`tmpdir handling`. diff -Nru pytest-2.4.2/doc/en/goodpractises.txt pytest-2.5.1/doc/en/goodpractises.txt --- pytest-2.4.2/doc/en/goodpractises.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/goodpractises.txt 2013-12-17 08:00:02.000000000 +0000 @@ -8,24 +8,149 @@ Work with virtual environments ----------------------------------------------------------- -We recommend to use virtualenv_ environments and use easy_install_ -(or pip_) for installing your application dependencies as well as -the ``pytest`` package itself. This way you will get a much more reproducible -environment. A good tool to help you automate test runs against multiple -dependency configurations or Python interpreters is `tox`_. +We recommend to use virtualenv_ environments and use pip_ +(or easy_install_) for installing your application and any dependencies +as well as the ``pytest`` package itself. This way you will get an isolated +and reproducible environment. Given you have installed virtualenv_ +and execute it from the command line, here is an example session for unix +or windows:: + + virtualenv . # create a virtualenv directory in the current directory + + source bin/activate # on unix + + scripts/activate # on Windows + +We can now install pytest:: + + pip install pytest + +Due to the ``activate`` step above the ``pip`` will come from +the virtualenv directory and install any package into the isolated +virtual environment. + +Choosing a test layout / import rules +------------------------------------------ + +py.test supports two common test layouts: + +* putting tests into an extra directory outside your actual application + code, useful if you have many functional tests or for other reasons + want to keep tests separate from actual application code (often a good + idea):: + + setup.py # your distutils/setuptools Python package metadata + mypkg/ + __init__.py + appmodule.py + tests/ + test_app.py + ... + + +* inlining test directories into your application package, useful if you + have direct relation between (unit-)test and application modules and + want to distribute your tests along with your application:: + + setup.py # your distutils/setuptools Python package metadata + mypkg/ + __init__.py + appmodule.py + ... + test/ + test_app.py + ... + +Important notes relating to both schemes: + +- **make sure that "mypkg" is importable**, for example by typing once:: + + pip install -e . # install package using setup.py in editable mode + +- **avoid "__init__.py" files in your test directories**. + This way your tests can run easily against an installed version + of ``mypkg``, independently from if the installed package contains + the tests or not. + +- With inlined tests you might put ``__init__.py`` into test + directories and make them installable as part of your application. + Using the ``py.test --pyargs mypkg`` invocation pytest will + discover where mypkg is installed and collect tests from there. + With the "external" test you can still distribute tests but they + will not be installed or become importable. + +Typically you can run tests by pointing to test directories or modules:: + + py.test tests/test_app.py # for external test dirs + py.test mypkg/test/test_app.py # for inlined test dirs + py.test mypkg # run tests in all below test directories + py.test # run all tests below current dir + ... + +Because of the above ``editable install`` mode you can change your +source code (both tests and the app) and rerun tests at will. +Once you are done with your work, you can `use tox`_ to make sure +that the package is really correct and tests pass in all +required configurations. + +.. note:: + + You can use Python3 namespace packages (PEP420) for your application + but pytest will still perform `test package name`_ discovery based on the + presence of ``__init__.py`` files. If you use one of the + two recommended file system layouts above but leave away the ``__init__.py`` + files from your directories it should just work on Python3.3 and above. From + "inlined tests", however, you will need to use absolute imports for + getting at your application code. + +.. _`test package name`: + +.. note:: + + If py.test finds a "a/b/test_module.py" test file while + recursing into the filesystem it determines the import name + as follows: + + * determine ``basedir``: this is the first "upward" (towards the root) + directory not containing an ``__init__.py``. If e.g. both ``a`` + and ``b`` contain an ``__init__.py`` file then the parent directory + of ``a`` will become the ``basedir``. + + * perform ``sys.path.insert(0, basedir)`` to make the test module + importable under the fully qualified import name. + + * ``import a.b.test_module`` where the path is determined + by converting path separators ``/`` into "." characters. This means + you must follow the convention of having directory and file + names map directly to the import names. + + The reason for this somewhat evolved importing technique is + that in larger projects multiple test modules might import + from each other and thus deriving a canonical import name helps + to avoid surprises such as a test modules getting imported twice. + .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`buildout`: http://www.buildout.org/ .. _pip: http://pypi.python.org/pypi/pip +.. _`use tox`: + Use tox and Continuous Integration servers ------------------------------------------------- -If you frequently release code to the public you -may want to look into `tox`_, the virtualenv test automation -tool and its `pytest support `_. -The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up -and generate reports. +If you frequently release code and want to make sure that your actual +package passes all tests you may want to look into `tox`_, the +virtualenv test automation tool and its `pytest support +`_. +Tox helps you to setup virtualenv environments with pre-defined +dependencies and then executing a pre-configured test command with +options. It will run tests against the installed package and not +against your source code checkout, helping to detect packaging +glitches. + +If you want to use Jenkins_ you can use the ``--junitxml=PATH`` option +to create a JUnitXML file that Jenkins_ can pick up and generate reports. .. _standalone: .. _`genscript method`: @@ -33,21 +158,19 @@ Create a py.test standalone script ------------------------------------------- -If you are a maintainer or application developer and want others -to easily run tests you can generate a completely standalone "py.test" -script:: +If you are a maintainer or application developer and want people +who don't deal with python much to easily run tests you may generate +a standalone "py.test" script:: py.test --genscript=runtests.py -generates a ``runtests.py`` script which is a fully functional basic +This generates a ``runtests.py`` script which is a fully functional basic ``py.test`` script, running unchanged under Python2 and Python3. You can tell people to download the script and then e.g. run it like this:: python runtests.py - - Integrating with distutils / ``python setup.py test`` -------------------------------------------------------- @@ -93,8 +216,9 @@ Integration with setuptools test commands ---------------------------------------------------- -Setuptools supports writing our own Test command for invoking -pytest:: +Setuptools supports writing our own Test command for invoking pytest. +Most often it is better to use tox_ instead, but here is how you can +get started with setuptools integration:: from setuptools.command.test import test as TestCommand import sys @@ -143,69 +267,4 @@ Within Python modules, py.test also discovers tests using the standard :ref:`unittest.TestCase ` subclassing technique. -Choosing a test layout / import rules ------------------------------------------- - -py.test supports common test layouts: - -* inlining test directories into your application package, useful if you want to - keep (unit) tests and actually tested code close together:: - - mypkg/ - __init__.py - appmodule.py - ... - test/ - test_app.py - ... - -* putting tests into an extra directory outside your actual application - code, useful if you have many functional tests or want to keep - tests separate from actual application code:: - - mypkg/ - __init__.py - appmodule.py - tests/ - test_app.py - ... - -In both cases you usually need to make sure that ``mypkg`` is importable, -for example by using the setuptools ``python setup.py develop`` method. - -You can run your tests by pointing to it:: - - py.test tests/test_app.py # for external test dirs - py.test mypkg/test/test_app.py # for inlined test dirs - py.test mypkg # run tests in all below test directories - py.test # run all tests below current dir - ... - -.. _`package name`: - -.. note:: - - If py.test finds a "a/b/test_module.py" test file while - recursing into the filesystem it determines the import name - as follows: - - * find ``basedir`` -- this is the first "upward" (towards the root) - directory not containing an ``__init__.py``. If both the ``a`` - and ``b`` directories contain an ``__init__.py`` the basedir will - be the parent dir of ``a``. - - * perform ``sys.path.insert(0, basedir)`` to make the test module - importable under the fully qualified import name. - - * ``import a.b.test_module`` where the path is determined - by converting path separators ``/`` into "." characters. This means - you must follow the convention of having directory and file - names map directly to the import names. - - The reason for this somewhat evolved importing technique is - that in larger projects multiple test modules might import - from each other and thus deriving a canonical import name helps - to avoid surprises such as a test modules getting imported twice. - - .. include:: links.inc diff -Nru pytest-2.4.2/doc/en/index.txt pytest-2.5.1/doc/en/index.txt --- pytest-2.4.2/doc/en/index.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/index.txt 2013-12-17 08:00:02.000000000 +0000 @@ -1,52 +1,51 @@ .. _features: -.. note:: second training: `professional testing with Python `_ , 25-27th November 2013, Leipzig. +.. second training: `professional testing with Python `_ , 25-27th November 2013, Leipzig. pytest: helps you write better programs ============================================= **a mature full-featured Python testing tool** - - runs on Posix/Windows, Python 2.4-3.3, PyPy and Jython-2.5.1 + - runs on Posix/Windows, Python 2.5-3.3, PyPy and Jython-2.5.1 + - **zero-reported-bugs** policy with >1000 tests against itself + - **strict backward compatibility policy** for safe pytest upgrades - :ref:`comprehensive online ` and `PDF documentation `_ - - many :ref:`third party plugins ` and - :ref:`builtin helpers ` - - used in :ref:`many projects and organisations `, in test - suites with up to twenty thousand tests - - strict policy of remaining backward compatible across releases + - many :ref:`third party plugins ` and :ref:`builtin helpers `, + - used in :ref:`many small and large projects and organisations ` - comes with many :ref:`tested examples ` **provides easy no-boilerplate testing** - makes it :ref:`easy to get started `, - many :ref:`usage options ` + has many :ref:`usage options ` - :ref:`assert with the assert statement` - helpful :ref:`traceback and failing assertion reporting ` - - allows :ref:`print debugging ` and :ref:`the + - :ref:`print debugging ` and :ref:`the capturing of standard output during test execution ` **scales from simple unit to complex functional testing** - :ref:`modular parametrizeable fixtures ` (new in 2.3, - improved in 2.4) + continously improved) - :ref:`parametrized test functions ` - :ref:`mark` - :ref:`skipping` (improved in 2.4) - - can :ref:`distribute tests to multiple CPUs ` through :ref:`xdist plugin ` - - can :ref:`continuously re-run failing tests ` + - :ref:`distribute tests to multiple CPUs ` through :ref:`xdist plugin ` + - :ref:`continuously re-run failing tests ` - flexible :ref:`Python test discovery` -**integrates many common testing methods**: +**integrates with other testing methods and tools**: - - multi-paradigm: pytest can run many ``nose``, ``unittest.py`` and - ``doctest.py`` style test suites, including running testcases made for + - multi-paradigm: pytest can run ``nose``, ``unittest`` and + ``doctest`` style test suites, including running testcases made for Django and trial - supports :ref:`good integration practises ` - supports extended :ref:`xUnit style setup ` - supports domain-specific :ref:`non-python tests` - - supports the generation of testing coverage reports - - `Javascript unit- and functional testing`_ + - supports generating `test coverage reports + `_ - supports :pep:`8` compliant coding styles in tests **extensive plugin and customization system**: @@ -56,8 +55,6 @@ - it is easy to add command line options or customize existing behaviour -.. _`Javascript unit- and functional testing`: http://pypi.python.org/pypi/oejskit - .. _`easy`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html diff -Nru pytest-2.4.2/doc/en/nose.txt pytest-2.5.1/doc/en/nose.txt --- pytest-2.4.2/doc/en/nose.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/nose.txt 2013-12-17 08:00:02.000000000 +0000 @@ -30,9 +30,25 @@ Unsupported idioms / known issues ---------------------------------- +- unittest-style ``setUp, tearDown, setUpClass, tearDownClass`` + are recognized only on ``unittest.TestCase`` classes but not + on plain classes. ``nose`` supports these methods also on plain + classes but pytest deliberately does not. As nose and pytest already + both support ``setup_class, teardown_class, setup_method, teardown_method`` + it doesn't seem useful to duplicate the unittest-API like nose does. + If you however rather think pytest should support the unittest-spelling on + plain classes please post `to this issue + `_. + +- nose imports test modules with the same import path (e.g. + ``tests.test_mod``) but different file system paths + (e.g. ``tests/test_mode.py`` and ``other/tests/test_mode.py``) + by extending sys.path/import semantics. pytest does not do that + but there is discussion in `issue268 `_ for adding some support. Note that + `nose2 choose to avoid this sys.path/import hackery `_. + - nose-style doctests are not collected and executed correctly, also doctest fixtures don't work. - no nose-configuration is recognized - diff -Nru pytest-2.4.2/doc/en/parametrize.txt pytest-2.5.1/doc/en/parametrize.txt --- pytest-2.4.2/doc/en/parametrize.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/parametrize.txt 2013-12-17 08:00:02.000000000 +0000 @@ -53,7 +53,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 3 items test_expectation.py ..F @@ -100,7 +100,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 3 items test_expectation.py ..x @@ -170,8 +170,8 @@ def test_valid_string(stringinput): > assert stringinput.isalpha() - E assert () - E + where = '!'.isalpha + E assert () + E + where = '!'.isalpha test_strings.py:3: AssertionError 1 failed in 0.01 seconds @@ -185,7 +185,7 @@ $ py.test -q -rs test_strings.py s ========================= short test summary info ========================== - SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:1024: got empty parameter set, function test_valid_string at /tmp/doc-exec-561/test_strings.py:1 + SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:1094: got empty parameter set, function test_valid_string at /tmp/doc-exec-24/test_strings.py:1 1 skipped in 0.01 seconds For further examples, you might want to look at :ref:`more diff -Nru pytest-2.4.2/doc/en/plugins_index/plugins_index.py pytest-2.5.1/doc/en/plugins_index/plugins_index.py --- pytest-2.4.2/doc/en/plugins_index/plugins_index.py 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/plugins_index/plugins_index.py 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,194 @@ +''' +Script to generate the file `plugins_index.txt` with information about pytest plugins taken directly +from a live PyPI server. + +This will evolve to include test compatibility (pythons and pytest versions) information also. +''' +from collections import namedtuple +import datetime +from distutils.version import LooseVersion +import itertools +from optparse import OptionParser +import os +import sys +import xmlrpclib + +import pytest + +#=================================================================================================== +# iter_plugins +#=================================================================================================== +def iter_plugins(client, search='pytest-'): + ''' + Returns an iterator of (name, version) from PyPI. + + :param client: xmlrpclib.ServerProxy + :param search: package names to search for + ''' + for plug_data in client.search({'name' : search}): + yield plug_data['name'], plug_data['version'] + + +#=================================================================================================== +# get_latest_versions +#=================================================================================================== +def get_latest_versions(plugins): + ''' + Returns an iterator of (name, version) from the given list of (name, version), but returning + only the latest version of the package. Uses distutils.LooseVersion to ensure compatibility + with PEP386. + ''' + plugins = [(name, LooseVersion(version)) for (name, version) in plugins] + for name, grouped_plugins in itertools.groupby(plugins, key=lambda x: x[0]): + name, loose_version = list(grouped_plugins)[-1] + yield name, str(loose_version) + + +#=================================================================================================== +# obtain_plugins_table +#=================================================================================================== +def obtain_plugins_table(plugins, client): + ''' + Returns information to populate a table of plugins, their versions, authors, etc. + + The returned information is a list of columns of `ColumnData` namedtuples(text, link). Link + can be None if the text for that column should not be linked to anything. + + :param plugins: list of (name, version) + :param client: xmlrpclib.ServerProxy + ''' + rows = [] + ColumnData = namedtuple('ColumnData', 'text link') + headers = ['Name', 'Author', 'Downloads', 'Python 2.7', 'Python 3.3', 'Summary'] + pytest_version = pytest.__version__ + print '*** pytest-{} ***'.format(pytest_version) + plugins = list(plugins) + for index, (package_name, version) in enumerate(plugins): + print package_name, version, '...', + + release_data = client.release_data(package_name, version) + download_count = release_data['downloads']['last_month'] + image_url = '.. image:: http://pytest-plugs.herokuapp.com/status/{name}-{version}'.format(name=package_name, + version=version) + image_url += '?py={py}&pytest={pytest}' + row = ( + ColumnData(package_name + '-' + version, release_data['release_url']), + ColumnData(release_data['author'], release_data['author_email']), + ColumnData(str(download_count), None), + ColumnData(image_url.format(py='py27', pytest=pytest_version), None), + ColumnData(image_url.format(py='py33', pytest=pytest_version), None), + ColumnData(release_data['summary'], None), + ) + assert len(row) == len(headers) + rows.append(row) + + print 'OK (%d%%)' % ((index + 1) * 100 / len(plugins)) + + return headers, rows + + +#=================================================================================================== +# generate_plugins_index_from_table +#=================================================================================================== +def generate_plugins_index_from_table(filename, headers, rows): + ''' + Generates a RST file with the table data given. + + :param filename: output filename + :param headers: see `obtain_plugins_table` + :param rows: see `obtain_plugins_table` + ''' + # creates a list of rows, each being a str containing appropriate column text and link + table_texts = [] + for row in rows: + column_texts = [] + for i, col_data in enumerate(row): + text = '`%s <%s>`_' % (col_data.text, col_data.link) if col_data.link else col_data.text + column_texts.append(text) + table_texts.append(column_texts) + + # compute max length of each column so we can build the rst table + column_lengths = [len(x) for x in headers] + for column_texts in table_texts: + for i, row_text in enumerate(column_texts): + column_lengths[i] = max(column_lengths[i], len(row_text) + 2) + + def get_row_limiter(char): + return ' '.join(char * length for length in column_lengths) + + with file(filename, 'w') as f: + # write welcome + print >> f, '.. _plugins_index:' + print >> f + print >> f, 'List of Third-Party Plugins' + print >> f, '===========================' + print >> f + + # table + print >> f, get_row_limiter('=') + for i, header in enumerate(headers): + print >> f, '{:^{fill}}'.format(header, fill=column_lengths[i]), + print >> f + print >> f, get_row_limiter('=') + + for column_texts in table_texts: + for i, row_text in enumerate(column_texts): + print >> f, '{:^{fill}}'.format(row_text, fill=column_lengths[i]), + print >> f + print >> f + print >> f, get_row_limiter('=') + print >> f + print >> f, '*(Downloads are given from last month only)*' + print >> f + print >> f, '*(Updated on %s)*' % _get_today_as_str() + + +#=================================================================================================== +# _get_today_as_str +#=================================================================================================== +def _get_today_as_str(): + ''' + internal. only exists so we can patch it in testing. + ''' + return datetime.date.today().strftime('%Y-%m-%d') + + +#=================================================================================================== +# generate_plugins_index +#=================================================================================================== +def generate_plugins_index(client, filename): + ''' + Generates an RST file with a table of the latest pytest plugins found in PyPI. + + :param client: xmlrpclib.ServerProxy + :param filename: output filename + ''' + plugins = get_latest_versions(iter_plugins(client)) + headers, rows = obtain_plugins_table(plugins, client) + generate_plugins_index_from_table(filename, headers, rows) + + +#=================================================================================================== +# main +#=================================================================================================== +def main(argv): + filename = os.path.join(os.path.dirname(__file__), 'plugins_index.txt') + url = 'http://pypi.python.org/pypi' + + parser = OptionParser(description='Generates a restructured document of pytest plugins from PyPI') + parser.add_option('-f', '--filename', default=filename, help='output filename [default: %default]') + parser.add_option('-u', '--url', default=url, help='url of PyPI server to obtain data from [default: %default]') + (options, _) = parser.parse_args(argv[1:]) + + client = xmlrpclib.ServerProxy(options.url) + generate_plugins_index(client, options.filename) + + print + print '%s Updated.' % options.filename + return 0 + +#=================================================================================================== +# main +#=================================================================================================== +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff -Nru pytest-2.4.2/doc/en/plugins_index/plugins_index.txt pytest-2.5.1/doc/en/plugins_index/plugins_index.txt --- pytest-2.4.2/doc/en/plugins_index/plugins_index.txt 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/plugins_index/plugins_index.txt 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,64 @@ +.. _plugins_index: + +List of Third-Party Plugins +=========================== + +========================================================================================== ==================================================================================== ========= ====================================================================================================== ====================================================================================================== ============================================================================================================================================= + Name Author Downloads Python 2.7 Python 3.3 Summary +========================================================================================== ==================================================================================== ========= ====================================================================================================== ====================================================================================================== ============================================================================================================================================= + `pytest-bdd-0.6.7 `_ `Oleg Pidsadnyi `_ 1640 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-0.6.7?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-0.6.7?py=py33&pytest=2.5.0 BDD for pytest + `pytest-bdd-splinter-0.5.96 `_ `Oleg Pidsadnyi `_ 3463 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-splinter-0.5.96?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-splinter-0.5.96?py=py33&pytest=2.5.0 Splinter subplugin for Pytest BDD plugin + `pytest-bench-0.2.5 `_ `Concordus Applications `_ 1588 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-0.2.5?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-0.2.5?py=py33&pytest=2.5.0 Benchmark utility that plugs into pytest. + `pytest-blockage-0.1 `_ `UNKNOWN `_ 110 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-0.1?py=py33&pytest=2.5.0 Disable network requests during a test run. + `pytest-browsermob-proxy-0.1 `_ `Dave Hunt `_ 61 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-0.1?py=py33&pytest=2.5.0 BrowserMob proxy plugin for py.test. + `pytest-bugzilla-0.2 `_ `Noufal Ibrahim `_ 105 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-0.2?py=py33&pytest=2.5.0 py.test bugzilla integration plugin + `pytest-cache-1.0 `_ `Holger Krekel `_ 5690 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-1.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-1.0?py=py33&pytest=2.5.0 pytest plugin with mechanisms for caching across test runs + `pytest-capturelog-0.7 `_ `Meme Dough `_ 1615 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-0.7?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-0.7?py=py33&pytest=2.5.0 py.test plugin to capture log messages + `pytest-codecheckers-0.2 `_ `Ronny Pfannschmidt `_ 408 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-0.2?py=py33&pytest=2.5.0 pytest plugin to add source code sanity checks (pep8 and friends) + `pytest-contextfixture-0.1.1 `_ `Andreas Pelme `_ 101 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-0.1.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-0.1.1?py=py33&pytest=2.5.0 Define pytest fixtures as context managers. + `pytest-couchdbkit-0.5.1 `_ `RonnyPfannschmidt `_ 215 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-0.5.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-0.5.1?py=py33&pytest=2.5.0 py.test extension for per-test couchdb databases using couchdbkit + `pytest-cov-1.6 `_ `Meme Dough `_ 23787 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-1.6?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-1.6?py=py33&pytest=2.5.0 py.test plugin for coverage reporting with support for both centralised and distributed testing, including subprocesses and multiprocessing + `pytest-dbfixtures-0.4.0 `_ `Clearcode - The A Room `_ 6332 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-0.4.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-0.4.0?py=py33&pytest=2.5.0 dbfixtures plugin for py.test. + `pytest-django-2.4 `_ `Andreas Pelme `_ 4935 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-2.4?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-2.4?py=py33&pytest=2.5.0 A Django plugin for py.test. + `pytest-django-lite-0.1.0 `_ `David Cramer `_ 1075 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-0.1.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-0.1.0?py=py33&pytest=2.5.0 The bare minimum to integrate py.test with Django. + `pytest-figleaf-1.0 `_ `holger krekel `_ 59 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-1.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-1.0?py=py33&pytest=2.5.0 py.test figleaf coverage plugin + `pytest-flakes-0.2 `_ `Florian Schulze, Holger Krekel and Ronny Pfannschmidt `_ 1203 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-0.2?py=py33&pytest=2.5.0 pytest plugin to check source code with pyflakes + `pytest-greendots-0.2 `_ `UNKNOWN `_ 149 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-0.2?py=py33&pytest=2.5.0 Green progress dots + `pytest-growl-0.1 `_ `Anthony Long `_ 65 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-0.1?py=py33&pytest=2.5.0 Growl notifications for pytest results. + `pytest-incremental-0.3.0 `_ `Eduardo Naufel Schettino `_ 192 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-0.3.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-0.3.0?py=py33&pytest=2.5.0 an incremental test runner (pytest plugin) + `pytest-instafail-0.1.1 `_ `Janne Vanhala `_ 431 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-0.1.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-0.1.1?py=py33&pytest=2.5.0 py.test plugin to show failures instantly + `pytest-ipdb-0.1-prerelease `_ `Matthew de Verteuil `_ 99 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-0.1-prerelease?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-0.1-prerelease?py=py33&pytest=2.5.0 A py.test plug-in to enable drop to ipdb debugger on test failure. + `pytest-jira-0.01 `_ `James Laska `_ 94 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-0.01?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-0.01?py=py33&pytest=2.5.0 py.test JIRA integration plugin, using markers + `pytest-konira-0.2 `_ `Alfredo Deza `_ 99 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-0.2?py=py33&pytest=2.5.0 Run Konira DSL tests with py.test + `pytest-localserver-0.3.2 `_ `Sebastian Rahlf `_ 470 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-0.3.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-0.3.2?py=py33&pytest=2.5.0 py.test plugin to test server connections locally. + `pytest-marker-bugzilla-0.06 `_ `Eric Sammons `_ 205 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-0.06?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-0.06?py=py33&pytest=2.5.0 py.test bugzilla integration plugin, using markers + `pytest-markfiltration-0.8 `_ `adam goucher `_ 269 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-0.8?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-0.8?py=py33&pytest=2.5.0 UNKNOWN + `pytest-marks-0.4 `_ `adam goucher `_ 241 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-0.4?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-0.4?py=py33&pytest=2.5.0 UNKNOWN + `pytest-monkeyplus-1.1.0 `_ `Virgil Dupras `_ 132 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-1.1.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-1.1.0?py=py33&pytest=2.5.0 pytest's monkeypatch subclass with extra functionalities + `pytest-mozwebqa-1.1.1 `_ `Dave Hunt `_ 1087 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-1.1.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-1.1.1?py=py33&pytest=2.5.0 Mozilla WebQA plugin for py.test. + `pytest-oerp-0.2.0 `_ `Leonardo Santagada `_ 158 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-0.2.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-0.2.0?py=py33&pytest=2.5.0 pytest plugin to test OpenERP modules + `pytest-osxnotify-0.1.4 `_ `Daniel Bader `_ 200 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-0.1.4?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-0.1.4?py=py33&pytest=2.5.0 OS X notifications for py.test results. + `pytest-paste-config-0.1 `_ `UNKNOWN `_ 169 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-0.1?py=py33&pytest=2.5.0 Allow setting the path to a paste config file + `pytest-pep8-1.0.5 `_ `Holger Krekel and Ronny Pfannschmidt `_ 5971 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-1.0.5?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-1.0.5?py=py33&pytest=2.5.0 pytest plugin to check PEP8 requirements + `pytest-poo-0.2 `_ `Andreas Pelme `_ 116 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-0.2?py=py33&pytest=2.5.0 Visualize your crappy tests + `pytest-pydev-0.1 `_ `Sebastian Rahlf `_ 107 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-0.1?py=py33&pytest=2.5.0 py.test plugin to connect to a remote debug server with PyDev or PyCharm. + `pytest-qt-1.0.2 `_ `Bruno Oliveira `_ 140 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-1.0.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-1.0.2?py=py33&pytest=2.5.0 pytest plugin that adds fixtures for testing Qt (PyQt and PySide) applications. + `pytest-quickcheck-0.8 `_ `Tetsuya Morimoto `_ 380 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-0.8?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-0.8?py=py33&pytest=2.5.0 pytest plugin to generate random data inspired by QuickCheck + `pytest-rage-0.1 `_ `Leonardo Santagada `_ 64 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-0.1?py=py33&pytest=2.5.0 pytest plugin to implement PEP712 + `pytest-random-0.02 `_ `Leah Klearman `_ 125 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-0.02?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-0.02?py=py33&pytest=2.5.0 py.test plugin to randomize tests + `pytest-rerunfailures-0.03 `_ `Leah Klearman `_ 153 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-0.03?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-0.03?py=py33&pytest=2.5.0 py.test plugin to re-run tests to eliminate flakey failures + `pytest-runfailed-0.3 `_ `Dimitri Merejkowsky `_ 96 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-0.3?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-0.3?py=py33&pytest=2.5.0 implement a --failed option for pytest + `pytest-runner-2.0 `_ `Jason R. Coombs `_ 5726 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-2.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-2.0?py=py33&pytest=2.5.0 UNKNOWN + `pytest-sugar-0.2.2 `_ `Teemu, Janne Vanhala `_ 374 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-0.2.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-0.2.2?py=py33&pytest=2.5.0 py.test plugin that adds instafail, ETA and neat graphics + `pytest-timeout-0.3 `_ `Floris Bruynooghe `_ 4514 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-0.3?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-0.3?py=py33&pytest=2.5.0 pytest plugin to abort tests after a timeout + `pytest-twisted-1.4 `_ `Ralf Schmitt `_ 257 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-1.4?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-1.4?py=py33&pytest=2.5.0 A twisted plugin for py.test. + `pytest-xdist-1.9 `_ `holger krekel and contributors `_ 8103 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-1.9?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-1.9?py=py33&pytest=2.5.0 py.test xdist plugin for distributed testing and loop-on-failing modes + `pytest-xprocess-0.8 `_ `Holger Krekel `_ 108 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-0.8?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-0.8?py=py33&pytest=2.5.0 pytest plugin to manage external processes across test runs + `pytest-yamlwsgi-0.6 `_ `Ali Afshar `_ 210 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-0.6?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-0.6?py=py33&pytest=2.5.0 Run tests against wsgi apps defined in yaml + `pytest-zap-0.1 `_ `Dave Hunt `_ 69 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-0.1?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-0.1?py=py33&pytest=2.5.0 OWASP ZAP plugin for py.test. + +========================================================================================== ==================================================================================== ========= ====================================================================================================== ====================================================================================================== ============================================================================================================================================= + +*(Downloads are given from last month only)* + +*(Updated on 2013-12-12)* diff -Nru pytest-2.4.2/doc/en/plugins_index/test_plugins_index.expected.txt pytest-2.5.1/doc/en/plugins_index/test_plugins_index.expected.txt --- pytest-2.4.2/doc/en/plugins_index/test_plugins_index.expected.txt 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/plugins_index/test_plugins_index.expected.txt 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,16 @@ +.. _plugins_index: + +List of Third-Party Plugins +=========================== + +============================================ ============================= ========= ============================================================================================= ============================================================================================= =================== + Name Author Downloads Python 2.7 Python 3.3 Summary +============================================ ============================= ========= ============================================================================================= ============================================================================================= =================== + `pytest-plugin1-1.0 `_ `someone `_ 4 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-plugin1-1.0?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-plugin1-1.0?py=py33&pytest=2.5.0 some plugin + `pytest-plugin2-1.2 `_ `other `_ 40 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-plugin2-1.2?py=py27&pytest=2.5.0 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-plugin2-1.2?py=py33&pytest=2.5.0 some other plugin + +============================================ ============================= ========= ============================================================================================= ============================================================================================= =================== + +*(Downloads are given from last month only)* + +*(Updated on 2013-10-20)* diff -Nru pytest-2.4.2/doc/en/plugins_index/test_plugins_index.py pytest-2.5.1/doc/en/plugins_index/test_plugins_index.py --- pytest-2.4.2/doc/en/plugins_index/test_plugins_index.py 1970-01-01 00:00:00.000000000 +0000 +++ pytest-2.5.1/doc/en/plugins_index/test_plugins_index.py 2013-12-17 08:00:02.000000000 +0000 @@ -0,0 +1,91 @@ +import os +import xmlrpclib + +import pytest + + +#=================================================================================================== +# test_plugins_index +#=================================================================================================== + +@pytest.mark.xfail(reason="issue405 fails, not py33 ready, not a core pytest test") +def test_plugins_index(tmpdir, monkeypatch): + ''' + Blackbox testing for plugins_index script. Calls main() generating a file and compares produced + output to expected. + + .. note:: if the test fails, a file named `test_plugins_index.obtained` will be generated in + the same directory as this test file. Ensure the contents are correct and overwrite + the global `expected_output` with the new contents. + ''' + import plugins_index + + # dummy interface to xmlrpclib.ServerProxy + class DummyProxy(object): + + expected_url = 'http://dummy.pypi' + def __init__(self, url): + assert url == self.expected_url + + def search(self, query): + assert query == {'name' : 'pytest-'} + return [ + {'name': 'pytest-plugin1', 'version' : '0.8'}, + {'name': 'pytest-plugin1', 'version' : '1.0'}, + {'name': 'pytest-plugin2', 'version' : '1.2'}, + ] + + def release_data(self, package_name, version): + results = { + ('pytest-plugin1', '1.0') : { + 'package_url' : 'http://plugin1', + 'release_url' : 'http://plugin1/1.0', + 'author' : 'someone', + 'author_email' : 'someone@py.com', + 'summary' : 'some plugin', + 'downloads': {'last_day': 1, 'last_month': 4, 'last_week': 2}, + }, + + ('pytest-plugin2', '1.2') : { + 'package_url' : 'http://plugin2', + 'release_url' : 'http://plugin2/1.2', + 'author' : 'other', + 'author_email' : 'other@py.com', + 'summary' : 'some other plugin', + 'downloads': {'last_day': 10, 'last_month': 40, 'last_week': 20}, + }, + } + return results[(package_name, version)] + + monkeypatch.setattr(xmlrpclib, 'ServerProxy', DummyProxy, 'foo') + monkeypatch.setattr(plugins_index, '_get_today_as_str', lambda: '2013-10-20') + + output_file = str(tmpdir.join('output.txt')) + assert plugins_index.main(['', '-f', output_file, '-u', DummyProxy.expected_url]) == 0 + + with file(output_file, 'rU') as f: + obtained_output = f.read() + expected_output = get_expected_output() + + if obtained_output != expected_output: + obtained_file = os.path.splitext(__file__)[0] + '.obtained.txt' + with file(obtained_file, 'w') as f: + f.write(obtained_output) + + assert obtained_output == expected_output + + +def get_expected_output(): + """ + :return: string with expected rst output from the plugins_index.py script. + """ + expected_filename = os.path.join(os.path.dirname(__file__), 'test_plugins_index.expected.txt') + expected_output = open(expected_filename, 'rU').read() + return expected_output.replace('pytest=2.X.Y', 'pytest={}'.format(pytest.__version__)) + + +#=================================================================================================== +# main +#=================================================================================================== +if __name__ == '__main__': + pytest.main() diff -Nru pytest-2.4.2/doc/en/projects.txt pytest-2.5.1/doc/en/projects.txt --- pytest-2.4.2/doc/en/projects.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/projects.txt 2013-12-17 08:00:02.000000000 +0000 @@ -23,7 +23,7 @@ Here are some examples of projects using py.test (please send notes via :ref:`contact`): * `PyPy `_, Python with a JIT compiler, running over - `16000 tests `_ + `21000 tests `_ * the `MoinMoin `_ Wiki Engine * `sentry `_, realtime app-maintenance and exception tracking * `tox `_, virtualenv/Hudson integration tool diff -Nru pytest-2.4.2/doc/en/skipping.txt pytest-2.5.1/doc/en/skipping.txt --- pytest-2.4.2/doc/en/skipping.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/skipping.txt 2013-12-17 08:00:02.000000000 +0000 @@ -70,7 +70,8 @@ where you define the markers which you then consistently apply throughout your test suite. -Alternatively, the pre pytest-2.4 way to specify `condition strings `_ instead of booleans will remain fully supported in future +Alternatively, the pre pytest-2.4 way to specify :ref:`condition strings +` instead of booleans will remain fully supported in future versions of pytest. It couldn't be easily used for importing markers between test modules so it's no longer advertised as the primary method. @@ -158,7 +159,7 @@ example $ py.test -rx xfail_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 6 items xfail_demo.py xxxxxx @@ -175,7 +176,7 @@ XFAIL xfail_demo.py::test_hello6 reason: reason - ======================== 6 xfailed in 0.05 seconds ========================= + ======================== 6 xfailed in 0.04 seconds ========================= .. _`skip/xfail with parametrize`: @@ -232,7 +233,7 @@ module's ``__version__`` attribute. -.. _`string conditions`: +.. _string conditions: specifying conditions as strings versus booleans ---------------------------------------------------------- diff -Nru pytest-2.4.2/doc/en/talks.txt pytest-2.5.1/doc/en/talks.txt --- pytest-2.4.2/doc/en/talks.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/talks.txt 2013-12-17 08:00:02.000000000 +0000 @@ -10,7 +10,10 @@ .. _`tutorial1 repository`: http://bitbucket.org/hpk42/pytest-tutorial1/ .. _`pycon 2010 tutorial PDF`: http://bitbucket.org/hpk42/pytest-tutorial1/raw/tip/pytest-basic.pdf -Basic usage and funcargs: +Basic usage and fixtures: + +- `pytest feature and release highlights (GERMAN, October 2013) + `_ - `pytest introduction from Brian Okken (January 2013) `_ diff -Nru pytest-2.4.2/doc/en/tmpdir.txt pytest-2.5.1/doc/en/tmpdir.txt --- pytest-2.4.2/doc/en/tmpdir.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/tmpdir.txt 2013-12-17 08:00:02.000000000 +0000 @@ -29,7 +29,7 @@ $ py.test test_tmpdir.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 1 items test_tmpdir.py F @@ -37,7 +37,7 @@ ================================= FAILURES ================================= _____________________________ test_create_file _____________________________ - tmpdir = local('/tmp/pytest-187/test_create_file0') + tmpdir = local('/tmp/pytest-39/test_create_file0') def test_create_file(tmpdir): p = tmpdir.mkdir("sub").join("hello.txt") diff -Nru pytest-2.4.2/doc/en/unittest.txt pytest-2.5.1/doc/en/unittest.txt --- pytest-2.4.2/doc/en/unittest.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/unittest.txt 2013-12-17 08:00:02.000000000 +0000 @@ -88,7 +88,7 @@ $ py.test test_unittest_db.py =========================== test session starts ============================ - platform linux2 -- Python 2.7.3 -- pytest-2.4.2 + platform linux2 -- Python 2.7.3 -- pytest-2.5.1 collected 2 items test_unittest_db.py FF @@ -101,7 +101,7 @@ def test_method1(self): assert hasattr(self, "db") > assert 0, self.db # fail for demo purposes - E AssertionError: + E AssertionError: test_unittest_db.py:9: AssertionError ___________________________ MyTest.test_method2 ____________________________ @@ -110,10 +110,10 @@ def test_method2(self): > assert 0, self.db # fail for demo purposes - E AssertionError: + E AssertionError: test_unittest_db.py:12: AssertionError - ========================= 2 failed in 0.02 seconds ========================= + ========================= 2 failed in 0.01 seconds ========================= This default pytest traceback shows that the two test methods share the same ``self.db`` instance which was our intention @@ -160,7 +160,7 @@ $ py.test -q test_unittest_cleandir.py . - 1 passed in 0.02 seconds + 1 passed in 0.01 seconds ... gives us one passed test because the ``initdir`` fixture function was executed ahead of the ``test_method``. diff -Nru pytest-2.4.2/doc/en/yieldfixture.txt pytest-2.5.1/doc/en/yieldfixture.txt --- pytest-2.4.2/doc/en/yieldfixture.txt 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/doc/en/yieldfixture.txt 2013-12-17 08:00:02.000000000 +0000 @@ -52,7 +52,7 @@ test called .teardown after yield - 1 passed in 0.01 seconds + 1 passed in 0.00 seconds We can also seemlessly use the new syntax with ``with`` statements. Let's simplify the above ``passwd`` fixture:: diff -Nru pytest-2.4.2/pytest.egg-info/PKG-INFO pytest-2.5.1/pytest.egg-info/PKG-INFO --- pytest-2.4.2/pytest.egg-info/PKG-INFO 2013-10-04 12:12:41.000000000 +0000 +++ pytest-2.5.1/pytest.egg-info/PKG-INFO 2013-12-17 08:00:02.000000000 +0000 @@ -1,14 +1,18 @@ Metadata-Version: 1.1 Name: pytest -Version: 2.4.2 +Version: 2.5.1 Summary: py.test: simple powerful testing with Python Home-page: http://pytest.org Author: Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others Author-email: holger at merlinux.eu License: MIT license Description: + Documentation: http://pytest.org/latest/ + Changelog: http://pytest.org/latest/changelog.html + Issues: https://bitbucket.org/hpk42/pytest/issues?status=open + The ``py.test`` testing tool makes it easy to write small tests, yet scales to support complex functional testing. It provides @@ -71,8 +75,6 @@ Classifier: Topic :: Utilities Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 2.4 -Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.0 diff -Nru pytest-2.4.2/pytest.egg-info/SOURCES.txt pytest-2.5.1/pytest.egg-info/SOURCES.txt --- pytest-2.4.2/pytest.egg-info/SOURCES.txt 2013-10-04 12:12:41.000000000 +0000 +++ pytest-2.5.1/pytest.egg-info/SOURCES.txt 2013-12-17 08:00:02.000000000 +0000 @@ -83,11 +83,18 @@ doc/en/xdist.txt doc/en/xunit_setup.txt doc/en/yieldfixture.txt -doc/en/_static/sphinxdoc.css -doc/en/_templates/indexsidebar.html +doc/en/_templates/globaltoc.html doc/en/_templates/layout.html -doc/en/_templates/localtoc.html -doc/en/_templates/searchbox.html +doc/en/_templates/links.html +doc/en/_templates/sidebarintro.html +doc/en/_themes/.gitignore +doc/en/_themes/LICENSE +doc/en/_themes/README +doc/en/_themes/flask_theme_support.py +doc/en/_themes/flask/layout.html +doc/en/_themes/flask/relations.html +doc/en/_themes/flask/theme.conf +doc/en/_themes/flask/static/flasky.css_t doc/en/announce/index.txt doc/en/announce/release-2.0.0.txt doc/en/announce/release-2.0.1.txt @@ -110,6 +117,8 @@ doc/en/announce/release-2.4.0.txt doc/en/announce/release-2.4.1.txt doc/en/announce/release-2.4.2.txt +doc/en/announce/release-2.5.0.txt +doc/en/announce/release-2.5.1.txt doc/en/example/attic.txt doc/en/example/conftest.py doc/en/example/index.txt @@ -145,6 +154,10 @@ doc/en/img/keleshev.png doc/en/img/pylib.png doc/en/img/theuni.png +doc/en/plugins_index/plugins_index.py +doc/en/plugins_index/plugins_index.txt +doc/en/plugins_index/test_plugins_index.expected.txt +doc/en/plugins_index/test_plugins_index.py doc/en/test/attic.txt doc/en/test/config.html doc/en/test/dist.html @@ -280,8 +293,6 @@ testing/test_conftest.py testing/test_core.py testing/test_doctest.py -testing/test_fixture_finalizer.py -testing/test_fixture_scope.py testing/test_genscript.py testing/test_helpconfig.py testing/test_junitxml.py diff -Nru pytest-2.4.2/pytest.egg-info/requires.txt pytest-2.5.1/pytest.egg-info/requires.txt --- pytest-2.4.2/pytest.egg-info/requires.txt 2013-10-04 12:12:41.000000000 +0000 +++ pytest-2.5.1/pytest.egg-info/requires.txt 2013-12-17 08:00:02.000000000 +0000 @@ -1 +1 @@ -py>=1.4.17 \ No newline at end of file +py>=1.4.19 \ No newline at end of file diff -Nru pytest-2.4.2/setup.py pytest-2.5.1/setup.py --- pytest-2.4.2/setup.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/setup.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,9 +1,23 @@ import os, sys from setuptools import setup, Command +classifiers=['Development Status :: 6 - Mature', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: MacOS :: MacOS X', + 'Topic :: Software Development :: Testing', + 'Topic :: Software Development :: Libraries', + 'Topic :: Utilities', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3'] + [ + ("Programming Language :: Python :: %s" % x) for x in + "2.6 2.7 3.0 3.1 3.2 3.3".split()] + long_description = open("README.rst").read() def main(): - install_requires = ["py>=1.4.17"] + install_requires = ["py>=1.4.19"] if sys.version_info < (2,7): install_requires.append("argparse") if sys.platform == "win32": @@ -13,29 +27,17 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.4.2', + version='2.5.1', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others', author_email='holger at merlinux.eu', entry_points= make_entry_points(), + classifiers=classifiers, cmdclass = {'test': PyTest}, # the following should be enabled for release install_requires=install_requires, - classifiers=['Development Status :: 6 - Mature', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: MacOS :: MacOS X', - 'Topic :: Software Development :: Testing', - 'Topic :: Software Development :: Libraries', - 'Topic :: Utilities', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3'] + [ - ("Programming Language :: Python :: %s" % x) for x in - "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split()], packages=['_pytest', '_pytest.assertion'], py_modules=['pytest'], zip_safe=False, diff -Nru pytest-2.4.2/testing/acceptance_test.py pytest-2.5.1/testing/acceptance_test.py --- pytest-2.4.2/testing/acceptance_test.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/acceptance_test.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,4 +1,4 @@ -import sys, py, pytest +import py, pytest class TestGeneralUsage: def test_config_error(self, testdir): @@ -14,7 +14,7 @@ ]) def test_root_conftest_syntax_error(self, testdir): - p = testdir.makepyfile(conftest="raise SyntaxError\n") + testdir.makepyfile(conftest="raise SyntaxError\n") result = testdir.runpytest() result.stderr.fnmatch_lines(["*raise SyntaxError*"]) assert result.ret != 0 @@ -67,7 +67,7 @@ result = testdir.runpytest("-s", "asd") assert result.ret == 4 # EXIT_USAGEERROR result.stderr.fnmatch_lines(["ERROR: file not found*asd"]) - s = result.stdout.fnmatch_lines([ + result.stdout.fnmatch_lines([ "*---configure", "*---unconfigure", ]) @@ -307,6 +307,24 @@ '*ERROR*', ]) assert result.ret == 4 # usage error only if item not found + + def test_namespace_import_doesnt_confuse_import_hook(self, testdir): + # Ref #383. Python 3.3's namespace package messed with our import hooks + # Importing a module that didn't exist, even if the ImportError was + # gracefully handled, would make our test crash. + testdir.mkdir('not_a_package') + p = testdir.makepyfile(""" + try: + from not_a_package import doesnt_exist + except ImportError: + # We handle the import error gracefully here + pass + + def test_whatever(): + pass + """) + res = testdir.runpytest(p.basename) + assert res.ret == 0 class TestInvocationVariants: @@ -539,7 +557,6 @@ assert result.ret == 0 for x in "123": for y in 'call',: #'setup', 'call', 'teardown': - l = [] for line in result.stdout.lines: if ("test_%s" % x) in line and y in line: break diff -Nru pytest-2.4.2/testing/conftest.py pytest-2.5.1/testing/conftest.py --- pytest-2.4.2/testing/conftest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/conftest.py 2013-12-17 08:00:02.000000000 +0000 @@ -12,10 +12,7 @@ help=("run FD checks if lsof is available")) def pytest_configure(config): - config.addinivalue_line("markers", - "multi(arg=[value1,value2, ...]): call the test function " - "multiple times with arg=value1, then with arg=value2, ... " - ) + config._basedir = py.path.local() if config.getvalue("lsof"): try: out = py.process.cmdexec("lsof -p %d" % pid) @@ -46,30 +43,13 @@ config._numfiles = len(lines2) raise AssertionError("\n".join(error)) -@pytest.mark.tryfirst # XXX rather do item.addfinalizer -def pytest_runtest_setup(item): - item._oldir = py.path.local() - def pytest_runtest_teardown(item, __multicall__): - item._oldir.chdir() + item.config._basedir.chdir() if hasattr(item.config, '_numfiles'): x = __multicall__.execute() check_open_files(item.config) return x -def pytest_generate_tests(metafunc): - multi = getattr(metafunc.function, 'multi', None) - if multi is not None: - assert len(multi.kwargs) == 1 - for name, l in multi.kwargs.items(): - for val in l: - metafunc.addcall(funcargs={name: val}) - elif 'anypython' in metafunc.fixturenames: - for name in ('python2.5', 'python2.6', - 'python2.7', 'python3.2', "python3.3", - 'pypy', 'jython'): - metafunc.addcall(id=name, param=name) - # XXX copied from execnet's conftest.py - needs to be merged winpymap = { 'python2.7': r'C:\Python27\python.exe', @@ -100,7 +80,10 @@ cache[name] = executable return executable -def pytest_funcarg__anypython(request): +@pytest.fixture(params=['python2.5', 'python2.6', + 'python2.7', 'python3.2', "python3.3", + 'pypy', 'jython']) +def anypython(request): name = request.param executable = getexecutable(name) if executable is None: diff -Nru pytest-2.4.2/testing/python/collect.py pytest-2.5.1/testing/python/collect.py --- pytest-2.4.2/testing/python/collect.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/python/collect.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,4 @@ -import pytest, py, sys -from _pytest import python as funcargs -from _pytest.python import FixtureLookupError +import pytest, py class TestModule: def test_failing_import(self, testdir): @@ -32,7 +30,7 @@ def test_module_considers_pluginmanager_at_import(self, testdir): modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") - pytest.raises(ImportError, "modcol.obj") + pytest.raises(ImportError, lambda: modcol.obj) class TestClass: def test_class_with_init_skip_collect(self, testdir): @@ -289,22 +287,10 @@ pass f1 = pytest.Function(name="name", parent=session, config=config, args=(1,), callobj=func1) + assert f1 == f1 f2 = pytest.Function(name="name",config=config, - args=(1,), callobj=func2, parent=session) - assert not f1 == f2 + callobj=func2, parent=session) assert f1 != f2 - f3 = pytest.Function(name="name", parent=session, config=config, - args=(1,2), callobj=func2) - assert not f3 == f2 - assert f3 != f2 - - assert not f3 == f1 - assert f3 != f1 - - f1_b = pytest.Function(name="name", parent=session, config=config, - args=(1,), callobj=func1) - assert f1 == f1_b - assert not f1 != f1_b def test_issue197_parametrize_emptyset(self, testdir): testdir.makepyfile(""" @@ -336,7 +322,7 @@ def test_function(arg): assert arg.__class__.__name__ == "A" """) - reprec = testdir.inline_run() + reprec = testdir.inline_run("--fulltrace") reprec.assertoutcome(passed=1) def test_parametrize_with_non_hashable_values(self, testdir): @@ -357,6 +343,68 @@ rec = testdir.inline_run() rec.assertoutcome(passed=2) + + def test_parametrize_with_non_hashable_values_indirect(self, testdir): + """Test parametrization with non-hashable values with indirect parametrization.""" + testdir.makepyfile(""" + archival_mapping = { + '1.0': {'tag': '1.0'}, + '1.2.2a1': {'tag': 'release-1.2.2a1'}, + } + + import pytest + + @pytest.fixture + def key(request): + return request.param + + @pytest.fixture + def value(request): + return request.param + + @pytest.mark.parametrize('key value'.split(), + archival_mapping.items(), indirect=True) + def test_archival_to_version(key, value): + assert key in archival_mapping + assert value == archival_mapping[key] + """) + rec = testdir.inline_run() + rec.assertoutcome(passed=2) + + + def test_parametrize_overrides_fixture(self, testdir): + """Test parametrization when parameter overrides existing fixture with same name.""" + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def value(): + return 'value' + + @pytest.mark.parametrize('value', + ['overrided']) + def test_overrided_via_param(value): + assert value == 'overrided' + """) + rec = testdir.inline_run() + rec.assertoutcome(passed=1) + + + def test_parametrize_with_mark(selfself, testdir): + items = testdir.getitems(""" + import pytest + @pytest.mark.foo + @pytest.mark.parametrize('arg', [ + 1, + pytest.mark.bar(pytest.mark.baz(2)) + ]) + def test_function(arg): + pass + """) + keywords = [item.keywords for item in items] + assert 'foo' in keywords[0] and 'bar' not in keywords[0] and 'baz' not in keywords[0] + assert 'foo' in keywords[1] and 'bar' in keywords[1] and 'baz' in keywords[1] + def test_function_equality_with_callspec(self, testdir, tmpdir): items = testdir.getitems(""" import pytest @@ -606,7 +654,7 @@ return MyFunction(name, parent=collector) """) item = testdir.getitem("def test_func(): pass") - runner = item.config.pluginmanager.getplugin("runner") + item.config.pluginmanager.getplugin("runner") assert item.location == ("ABCDE", 42, "custom") def test_func_reportinfo(self, testdir): @@ -696,7 +744,7 @@ [pytest] python_functions=_test """) - p = testdir.makepyfile(""" + testdir.makepyfile(""" def _test_underscore(): pass """) diff -Nru pytest-2.4.2/testing/python/fixture.py pytest-2.5.1/testing/python/fixture.py --- pytest-2.4.2/testing/python/fixture.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/python/fixture.py 2013-12-17 08:00:02.000000000 +0000 @@ -2,7 +2,7 @@ from _pytest import python as funcargs from _pytest.python import FixtureLookupError from _pytest.pytester import get_public_names - +from textwrap import dedent def test_getfuncargnames(): def f(): pass @@ -247,7 +247,7 @@ assert result.ret == 0 def test_funcarg_lookup_error(self, testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_lookup_error(unknown): pass """) @@ -307,7 +307,7 @@ def pytest_funcarg__something(request): return 1 """) - item = testdir.makepyfile(""" + testdir.makepyfile(""" def pytest_funcarg__something(request): return request.getfuncargvalue("something") + 1 def test_func(something): @@ -473,7 +473,7 @@ assert l == ["module", "function", "class", "function", "method", "function"] """) - reprec = testdir.inline_run() + reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=3) def test_fixtures_sub_subdir_normalize_sep(self, testdir): @@ -634,13 +634,13 @@ l.append("setup") def teardown(val): l.append("teardown") - ret1 = req1.cached_setup(setup, teardown, scope="function") + req1.cached_setup(setup, teardown, scope="function") assert l == ['setup'] # artificial call of finalizer setupstate = req1._pyfuncitem.session._setupstate setupstate._callfinalizers(item1) assert l == ["setup", "teardown"] - ret2 = req1.cached_setup(setup, teardown, scope="function") + req1.cached_setup(setup, teardown, scope="function") assert l == ["setup", "teardown", "setup"] setupstate._callfinalizers(item1) assert l == ["setup", "teardown", "setup", "teardown"] @@ -914,6 +914,34 @@ reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_fixture_parametrized_with_iterator(self, testdir): + testdir.makepyfile(""" + import pytest + + l = [] + def f(): + yield 1 + yield 2 + dec = pytest.fixture(scope="module", params=f()) + + @dec + def arg(request): + return request.param + @dec + def arg2(request): + return request.param + + def test_1(arg): + l.append(arg) + def test_2(arg2): + l.append(arg2*10) + """) + reprec = testdir.inline_run("-v") + reprec.assertoutcome(passed=4) + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + assert l == [1,2, 10,20] + + class TestFixtureManagerParseFactories: def pytest_funcarg__testdir(self, request): testdir = request.getfuncargvalue("testdir") @@ -1315,6 +1343,7 @@ l.append("step2-%d" % item) def test_finish(): + print (l) assert l == ["setup-1", "step1-1", "step2-1", "teardown-1", "setup-2", "step1-2", "step2-2", "teardown-2",] """) @@ -1461,7 +1490,7 @@ 'request.getfuncargvalue("arg")', 'request.cached_setup(lambda: None, scope="function")', ], ids=["getfuncargvalue", "cached_setup"]) - def test_scope_mismatch(self, testdir, method): + def test_scope_mismatch_various(self, testdir, method): testdir.makeconftest(""" import pytest finalized = [] @@ -1609,7 +1638,7 @@ """) def test_class_ordering(self, testdir): - p = testdir.makeconftest(""" + testdir.makeconftest(""" import pytest l = [] @@ -1683,23 +1712,22 @@ l.append("test3") def test_4(modarg, arg): l.append("test4") - def test_5(): - assert len(l) == 12 * 3 - expected = [ - 'create:1', 'test1', 'fin:1', 'create:2', 'test1', - 'fin:2', 'create:mod1', 'test2', 'create:1', 'test3', - 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1', - 'test4', 'fin:1', 'create:2', 'test4', 'fin:2', - 'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3', - 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1', - 'test4', 'fin:1', 'create:2', 'test4', 'fin:2', - 'fin:mod2'] - import pprint - pprint.pprint(list(zip(l, expected))) - assert l == expected """) reprec = testdir.inline_run("-v") - reprec.assertoutcome(passed=12+1) + reprec.assertoutcome(passed=12) + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + expected = [ + 'create:1', 'test1', 'fin:1', 'create:2', 'test1', + 'fin:2', 'create:mod1', 'test2', 'create:1', 'test3', + 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1', + 'test4', 'fin:1', 'create:2', 'test4', 'fin:2', + 'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3', + 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1', + 'test4', 'fin:1', 'create:2', 'test4', 'fin:2', + 'fin:mod2'] + import pprint + pprint.pprint(list(zip(l, expected))) + assert l == expected def test_parametrized_fixture_teardown_order(self, testdir): testdir.makepyfile(""" @@ -1738,35 +1766,100 @@ """) assert "error" not in result.stdout.str() + def test_fixture_finalizer(self, testdir): + testdir.makeconftest(""" + import pytest + import sys + + @pytest.fixture + def browser(request): + + def finalize(): + sys.stdout.write('Finalized') + request.addfinalizer(finalize) + return {} + """) + b = testdir.mkdir("subdir") + b.join("test_overriden_fixture_finalizer.py").write(dedent(""" + import pytest + @pytest.fixture + def browser(browser): + browser['visited'] = True + return browser + + def test_browser(browser): + assert browser['visited'] is True + """)) + reprec = testdir.runpytest("-s") + for test in ['test_browser']: + reprec.stdout.fnmatch_lines('*Finalized*') + + def test_class_scope_with_normal_tests(self, testdir): + testpath = testdir.makepyfile(""" + import pytest + + class Box: + value = 0 + + @pytest.fixture(scope='class') + def a(request): + Box.value += 1 + return Box.value + + def test_a(a): + assert a == 1 + + class Test1: + def test_b(self, a): + assert a == 2 + + class Test2: + def test_c(self, a): + assert a == 3""") + reprec = testdir.inline_run(testpath) + for test in ['test_a', 'test_b', 'test_c']: + assert reprec.matchreport(test).passed + + def test_request_is_clean(self, testdir): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.fixture(params=[1, 2]) + def fix(request): + request.addfinalizer(lambda: l.append(request.param)) + def test_fix(fix): + pass + """) + reprec = testdir.inline_run("-s") + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + assert l == [1,2] + def test_parametrize_separated_lifecycle(self, testdir): testdir.makepyfile(""" import pytest + l = [] @pytest.fixture(scope="module", params=[1, 2]) def arg(request): - request.config.l = l # to access from outer x = request.param request.addfinalizer(lambda: l.append("fin%s" % x)) return request.param - - l = [] def test_1(arg): l.append(arg) def test_2(arg): l.append(arg) """) - reprec = testdir.inline_run("-v") + reprec = testdir.inline_run("-vs") reprec.assertoutcome(passed=4) - l = reprec.getcalls("pytest_configure")[0].config.l + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l import pprint pprint.pprint(l) - assert len(l) == 6 + #assert len(l) == 6 assert l[0] == l[1] == 1 assert l[2] == "fin1" assert l[3] == l[4] == 2 assert l[5] == "fin2" - def test_parametrize_function_scoped_finalizers_called(self, testdir): testdir.makepyfile(""" import pytest @@ -1789,6 +1882,69 @@ reprec = testdir.inline_run("-v") reprec.assertoutcome(passed=5) + + @pytest.mark.issue246 + @pytest.mark.parametrize("scope", ["session", "function", "module"]) + def test_finalizer_order_on_parametrization(self, scope, testdir): + testdir.makepyfile(""" + import pytest + l = [] + + @pytest.fixture(scope=%(scope)r, params=["1"]) + def fix1(request): + return request.param + + @pytest.fixture(scope=%(scope)r) + def fix2(request, base): + def cleanup_fix2(): + assert not l, "base should not have been finalized" + request.addfinalizer(cleanup_fix2) + + @pytest.fixture(scope=%(scope)r) + def base(request, fix1): + def cleanup_base(): + l.append("fin_base") + print ("finalizing base") + request.addfinalizer(cleanup_base) + + def test_begin(): + pass + def test_baz(base, fix2): + pass + def test_other(): + pass + """ % {"scope": scope}) + reprec = testdir.inline_run("-lvs") + reprec.assertoutcome(passed=3) + + @pytest.mark.issue396 + def test_class_scope_parametrization_ordering(self, testdir): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.fixture(params=["John", "Doe"], scope="class") + def human(request): + request.addfinalizer(lambda: l.append("fin %s" % request.param)) + return request.param + + class TestGreetings: + def test_hello(self, human): + l.append("test_hello") + + class TestMetrics: + def test_name(self, human): + l.append("test_name") + + def test_population(self, human): + l.append("test_population") + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=6) + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l + assert l == ["test_hello", "fin John", "test_hello", "fin Doe", + "test_name", "test_population", "fin John", + "test_name", "test_population", "fin Doe"] + def test_parametrize_setup_function(self, testdir): testdir.makepyfile(""" import pytest @@ -1833,6 +1989,40 @@ reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_params_and_ids(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture(params=[object(), object()], + ids=['alpha', 'beta']) + def fix(request): + return request.param + + def test_foo(fix): + assert 1 + """) + res = testdir.runpytest('-v') + res.stdout.fnmatch_lines([ + '*test_foo*alpha*', + '*test_foo*beta*']) + + def test_params_and_ids_yieldfixture(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.yield_fixture(params=[object(), object()], + ids=['alpha', 'beta']) + def fix(request): + yield request.param + + def test_foo(fix): + assert 1 + """) + res = testdir.runpytest('-v') + res.stdout.fnmatch_lines([ + '*test_foo*alpha*', + '*test_foo*beta*']) + class TestRequestScopeAccess: pytestmark = pytest.mark.parametrize(("scope", "ok", "error"),[ diff -Nru pytest-2.4.2/testing/python/integration.py pytest-2.5.1/testing/python/integration.py --- pytest-2.4.2/testing/python/integration.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/python/integration.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,5 +1,6 @@ -import pytest, py, sys +import pytest from _pytest import runner +from _pytest import python class TestOEJSKITSpecials: def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage @@ -55,6 +56,20 @@ assert not clscol.funcargs +def test_wrapped_getfslineno(): + def func(): + pass + def wrap(f): + func.__wrapped__ = f + func.patchings = ["qwe"] + return func + @wrap + def wrapped_func(x, y, z): + pass + fs, lineno = python.getfslineno(wrapped_func) + fs2, lineno2 = python.getfslineno(wrap) + assert lineno > lineno2, "getfslineno does not unwrap correctly" + class TestMockDecoration: def test_wrapped_getfuncargnames(self): from _pytest.python import getfuncargnames @@ -118,6 +133,32 @@ """) reprec = testdir.inline_run() reprec.assertoutcome(passed=2) + calls = reprec.getcalls("pytest_runtest_logreport") + funcnames = [call.report.location[2] for call in calls + if call.report.when == "call"] + assert funcnames == ["T.test_hello", "test_someting"] + + def test_mock_sorting(self, testdir): + pytest.importorskip("mock", "1.0.1") + testdir.makepyfile(""" + import os + import mock + + @mock.patch("os.path.abspath") + def test_one(abspath): + pass + @mock.patch("os.path.abspath") + def test_two(abspath): + pass + @mock.patch("os.path.abspath") + def test_three(abspath): + pass + """) + reprec = testdir.inline_run() + calls = reprec.getreports("pytest_runtest_logreport") + calls = [x for x in calls if x.when == "call"] + names = [x.nodeid.split("::")[-1] for x in calls] + assert names == ["test_one", "test_two", "test_three"] class TestReRunTests: @@ -150,3 +191,7 @@ result.stdout.fnmatch_lines(""" *2 passed* """) + +def test_pytestconfig_is_session_scoped(): + from _pytest.python import pytestconfig + assert pytestconfig._pytestfixturefunction.scope == "session" diff -Nru pytest-2.4.2/testing/python/metafunc.py pytest-2.5.1/testing/python/metafunc.py --- pytest-2.4.2/testing/python/metafunc.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/python/metafunc.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,7 +1,6 @@ -import pytest, py, sys +import pytest, py from _pytest import python as funcargs -from _pytest.python import FixtureLookupError class TestMetafunc: def Metafunc(self, func): @@ -194,8 +193,8 @@ metafunc.parametrize('y', [2]) def pytest_funcarg__x(request): return request.param * 10 - def pytest_funcarg__y(request): - return request.param + #def pytest_funcarg__y(request): + # return request.param def test_simple(x,y): assert x in (10,20) @@ -593,6 +592,8 @@ def test_it(foo): pass + def test_it2(foo): + pass """) reprec = testdir.inline_run("--collect-only") assert not reprec.getcalls("pytest_internalerror") @@ -629,6 +630,22 @@ "*3 passed*" ]) + def test_generate_same_function_names_issue403(self, testdir): + testdir.makepyfile(""" + import pytest + + def make_tests(): + @pytest.mark.parametrize("x", range(2)) + def test_foo(x): + pass + return test_foo + + test_x = make_tests() + test_y = make_tests() + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=4) + class TestMarkersWithParametrization: pytestmark = pytest.mark.issue308 @@ -815,7 +832,7 @@ reprec.assertoutcome(passed=2, skipped=2) - @pytest.mark.xfail(reason="issue 290") + @pytest.mark.issue290 def test_parametrize_ID_generation_string_int_works(self, testdir): testdir.makepyfile(""" import pytest diff -Nru pytest-2.4.2/testing/python/raises.py pytest-2.5.1/testing/python/raises.py --- pytest-2.4.2/testing/python/raises.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/python/raises.py 2013-12-17 08:00:02.000000000 +0000 @@ -29,7 +29,7 @@ def test_raises_flip_builtin_AssertionError(self): # we replace AssertionError on python level # however c code might still raise the builtin one - from _pytest.assertion.util import BuiltinAssertionError + from _pytest.assertion.util import BuiltinAssertionError # noqa pytest.raises(AssertionError,""" raise BuiltinAssertionError """) diff -Nru pytest-2.4.2/testing/test_argcomplete.py pytest-2.5.1/testing/test_argcomplete.py --- pytest-2.4.2/testing/test_argcomplete.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_argcomplete.py 2013-12-17 08:00:02.000000000 +0000 @@ -72,7 +72,7 @@ # the following barfs with a syntax error on py2.5 # @pytest.mark.skipif("sys.version_info < (2,6)") class TestArgComplete: - @pytest.mark.skipif("sys.platform == 'win32'") + @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") @pytest.mark.skipif("sys.version_info < (2,6)") def test_compare_with_compgen(self): from _pytest._argcomplete import FastFilesCompleter @@ -81,7 +81,7 @@ for x in '/ /d /data qqq'.split(): assert equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) - @pytest.mark.skipif("sys.platform == 'win32'") + @pytest.mark.skipif("sys.platform in ('win32', 'darwin')") @pytest.mark.skipif("sys.version_info < (2,6)") def test_remove_dir_prefix(self): """this is not compatible with compgen but it is with bash itself: diff -Nru pytest-2.4.2/testing/test_assertion.py pytest-2.5.1/testing/test_assertion.py --- pytest-2.4.2/testing/test_assertion.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_assertion.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,8 +1,9 @@ +# -*- coding: utf-8 -*- import sys import py, pytest import _pytest.assertion as plugin -from _pytest.assertion import reinterpret, util +from _pytest.assertion import reinterpret needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)") @@ -176,6 +177,15 @@ expl = ' '.join(callequal('foo', 'bar')) assert 'raised in repr()' not in expl + def test_unicode(self): + left = py.builtin._totext('£€', 'utf-8') + right = py.builtin._totext('£', 'utf-8') + expl = callequal(left, right) + assert expl[0] == py.builtin._totext("'£€' == '£'", 'utf-8') + assert expl[1] == py.builtin._totext('- £€', 'utf-8') + assert expl[2] == py.builtin._totext('+ £', 'utf-8') + + def test_python25_compile_issue257(testdir): testdir.makepyfile(""" def test_rewritten(): @@ -353,7 +363,7 @@ @pytest.mark.skipif("sys.version_info < (2,5) or '__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')" ) def test_warn_missing(testdir): - p1 = testdir.makepyfile("") + testdir.makepyfile("") result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h") result.stderr.fnmatch_lines([ "*WARNING*assert statements are not executed*", @@ -376,3 +386,16 @@ result.stdout.fnmatch_lines(""" """) + +def test_AssertionError_message(testdir): + testdir.makepyfile(""" + def test_hello(): + x,y = 1,2 + assert 0, (x,y) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + *def test_hello* + *assert 0, (x,y)* + *AssertionError: (1, 2)* + """) diff -Nru pytest-2.4.2/testing/test_assertrewrite.py pytest-2.5.1/testing/test_assertrewrite.py --- pytest-2.4.2/testing/test_assertrewrite.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_assertrewrite.py 2013-12-17 08:00:02.000000000 +0000 @@ -107,13 +107,13 @@ assert f assert getmsg(f) == "assert False" def f(): - assert a_global + assert a_global # noqa assert getmsg(f, {"a_global" : False}) == "assert False" def f(): assert sys == 42 assert getmsg(f, {"sys" : sys}) == "assert sys == 42" def f(): - assert cls == 42 + assert cls == 42 # noqa class X(object): pass assert getmsg(f, {"cls" : X}) == "assert cls == 42" @@ -174,7 +174,7 @@ def test_short_circut_evaluation(self): def f(): - assert True or explode + assert True or explode # noqa getmsg(f, must_pass=True) def f(): x = 1 @@ -206,7 +206,6 @@ assert x + y assert getmsg(f) == "assert (1 + -1)" def f(): - x = range(10) assert not 5 % 4 assert getmsg(f) == "assert not (5 % 4)" @@ -243,12 +242,12 @@ g = 3 ns = {"x" : X} def f(): - assert not x.g + assert not x.g # noqa assert getmsg(f, ns) == """assert not 3 + where 3 = x.g""" def f(): - x.a = False - assert x.a + x.a = False # noqa + assert x.a # noqa assert getmsg(f, ns) == """assert x.a""" def test_comparisons(self): @@ -435,21 +434,46 @@ def test_missing(): assert not __loader__.is_package('pytest_not_there') """) - pkg = testdir.mkpydir('fun') + testdir.mkpydir('fun') result = testdir.runpytest() result.stdout.fnmatch_lines([ '* 3 passed*', ]) - @pytest.mark.skipif("sys.version_info[0] >= 3") + @pytest.mark.xfail("hasattr(sys, 'pypy_translation_info')") def test_assume_ascii(self, testdir): - content = "u'\xe2\x99\xa5'" + content = "u'\xe2\x99\xa5\x01\xfe'" testdir.tmpdir.join("test_encoding.py").write(content, "wb") res = testdir.runpytest() assert res.ret != 0 assert "SyntaxError: Non-ASCII character" in res.stdout.str() + @pytest.mark.skipif("sys.version_info[0] >= 3") + def test_detect_coding_cookie(self, testdir): + testdir.tmpdir.join("test_cookie.py").write("""# -*- coding: utf-8 -*- +u"St\xc3\xa4d" +def test_rewritten(): + assert "@py_builtins" in globals()""", "wb") + assert testdir.runpytest().ret == 0 + + @pytest.mark.skipif("sys.version_info[0] >= 3") + def test_detect_coding_cookie_second_line(self, testdir): + testdir.tmpdir.join("test_cookie.py").write("""#!/usr/bin/env python +# -*- coding: utf-8 -*- +u"St\xc3\xa4d" +def test_rewritten(): + assert "@py_builtins" in globals()""", "wb") + assert testdir.runpytest().ret == 0 + + @pytest.mark.skipif("sys.version_info[0] >= 3") + def test_detect_coding_cookie_crlf(self, testdir): + testdir.tmpdir.join("test_cookie.py").write("""#!/usr/bin/env python +# -*- coding: utf-8 -*- +u"St\xc3\xa4d" +def test_rewritten(): + assert "@py_builtins" in globals()""".replace("\n", "\r\n"), "wb") + assert testdir.runpytest().ret == 0 def test_write_pyc(self, testdir, tmpdir, monkeypatch): from _pytest.assertion.rewrite import _write_pyc @@ -469,3 +493,35 @@ raise e monkeypatch.setattr(b, "open", open) assert not _write_pyc(state, [1], source_path, pycpath) + + def test_resources_provider_for_loader(self, testdir): + """ + Attempts to load resources from a package should succeed normally, + even when the AssertionRewriteHook is used to load the modules. + + See #366 for details. + """ + pytest.importorskip("pkg_resources") + + testdir.mkpydir('testpkg') + contents = { + 'testpkg/test_pkg': """ + import pkg_resources + + import pytest + from _pytest.assertion.rewrite import AssertionRewritingHook + + def test_load_resource(): + assert isinstance(__loader__, AssertionRewritingHook) + res = pkg_resources.resource_string(__name__, 'resource.txt') + res = res.decode('ascii') + assert res == 'Load me please.' + """, + } + testdir.makepyfile(**contents) + testdir.maketxtfile(**{'testpkg/resource': "Load me please."}) + + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '* 1 passed*', + ]) diff -Nru pytest-2.4.2/testing/test_capture.py pytest-2.5.1/testing/test_capture.py --- pytest-2.4.2/testing/test_capture.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_capture.py 2013-12-17 08:00:02.000000000 +0000 @@ -32,7 +32,7 @@ assert capman._getmethod(config, sub.join("test_hello.py")) == mode @needsosdup - @pytest.mark.multi(method=['no', 'fd', 'sys']) + @pytest.mark.parametrize("method", ['no', 'fd', 'sys']) def test_capturing_basic_api(self, method): capouter = py.io.StdCaptureFD() old = sys.stdout, sys.stderr, sys.stdin @@ -81,7 +81,7 @@ capouter.reset() @pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") -@pytest.mark.multi(method=['fd', 'sys']) +@pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_unicode(testdir, method): if sys.version_info >= (3,0): obj = "'b\u00f6y'" @@ -100,7 +100,7 @@ "*1 passed*" ]) -@pytest.mark.multi(method=['fd', 'sys']) +@pytest.mark.parametrize("method", ['fd', 'sys']) def test_capturing_bytes_in_utf8_encoding(testdir, method): testdir.makepyfile(""" def test_unicode(): diff -Nru pytest-2.4.2/testing/test_collection.py pytest-2.5.1/testing/test_collection.py --- pytest-2.4.2/testing/test_collection.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_collection.py 2013-12-17 08:00:02.000000000 +0000 @@ -242,7 +242,7 @@ assert "passed" in result.stdout.str() def test_pytest_fs_collect_hooks_are_seen(self, testdir): - conf = testdir.makeconftest(""" + testdir.makeconftest(""" import pytest class MyModule(pytest.Module): pass @@ -250,8 +250,8 @@ if path.ext == ".py": return MyModule(path, parent) """) - sub = testdir.mkdir("sub") - p = testdir.makepyfile("def test_x(): pass") + testdir.mkdir("sub") + testdir.makepyfile("def test_x(): pass") result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*MyModule*", @@ -318,7 +318,7 @@ topdir = testdir.tmpdir rcol = Session(config) assert topdir == rcol.fspath - rootid = rcol.nodeid + #rootid = rcol.nodeid #root2 = rcol.perform_collect([rcol.nodeid], genitems=False)[0] #assert root2 == rcol, rootid colitems = rcol.perform_collect([rcol.nodeid], genitems=False) @@ -329,13 +329,13 @@ def test_collect_protocol_single_function(self, testdir): p = testdir.makepyfile("def test_func(): pass") id = "::".join([p.basename, "test_func"]) - topdir = testdir.tmpdir items, hookrec = testdir.inline_genitems(id) item, = items assert item.name == "test_func" newid = item.nodeid assert newid == id py.std.pprint.pprint(hookrec.hookrecorder.calls) + topdir = testdir.tmpdir # noqa hookrec.hookrecorder.contains([ ("pytest_collectstart", "collector.fspath == topdir"), ("pytest_make_collect_report", "collector.fspath == topdir"), @@ -436,7 +436,7 @@ ]) def test_serialization_byid(self, testdir): - p = testdir.makepyfile("def test_func(): pass") + testdir.makepyfile("def test_func(): pass") items, hookrec = testdir.inline_genitems() assert len(items) == 1 item, = items diff -Nru pytest-2.4.2/testing/test_config.py pytest-2.5.1/testing/test_config.py --- pytest-2.4.2/testing/test_config.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_config.py 2013-12-17 08:00:02.000000000 +0000 @@ -16,7 +16,7 @@ assert config.inicfg['name'] == 'value' def test_getcfg_empty_path(self, tmpdir): - cfg = getcfg([''], ['setup.cfg']) #happens on py.test "" + getcfg([''], ['setup.cfg']) #happens on py.test "" def test_append_parse_args(self, testdir, tmpdir): tmpdir.join("setup.cfg").write(py.code.Source(""" @@ -31,7 +31,7 @@ #assert len(args) == 1 def test_tox_ini_wrong_version(self, testdir): - p = testdir.makefile('.ini', tox=""" + testdir.makefile('.ini', tox=""" [pytest] minversion=9.0 """) @@ -41,7 +41,7 @@ "*tox.ini:2*requires*9.0*actual*" ]) - @pytest.mark.multi(name="setup.cfg tox.ini pytest.ini".split()) + @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) def test_ini_names(self, testdir, name): testdir.tmpdir.join(name).write(py.std.textwrap.dedent(""" [pytest] @@ -77,7 +77,7 @@ class TestConfigCmdlineParsing: def test_parsing_again_fails(self, testdir): config = testdir.parseconfig() - pytest.raises(AssertionError, "config.parse([])") + pytest.raises(AssertionError, lambda: config.parse([])) class TestConfigAPI: @@ -200,7 +200,7 @@ parser.addini("args", "new args", type="args") parser.addini("a2", "", "args", default="1 2 3".split()) """) - p = testdir.makeini(""" + testdir.makeini(""" [pytest] args=123 "123 hello" "this" """) @@ -217,7 +217,7 @@ parser.addini("xy", "", type="linelist") parser.addini("a2", "", "linelist") """) - p = testdir.makeini(""" + testdir.makeini(""" [pytest] xy= 123 345 second line @@ -234,7 +234,7 @@ def pytest_addoption(parser): parser.addini("xy", "", type="linelist") """) - p = testdir.makeini(""" + testdir.makeini(""" [pytest] xy= 123 """) diff -Nru pytest-2.4.2/testing/test_conftest.py pytest-2.5.1/testing/test_conftest.py --- pytest-2.4.2/testing/test_conftest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_conftest.py 2013-12-17 08:00:02.000000000 +0000 @@ -8,7 +8,7 @@ def pytest_funcarg__basedir(request): def basedirmaker(request): - basedir = d = request.getfuncargvalue("tmpdir") + d = request.getfuncargvalue("tmpdir") d.ensure("adir/conftest.py").write("a=1 ; Directory = 3") d.ensure("adir/b/conftest.py").write("b=2 ; a = 1.5") if request.param == "inpackage": @@ -41,7 +41,7 @@ def test_immediate_initialiation_and_incremental_are_the_same(self, basedir): conftest = Conftest() - snap0 = len(conftest._path2confmods) + len(conftest._path2confmods) conftest.getconftestmodules(basedir) snap1 = len(conftest._path2confmods) #assert len(conftest._path2confmods) == snap1 + 1 @@ -57,7 +57,7 @@ def test_value_access_not_existing(self, basedir): conftest = ConftestWithSetinitial(basedir) - pytest.raises(KeyError, "conftest.rget('a')") + pytest.raises(KeyError, lambda: conftest.rget('a')) #pytest.raises(KeyError, "conftest.lget('a')") def test_value_access_by_path(self, basedir): @@ -97,7 +97,7 @@ tmpdir.ensure("adir-1.0/b/conftest.py").write("b=2 ; a = 1.5") tmpdir.ensure("adir-1.0/b/__init__.py") tmpdir.ensure("adir-1.0/__init__.py") - conftest = ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) + ConftestWithSetinitial(tmpdir.join("adir-1.0", "b")) def test_doubledash_not_considered(testdir): conf = testdir.mkdir("--option") @@ -182,7 +182,7 @@ assert conftest.getconftestmodules(sub) == [] assert conftest.getconftestmodules(conf.dirpath()) == [] -@pytest.mark.multi(name='test tests whatever .dotdir'.split()) +@pytest.mark.parametrize("name", 'test tests whatever .dotdir'.split()) def test_setinitial_conftest_subdirs(testdir, name): sub = testdir.mkdir(name) subconftest = sub.ensure("conftest.py") @@ -215,3 +215,40 @@ conftest = Conftest() monkeypatch.setattr(conftest, 'importconftest', impct) assert conftest.getconftestmodules(sub) == [ct1, ct2] + + +def test_fixture_dependency(testdir, monkeypatch): + ct1 = testdir.makeconftest("") + ct1 = testdir.makepyfile("__init__.py") + ct1.write("") + sub = testdir.mkdir("sub") + sub.join("__init__.py").write("") + sub.join("conftest.py").write(py.std.textwrap.dedent(""" + import pytest + + @pytest.fixture + def not_needed(): + assert False, "Should not be called!" + + @pytest.fixture + def foo(): + assert False, "Should not be called!" + + @pytest.fixture + def bar(foo): + return 'bar' + """)) + subsub = sub.mkdir("subsub") + subsub.join("__init__.py").write("") + subsub.join("test_bar.py").write(py.std.textwrap.dedent(""" + import pytest + + @pytest.fixture + def bar(): + return 'sub bar' + + def test_event_fixture(bar): + assert bar == 'sub bar' + """)) + result = testdir.runpytest("sub") + result.stdout.fnmatch_lines(["*1 passed*"]) diff -Nru pytest-2.4.2/testing/test_core.py pytest-2.5.1/testing/test_core.py --- pytest-2.4.2/testing/test_core.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_core.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,5 @@ import pytest, py, os -from _pytest.core import PluginManager -from _pytest.core import MultiCall, HookRelay, varnames +from _pytest.core import * # noqa from _pytest.config import get_plugin_manager @@ -8,13 +7,12 @@ def test_consider_env_fails_to_import(self, monkeypatch): pluginmanager = PluginManager() monkeypatch.setenv('PYTEST_PLUGINS', 'nonexisting', prepend=",") - pytest.raises(ImportError, "pluginmanager.consider_env()") + pytest.raises(ImportError, lambda: pluginmanager.consider_env()) def test_preparse_args(self): pluginmanager = PluginManager() - pytest.raises(ImportError, """ - pluginmanager.consider_preparse(["xyz", "-p", "hello123"]) - """) + pytest.raises(ImportError, lambda: + pluginmanager.consider_preparse(["xyz", "-p", "hello123"])) def test_plugin_prevent_register(self): pluginmanager = PluginManager() @@ -93,7 +91,7 @@ # ok, we did not explode def test_pluginmanager_ENV_startup(self, testdir, monkeypatch): - x500 = testdir.makepyfile(pytest_x500="#") + testdir.makepyfile(pytest_x500="#") p = testdir.makepyfile(""" import pytest def test_hello(pytestconfig): @@ -110,7 +108,7 @@ pytest.raises(ImportError, 'pluginmanager.import_plugin("qweqwex.y")') pytest.raises(ImportError, 'pluginmanager.import_plugin("pytest_qweqwx.y")') - reset = testdir.syspathinsert() + testdir.syspathinsert() pluginname = "pytest_hello" testdir.makepyfile(**{pluginname: ""}) pluginmanager.import_plugin("pytest_hello") @@ -128,7 +126,7 @@ pytest.raises(ImportError, 'pluginmanager.import_plugin("qweqwex.y")') pytest.raises(ImportError, 'pluginmanager.import_plugin("pytest_qweqwex.y")') - reset = testdir.syspathinsert() + testdir.syspathinsert() testdir.mkpydir("pkg").join("plug.py").write("x=3") pluginname = "pkg.plug" pluginmanager.import_plugin(pluginname) @@ -170,7 +168,7 @@ def test_consider_conftest_deps(self, testdir): mod = testdir.makepyfile("pytest_plugins='xyz'").pyimport() pp = PluginManager() - pytest.raises(ImportError, "pp.consider_conftest(mod)") + pytest.raises(ImportError, lambda: pp.consider_conftest(mod)) def test_pm(self): pp = PluginManager() @@ -210,9 +208,7 @@ l = pp.getplugins() assert mod in l pytest.raises(ValueError, "pp.register(mod)") - mod2 = py.std.types.ModuleType("pytest_hello") - #pp.register(mod2) # double pm - pytest.raises(ValueError, "pp.register(mod)") + pytest.raises(ValueError, lambda: pp.register(mod)) #assert not pp.isregistered(mod2) assert pp.getplugins() == l @@ -229,14 +225,14 @@ class hello: def pytest_gurgel(self): pass - pytest.raises(Exception, "pp.register(hello())") + pytest.raises(Exception, lambda: pp.register(hello())) def test_register_mismatch_arg(self): pp = get_plugin_manager() class hello: def pytest_configure(self, asd): pass - excinfo = pytest.raises(Exception, "pp.register(hello())") + pytest.raises(Exception, lambda: pp.register(hello())) def test_register(self): pm = get_plugin_manager() @@ -293,7 +289,7 @@ class TestPytestPluginInteractions: def test_addhooks_conftestplugin(self, testdir): - newhooks = testdir.makepyfile(newhooks=""" + testdir.makepyfile(newhooks=""" def pytest_myhook(xyz): "new hook" """) @@ -312,7 +308,7 @@ assert res == [11] def test_addhooks_nohooks(self, testdir): - conf = testdir.makeconftest(""" + testdir.makeconftest(""" import sys def pytest_addhooks(pluginmanager): pluginmanager.addhooks(sys) @@ -344,10 +340,8 @@ assert hello == "world" assert 'hello' in py.test.__all__ """) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines([ - "*1 passed*" - ]) + reprec = testdir.inline_run(p) + reprec.assertoutcome(passed=1) def test_do_option_postinitialize(self, testdir): config = testdir.parseconfigure() @@ -431,7 +425,7 @@ def test_varnames(): def f(x): - i = 3 + i = 3 # noqa class A: def f(self, y): pass @@ -442,6 +436,15 @@ assert varnames(A().f) == ('y',) assert varnames(B()) == ('z',) +def test_varnames_class(): + class C: + def __init__(self, x): + pass + class D: + pass + assert varnames(C) == ("x",) + assert varnames(D) == () + class TestMultiCall: def test_uses_copy_of_methods(self): l = [lambda: 42] @@ -496,7 +499,7 @@ def test_tags_call_error(self): multicall = MultiCall([lambda x: x], {}) - pytest.raises(TypeError, "multicall.execute()") + pytest.raises(TypeError, multicall.execute) def test_call_subexecute(self): def m(__multicall__): @@ -544,7 +547,7 @@ def hello(self, arg): "api hook 1" mcm = HookRelay(hookspecs=Api, pm=pm, prefix="he") - pytest.raises(TypeError, "mcm.hello(3)") + pytest.raises(TypeError, lambda: mcm.hello(3)) def test_firstresult_definition(self): pm = PluginManager() @@ -655,3 +658,10 @@ "*tryfirst*first*", "*trylast*last*", ]) + +def test_importplugin_issue375(testdir): + testdir.makepyfile(qwe="import aaaa") + excinfo = pytest.raises(ImportError, lambda: importplugin("qwe")) + assert "qwe" not in str(excinfo.value) + assert "aaaa" in str(excinfo.value) + diff -Nru pytest-2.4.2/testing/test_doctest.py pytest-2.5.1/testing/test_doctest.py --- pytest-2.4.2/testing/test_doctest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_doctest.py 2013-12-17 08:00:02.000000000 +0000 @@ -99,7 +99,7 @@ reprec.assertoutcome(failed=1) def test_doctest_unexpected_exception(self, testdir): - p = testdir.maketxtfile(""" + testdir.maketxtfile(""" >>> i = 0 >>> 0 / i 2 @@ -136,7 +136,7 @@ testdir.tmpdir.join("hello.py").write(py.code.Source(""" import asdalsdkjaslkdjasd """)) - p = testdir.maketxtfile(""" + testdir.maketxtfile(""" >>> import hello >>> """) @@ -209,6 +209,26 @@ reprec = testdir.inline_run(p, ) reprec.assertoutcome(passed=1) + @xfail_if_pdbpp_installed + def test_txtfile_with_usefixtures_in_ini(self, testdir): + testdir.makeini(""" + [pytest] + usefixtures = myfixture + """) + testdir.makeconftest(""" + import pytest + @pytest.fixture + def myfixture(monkeypatch): + monkeypatch.setenv("HELLO", "WORLD") + """) + + p = testdir.maketxtfile(""" + >>> import os + >>> os.environ["HELLO"] + 'WORLD' + """) + reprec = testdir.inline_run(p, ) + reprec.assertoutcome(passed=1) @xfail_if_pdbpp_installed def test_doctestmodule_with_fixtures(self, testdir): diff -Nru pytest-2.4.2/testing/test_fixture_finalizer.py pytest-2.5.1/testing/test_fixture_finalizer.py --- pytest-2.4.2/testing/test_fixture_finalizer.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_fixture_finalizer.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -"""Tests for fixtures with different scoping.""" -import py.code - - -def test_fixture_finalizer(testdir): - testdir.makeconftest(""" - import pytest - import sys - - @pytest.fixture - def browser(request): - - def finalize(): - sys.stdout.write('Finalized') - request.addfinalizer(finalize) - return {} - """) - b = testdir.mkdir("subdir") - b.join("test_overriden_fixture_finalizer.py").write(py.code.Source(""" - import pytest - @pytest.fixture - def browser(browser): - browser['visited'] = True - return browser - - def test_browser(browser): - assert browser['visited'] is True - """)) - reprec = testdir.runpytest("-s") - for test in ['test_browser']: - reprec.stdout.fnmatch_lines('*Finalized*') diff -Nru pytest-2.4.2/testing/test_fixture_scope.py pytest-2.5.1/testing/test_fixture_scope.py --- pytest-2.4.2/testing/test_fixture_scope.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_fixture_scope.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -"""Tests for fixtures with different scoping.""" - - -def test_class_scope_with_normal_tests(testdir): - testpath = testdir.makepyfile(""" - import pytest - - class Box: - value = 0 - - @pytest.fixture(scope='class') - def a(request): - Box.value += 1 - return Box.value - - def test_a(a): - assert a == 1 - - class Test1: - def test_b(self, a): - assert a == 2 - - class Test2: - def test_c(self, a): - assert a == 3""") - reprec = testdir.inline_run(testpath) - for test in ['test_a', 'test_b', 'test_c']: - assert reprec.matchreport(test).passed diff -Nru pytest-2.4.2/testing/test_genscript.py pytest-2.5.1/testing/test_genscript.py --- pytest-2.4.2/testing/test_genscript.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_genscript.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,5 @@ import pytest -import py, os, sys -import subprocess +import sys @pytest.fixture(scope="module") @@ -23,7 +22,8 @@ def test_gen(testdir, anypython, standalone): if sys.version_info >= (2,7): result = testdir._run(anypython, "-c", - "import sys;print sys.version_info >=(2,7)") + "import sys;print (sys.version_info >=(2,7))") + assert result.ret == 0 if result.stdout.str() == "False": pytest.skip("genscript called from python2.7 cannot work " "earlier python versions") @@ -36,14 +36,3 @@ result = standalone.run(anypython, testdir, p) assert result.ret != 0 -def test_rundist(testdir, pytestconfig, standalone): - pytestconfig.pluginmanager.skipifmissing("xdist") - testdir.makepyfile(""" - def test_one(): - pass - """) - result = standalone.run(sys.executable, testdir, '-n', '3') - assert result.ret == 0 - result.stdout.fnmatch_lines([ - "*1 passed*", - ]) diff -Nru pytest-2.4.2/testing/test_helpconfig.py pytest-2.5.1/testing/test_helpconfig.py --- pytest-2.4.2/testing/test_helpconfig.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_helpconfig.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,4 +1,4 @@ -import py, pytest,os +import py, pytest from _pytest.helpconfig import collectattr def test_version(testdir, pytestconfig): diff -Nru pytest-2.4.2/testing/test_junitxml.py pytest-2.5.1/testing/test_junitxml.py --- pytest-2.4.2/testing/test_junitxml.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_junitxml.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,8 @@ -import pytest +# -*- coding: utf-8 -*- + from xml.dom import minidom import py, sys, os +from _pytest.junitxml import LogXML def runandparse(testdir, *args): resultpath = testdir.tmpdir.join("junit.xml") @@ -282,6 +284,19 @@ if not sys.platform.startswith("java"): assert "hx" in fnode.toxml() + def test_assertion_binchars(self, testdir): + """this test did fail when the escaping wasnt strict""" + testdir.makepyfile(""" + + M1 = '\x01\x02\x03\x04' + M2 = '\x01\x02\x03\x05' + + def test_str_compare(): + assert M1 == M2 + """) + result, dom = runandparse(testdir) + print(dom.toxml()) + def test_pass_captures_stdout(self, testdir): testdir.makepyfile(""" def test_pass(): @@ -370,7 +385,7 @@ assert False """) xmlf = testdir.tmpdir.join('junit.xml') - result = testdir.runpytest('--junitxml=%s' % xmlf) + testdir.runpytest('--junitxml=%s' % xmlf) text = xmlf.read() assert '\x00' not in text assert '#x00' in text @@ -386,11 +401,10 @@ assert False """) xmlf = testdir.tmpdir.join('junit.xml') - result = testdir.runpytest('--junitxml=%s' % xmlf) + testdir.runpytest('--junitxml=%s' % xmlf) text = xmlf.read() assert '#x0' in text - def test_invalid_xml_escape(): # Test some more invalid xml chars, the full range should be # tested really but let's just thest the edges of the ranges @@ -405,7 +419,6 @@ unichr(65) except NameError: unichr = chr - u = py.builtin._totext invalid = (0x00, 0x1, 0xB, 0xC, 0xE, 0x19, 27, # issue #126 0xD800, 0xDFFF, 0xFFFE, 0x0FFFF) #, 0x110000) @@ -425,8 +438,6 @@ assert chr(i) == bin_xml_escape(unichr(i)).uniobj def test_logxml_path_expansion(tmpdir, monkeypatch): - from _pytest.junitxml import LogXML - home_tilde = py.path.local(os.path.expanduser('~')).join('test.xml') xml_tilde = LogXML('~%stest.xml' % tmpdir.sep, None) @@ -463,3 +474,26 @@ assert_attr(node, name="test_func[#x00]") +def test_unicode_issue368(testdir): + path = testdir.tmpdir.join("test.xml") + log = LogXML(str(path), None) + ustr = py.builtin._totext("ВНИ!", "utf-8") + class report: + longrepr = ustr + sections = [] + nodeid = "something" + + # hopefully this is not too brittle ... + log.pytest_sessionstart() + log._opentestcase(report) + log.append_failure(report) + log.append_collect_failure(report) + log.append_collect_skipped(report) + log.append_error(report) + report.longrepr = "filename", 1, ustr + log.append_skipped(report) + report.wasxfail = ustr + log.append_skipped(report) + log.pytest_sessionfinish() + + diff -Nru pytest-2.4.2/testing/test_mark.py pytest-2.5.1/testing/test_mark.py --- pytest-2.4.2/testing/test_mark.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_mark.py 2013-12-17 08:00:02.000000000 +0000 @@ -13,7 +13,7 @@ def test_pytest_mark_notcallable(self): mark = Mark() - pytest.raises((AttributeError, TypeError), "mark()") + pytest.raises((AttributeError, TypeError), mark) def test_pytest_mark_bare(self): mark = Mark() @@ -35,7 +35,7 @@ mark = Mark() def f(): pass - marker = mark.world + mark.world mark.world(x=3)(f) assert f.world.kwargs['x'] == 3 mark.world(y=4)(f) @@ -100,6 +100,16 @@ "*a1some*another marker", ]) +def test_mark_on_pseudo_function(testdir): + testdir.makepyfile(""" + import pytest + + @pytest.mark.r(lambda x: 0/0) + def test_hello(): + pass + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) def test_strict_prohibits_unregistered_markers(testdir): testdir.makepyfile(""" @@ -114,7 +124,7 @@ "*unregisteredmark*not*registered*", ]) -@pytest.mark.multi(spec=[ +@pytest.mark.parametrize("spec", [ ("xyz", ("test_one",)), ("xyz and xyz2", ()), ("xyz2", ("test_two",)), @@ -137,7 +147,7 @@ assert len(passed) == len(passed_result) assert list(passed) == list(passed_result) -@pytest.mark.multi(spec=[ +@pytest.mark.parametrize("spec", [ ("interface", ("test_interface",)), ("not interface", ("test_nointer",)), ]) @@ -162,9 +172,11 @@ assert len(passed) == len(passed_result) assert list(passed) == list(passed_result) -@pytest.mark.multi(spec=[ +@pytest.mark.parametrize("spec", [ ("interface", ("test_interface",)), - ("not interface", ("test_nointer",)), + ("not interface", ("test_nointer", "test_pass")), + ("pass", ("test_pass",)), + ("not pass", ("test_interface", "test_nointer")), ]) def test_keyword_option_custom(spec, testdir): testdir.makepyfile(""" @@ -172,6 +184,8 @@ pass def test_nointer(): pass + def test_pass(): + pass """) opt, passed_result = spec rec = testdir.inline_run("-k", opt) @@ -181,6 +195,24 @@ assert list(passed) == list(passed_result) +@pytest.mark.parametrize("spec", [ + ("None", ("test_func[None]",)), + ("1.3", ("test_func[1.3]",)) +]) +def test_keyword_option_parametrize(spec, testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.parametrize("arg", [None, 1.3]) + def test_func(arg): + pass + """) + opt, passed_result = spec + rec = testdir.inline_run("-k", opt) + passed, skipped, fail = rec.listoutcomes() + passed = [x.nodeid.split("::")[-1] for x in passed] + assert len(passed) == len(passed_result) + assert list(passed) == list(passed_result) + class TestFunctional: def test_mark_per_function(self, testdir): @@ -364,7 +396,7 @@ assert len(deselected_tests) == 2 def test_keywords_at_node_level(self, testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" import pytest @pytest.fixture(scope="session", autouse=True) def some(request): @@ -510,3 +542,4 @@ assert_test_is_not_selected("__") assert_test_is_not_selected("()") + diff -Nru pytest-2.4.2/testing/test_monkeypatch.py pytest-2.5.1/testing/test_monkeypatch.py --- pytest-2.4.2/testing/test_monkeypatch.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_monkeypatch.py 2013-12-17 08:00:02.000000000 +0000 @@ -45,6 +45,12 @@ import _pytest assert _pytest.config.Config == 42 + def test_unicode_string(self, monkeypatch): + monkeypatch.setattr("_pytest.config.Config", 42) + import _pytest + assert _pytest.config.Config == 42 + monkeypatch.delattr("_pytest.config.Config") + def test_wrong_target(self, monkeypatch): pytest.raises(TypeError, lambda: monkeypatch.setattr(None, None)) diff -Nru pytest-2.4.2/testing/test_nose.py pytest-2.5.1/testing/test_nose.py --- pytest-2.4.2/testing/test_nose.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_nose.py 2013-12-17 08:00:02.000000000 +0000 @@ -96,7 +96,7 @@ def test_nose_setup_func_failure_2(testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" l = [] my_setup = 1 diff -Nru pytest-2.4.2/testing/test_parseopt.py pytest-2.5.1/testing/test_parseopt.py --- pytest-2.4.2/testing/test_parseopt.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_parseopt.py 2013-12-17 08:00:02.000000000 +0000 @@ -3,7 +3,6 @@ import os import py, pytest from _pytest import config as parseopt -from textwrap import dedent @pytest.fixture def parser(): @@ -12,7 +11,7 @@ class TestParser: def test_no_help_by_default(self, capsys): parser = parseopt.Parser(usage="xyz") - pytest.raises(SystemExit, 'parser.parse(["-h"])') + pytest.raises(SystemExit, lambda: parser.parse(["-h"])) out, err = capsys.readouterr() assert err.find("error: unrecognized arguments") != -1 @@ -65,9 +64,9 @@ assert group2 is group def test_group_ordering(self, parser): - group0 = parser.getgroup("1") - group1 = parser.getgroup("2") - group1 = parser.getgroup("3", after="1") + parser.getgroup("1") + parser.getgroup("2") + parser.getgroup("3", after="1") groups = parser._groups groups_names = [x.name for x in groups] assert groups_names == list("132") @@ -104,7 +103,7 @@ assert getattr(args, parseopt.FILE_OR_DIR)[0] == py.path.local() def test_parse_known_args(self, parser): - args = parser.parse_known_args([py.path.local()]) + parser.parse_known_args([py.path.local()]) parser.addoption("--hello", action="store_true") ns = parser.parse_known_args(["x", "--y", "--hello", "this"]) assert ns.hello @@ -114,7 +113,7 @@ option = parser.parse([]) assert option.hello == "x" del option.hello - args = parser.parse_setoption([], option) + parser.parse_setoption([], option) assert option.hello == "x" def test_parse_setoption(self, parser): @@ -128,7 +127,7 @@ assert not args def test_parse_special_destination(self, parser): - x = parser.addoption("--ultimate-answer", type=int) + parser.addoption("--ultimate-answer", type=int) args = parser.parse(['--ultimate-answer', '42']) assert args.ultimate_answer == 42 diff -Nru pytest-2.4.2/testing/test_pastebin.py pytest-2.5.1/testing/test_pastebin.py --- pytest-2.4.2/testing/test_pastebin.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_pastebin.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,4 +1,3 @@ -import pytest class TestPasting: def pytest_funcarg__pastebinlist(self, request): @@ -56,4 +55,4 @@ assert proxy is not None assert proxy.__class__.__module__.startswith('xmlrpc') - + diff -Nru pytest-2.4.2/testing/test_pdb.py pytest-2.5.1/testing/test_pdb.py --- pytest-2.4.2/testing/test_pdb.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_pdb.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,4 +1,5 @@ -import py, pytest + +import py import sys from test_doctest import xfail_if_pdbpp_installed @@ -62,7 +63,7 @@ child.expect(".*i = 0") child.expect("(Pdb)") child.sendeof() - rest = child.read() + rest = child.read().decode("utf8") assert "1 failed" in rest assert "def test_1" not in rest if child.isalive(): @@ -127,7 +128,7 @@ child.expect("x = 3") child.expect("(Pdb)") child.sendeof() - rest = child.read() + rest = child.read().decode("utf-8") assert "1 failed" in rest assert "def test_1" in rest assert "hello17" in rest # out is captured @@ -144,7 +145,7 @@ child.expect("test_1") child.expect("(Pdb)") child.sendeof() - rest = child.read() + rest = child.read().decode("utf8") assert "1 failed" in rest assert "reading from stdin while output" not in rest if child.isalive(): @@ -162,7 +163,7 @@ child.send("capsys.readouterr()\n") child.expect("hello1") child.sendeof() - rest = child.read() + child.read() if child.isalive(): child.wait() @@ -182,7 +183,7 @@ child.expect("0") child.expect("(Pdb)") child.sendeof() - rest = child.read() + rest = child.read().decode("utf8") assert "1 failed" in rest if child.isalive(): child.wait() @@ -206,7 +207,7 @@ child.sendline('c') child.expect("x = 4") child.sendeof() - rest = child.read() + rest = child.read().decode("utf8") assert "1 failed" in rest assert "def test_1" in rest assert "hello17" in rest # out is captured @@ -238,6 +239,7 @@ child.expect("x = 5") child.sendeof() child.wait() + def test_pdb_collection_failure_is_shown(self, testdir): p1 = testdir.makepyfile("""xxx """) result = testdir.runpytest("--pdb", p1) diff -Nru pytest-2.4.2/testing/test_pytester.py pytest-2.5.1/testing/test_pytester.py --- pytest-2.4.2/testing/test_pytester.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_pytester.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,7 +1,7 @@ import py import pytest -import os, sys -from _pytest.pytester import LineMatcher, LineComp, HookRecorder +import os +from _pytest.pytester import HookRecorder from _pytest.core import PluginManager def test_reportrecorder(testdir): @@ -56,7 +56,6 @@ def test_parseconfig(testdir): - import py config1 = testdir.parseconfig() config2 = testdir.parseconfig() assert config2 != config1 diff -Nru pytest-2.4.2/testing/test_resultlog.py pytest-2.5.1/testing/test_resultlog.py --- pytest-2.4.2/testing/test_resultlog.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_resultlog.py 2013-12-17 08:00:02.000000000 +0000 @@ -195,3 +195,23 @@ pytest_unconfigure(config) assert not hasattr(config, '_resultlog') + +def test_failure_issue380(testdir): + testdir.makeconftest(""" + import pytest + class MyCollector(pytest.File): + def collect(self): + raise ValueError() + def repr_failure(self, excinfo): + return "somestring" + def pytest_collect_file(path, parent): + return MyCollector(parent=parent, fspath=path) + """) + testdir.makepyfile(""" + def test_func(): + pass + """) + result = testdir.runpytest("--resultlog=log") + assert result.ret == 1 + + diff -Nru pytest-2.4.2/testing/test_runner.py pytest-2.5.1/testing/test_runner.py --- pytest-2.4.2/testing/test_runner.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_runner.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,6 +1,7 @@ +from __future__ import with_statement + import pytest, py, sys, os from _pytest import runner, main -from py._code.code import ReprExceptionInfo class TestSetupState: def test_setup(self, testdir): @@ -39,10 +40,39 @@ def setup_module(mod): raise ValueError(42) def test_func(): pass - """) + """) # noqa + ss = runner.SetupState() + pytest.raises(ValueError, lambda: ss.prepare(item)) + pytest.raises(ValueError, lambda: ss.prepare(item)) + + def test_teardown_multiple_one_fails(self, testdir): + r = [] + def fin1(): r.append('fin1') + def fin2(): raise Exception('oops') + def fin3(): r.append('fin3') + item = testdir.getitem("def test_func(): pass") + ss = runner.SetupState() + ss.addfinalizer(fin1, item) + ss.addfinalizer(fin2, item) + ss.addfinalizer(fin3, item) + with pytest.raises(Exception) as err: + ss._callfinalizers(item) + assert err.value.args == ('oops',) + assert r == ['fin3', 'fin1'] + + def test_teardown_multiple_fail(self, testdir): + # Ensure the first exception is the one which is re-raised. + # Ideally both would be reported however. + def fin1(): raise Exception('oops1') + def fin2(): raise Exception('oops2') + item = testdir.getitem("def test_func(): pass") ss = runner.SetupState() - pytest.raises(ValueError, "ss.prepare(item)") - pytest.raises(ValueError, "ss.prepare(item)") + ss.addfinalizer(fin1, item) + ss.addfinalizer(fin2, item) + with pytest.raises(Exception) as err: + ss._callfinalizers(item) + assert err.value.args == ('oops2',) + class BaseFunctionalTests: def test_passfunction(self, testdir): @@ -428,7 +458,7 @@ def f(): importorskip("asdlkj") try: - sys = importorskip("sys") + sys = importorskip("sys") # noqa assert sys == py.std.sys #path = py.test.importorskip("os.path") #assert path == py.std.os.path @@ -439,12 +469,14 @@ assert path.purebasename == "test_runner" pytest.raises(SyntaxError, "py.test.importorskip('x y z')") pytest.raises(SyntaxError, "py.test.importorskip('x=y')") - path = importorskip("py", minversion=".".join(py.__version__)) mod = py.std.types.ModuleType("hello123") mod.__version__ = "1.3" + sys.modules["hello123"] = mod pytest.raises(pytest.skip.Exception, """ - py.test.importorskip("hello123", minversion="5.0") + py.test.importorskip("hello123", minversion="1.3.1") """) + mod2 = pytest.importorskip("hello123", minversion="1.3") + assert mod2 == mod except pytest.skip.Exception: print(py.code.ExceptionInfo()) py.test.fail("spurious skip") @@ -464,7 +496,7 @@ """) import subprocess popen = subprocess.Popen([sys.executable, str(p)], stdout=subprocess.PIPE) - s = popen.stdout.read() + popen.communicate() ret = popen.wait() assert ret == 0 diff -Nru pytest-2.4.2/testing/test_session.py pytest-2.5.1/testing/test_session.py --- pytest-2.4.2/testing/test_session.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_session.py 2013-12-17 08:00:02.000000000 +0000 @@ -204,7 +204,7 @@ def test_plugin_specify(testdir): testdir.chdir() - config = pytest.raises(ImportError, """ + pytest.raises(ImportError, """ testdir.parseconfig("-p", "nqweotexistent") """) #pytest.raises(ImportError, diff -Nru pytest-2.4.2/testing/test_skipping.py pytest-2.5.1/testing/test_skipping.py --- pytest-2.4.2/testing/test_skipping.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_skipping.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,8 +1,7 @@ import pytest import sys -from _pytest.skipping import MarkEvaluator, folded_skips -from _pytest.skipping import pytest_runtest_setup +from _pytest.skipping import MarkEvaluator, folded_skips, pytest_runtest_setup from _pytest.runner import runtestprotocol class TestEvaluator: @@ -108,7 +107,7 @@ pass """) ev = MarkEvaluator(item, 'skipif') - exc = pytest.raises(pytest.fail.Exception, "ev.istrue()") + exc = pytest.raises(pytest.fail.Exception, ev.istrue) assert """Failed: you need to specify reason=STRING when using booleans as conditions.""" in exc.value.msg def test_skipif_class(self, testdir): @@ -159,13 +158,14 @@ @pytest.mark.xfail def test_func(): assert 0 + def test_func2(): + pytest.xfail("hello") """) result = testdir.runpytest("--runxfail") - assert result.ret == 1 result.stdout.fnmatch_lines([ "*def test_func():*", "*assert 0*", - "*1 failed*", + "*1 failed*1 pass*", ]) def test_xfail_evalfalse_but_fails(self, testdir): @@ -188,7 +188,7 @@ def test_this(): assert 0 """) - result = testdir.runpytest(p, '-v') + testdir.runpytest(p, '-v') #result.stdout.fnmatch_lines([ # "*HINT*use*-r*" #]) @@ -261,10 +261,7 @@ "*reason:*hello*", ]) result = testdir.runpytest(p, "--runxfail") - result.stdout.fnmatch_lines([ - "*def test_this():*", - "*pytest.xfail*", - ]) + result.stdout.fnmatch_lines("*1 pass*") def test_xfail_imperative_in_setup_function(self, testdir): p = testdir.makepyfile(""" @@ -285,10 +282,10 @@ "*reason:*hello*", ]) result = testdir.runpytest(p, "--runxfail") - result.stdout.fnmatch_lines([ - "*def setup_function(function):*", - "*pytest.xfail*", - ]) + result.stdout.fnmatch_lines(""" + *def test_this* + *1 fail* + """) def xtest_dynamic_xfail_set_during_setup(self, testdir): p = testdir.makepyfile(""" @@ -372,8 +369,9 @@ @pytest.mark.skipif("hasattr(os, 'sep')") def test_func(): pass - """) - x = pytest.raises(pytest.skip.Exception, "pytest_runtest_setup(item)") + """) # noqa + x = pytest.raises(pytest.skip.Exception, lambda: + pytest_runtest_setup(item)) assert x.value.msg == "condition: hasattr(os, 'sep')" diff -Nru pytest-2.4.2/testing/test_terminal.py pytest-2.5.1/testing/test_terminal.py --- pytest-2.4.2/testing/test_terminal.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_terminal.py 2013-12-17 08:00:02.000000000 +0000 @@ -39,7 +39,7 @@ class TestTerminal: def test_pass_skip_fail(self, testdir, option): - p = testdir.makepyfile(""" + testdir.makepyfile(""" import pytest def test_ok(): pass @@ -76,7 +76,6 @@ def test_writeline(self, testdir, linecomp): modcol = testdir.getmodulecol("def test_one(): pass") - stringio = py.io.TextIO() rep = TerminalReporter(modcol.config, file=linecomp.stringio) rep.write_fspath_result(py.path.local("xy.py"), '.') rep.write_line("hello world") @@ -97,7 +96,7 @@ ]) def test_runtest_location_shown_before_test_starts(self, testdir): - p1 = testdir.makepyfile(""" + testdir.makepyfile(""" def test_1(): import time time.sleep(20) @@ -108,7 +107,7 @@ child.kill(15) def test_itemreport_subclasses_show_subclassed_file(self, testdir): - p1 = testdir.makepyfile(test_p1=""" + testdir.makepyfile(test_p1=""" class BaseTests: def test_p1(self): pass @@ -145,7 +144,7 @@ assert " <- " not in result.stdout.str() def test_keyboard_interrupt(self, testdir, option): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_foobar(): assert 0 def test_spamegg(): @@ -172,7 +171,7 @@ def pytest_sessionstart(): raise KeyboardInterrupt """) - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_foobar(): pass """) @@ -214,7 +213,7 @@ ]) def test_collectonly_fatal(self, testdir): - p1 = testdir.makeconftest(""" + testdir.makeconftest(""" def pytest_collectstart(collector): assert 0, "urgs" """) @@ -233,7 +232,6 @@ pass """) result = testdir.runpytest("--collect-only", p) - stderr = result.stderr.str().strip() #assert stderr.startswith("inserting into sys.path") assert result.ret == 0 result.stdout.fnmatch_lines([ @@ -247,7 +245,6 @@ def test_collectonly_error(self, testdir): p = testdir.makepyfile("import Errlkjqweqwe") result = testdir.runpytest("--collect-only", p) - stderr = result.stderr.str().strip() assert result.ret == 1 result.stdout.fnmatch_lines(py.code.Source(""" *ERROR* @@ -293,7 +290,7 @@ class TestFixtureReporting: def test_setup_fixture_error(self, testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def setup_function(function): print ("setup func") assert 0 @@ -311,7 +308,7 @@ assert result.ret != 0 def test_teardown_fixture_error(self, testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_nada(): pass def teardown_function(function): @@ -329,7 +326,7 @@ ]) def test_teardown_fixture_error_and_test_failure(self, testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_fail(): assert 0, "failingfunc" @@ -403,7 +400,7 @@ assert result.ret == 0 def test_header_trailer_info(self, testdir): - p1 = testdir.makepyfile(""" + testdir.makepyfile(""" def test_passes(): pass """) @@ -486,20 +483,32 @@ def test_fail_extra_reporting(testdir): - p = testdir.makepyfile("def test_this(): assert 0") - result = testdir.runpytest(p) + testdir.makepyfile("def test_this(): assert 0") + result = testdir.runpytest() assert 'short test summary' not in result.stdout.str() - result = testdir.runpytest(p, '-rf') + result = testdir.runpytest('-rf') result.stdout.fnmatch_lines([ "*test summary*", "FAIL*test_fail_extra_reporting*", ]) def test_fail_reporting_on_pass(testdir): - p = testdir.makepyfile("def test_this(): assert 1") - result = testdir.runpytest(p, '-rf') + testdir.makepyfile("def test_this(): assert 1") + result = testdir.runpytest('-rf') assert 'short test summary' not in result.stdout.str() +def test_color_yes(testdir): + testdir.makepyfile("def test_this(): assert 1") + result = testdir.runpytest('--color=yes') + assert 'test session starts' in result.stdout.str() + assert '\x1b[1m' in result.stdout.str() + +def test_color_no(testdir): + testdir.makepyfile("def test_this(): assert 1") + result = testdir.runpytest('--color=no') + assert 'test session starts' in result.stdout.str() + assert '\x1b[1m' not in result.stdout.str() + def test_getreportopt(): class config: class option: @@ -522,7 +531,7 @@ def test_terminalreporter_reportopt_addopts(testdir): testdir.makeini("[pytest]\naddopts=-rs") - p = testdir.makepyfile(""" + testdir.makepyfile(""" def pytest_funcarg__tr(request): tr = request.config.pluginmanager.getplugin("terminalreporter") return tr @@ -570,7 +579,7 @@ provider to run e.g. distributed tests. """ def test_collect_fail(self, testdir, option): - p = testdir.makepyfile("import xyz\n") + testdir.makepyfile("import xyz\n") result = testdir.runpytest(*option.args) result.stdout.fnmatch_lines([ "> import xyz", @@ -579,7 +588,7 @@ ]) def test_maxfailures(self, testdir, option): - p = testdir.makepyfile(""" + testdir.makepyfile(""" def test_1(): assert 0 def test_2(): @@ -597,7 +606,7 @@ def test_tb_option(self, testdir, option): - p = testdir.makepyfile(""" + testdir.makepyfile(""" import pytest def g(): raise IndexError @@ -678,7 +687,7 @@ ]) def test_tbstyle_native_setup_error(testdir): - p = testdir.makepyfile(""" + testdir.makepyfile(""" import pytest @pytest.fixture def setup_error_fixture(): diff -Nru pytest-2.4.2/testing/test_tmpdir.py pytest-2.5.1/testing/test_tmpdir.py --- pytest-2.4.2/testing/test_tmpdir.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_tmpdir.py 2013-12-17 08:00:02.000000000 +0000 @@ -1,5 +1,4 @@ import py, pytest -import os from _pytest.tmpdir import tmpdir, TempdirHandler diff -Nru pytest-2.4.2/testing/test_unittest.py pytest-2.5.1/testing/test_unittest.py --- pytest-2.4.2/testing/test_unittest.py 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/testing/test_unittest.py 2013-12-17 08:00:02.000000000 +0000 @@ -15,7 +15,7 @@ assert reprec.matchreport("test_failing").failed def test_runTest_method(testdir): - testpath=testdir.makepyfile(""" + testdir.makepyfile(""" import unittest pytest_plugins = "pytest_unittest" class MyTestCaseWithRunTest(unittest.TestCase): @@ -236,7 +236,7 @@ reprec.assertoutcome(passed=3) -@pytest.mark.multi(type=['Error', 'Failure']) +@pytest.mark.parametrize("type", ['Error', 'Failure']) def test_testcase_adderrorandfailure_defers(testdir, type): testdir.makepyfile(""" from unittest import TestCase @@ -256,7 +256,7 @@ result = testdir.runpytest() assert 'should not raise' not in result.stdout.str() -@pytest.mark.multi(type=['Error', 'Failure']) +@pytest.mark.parametrize("type", ['Error', 'Failure']) def test_testcase_custom_exception_info(testdir, type): testdir.makepyfile(""" from unittest import TestCase @@ -310,9 +310,10 @@ reprec.assertoutcome(skipped=1) -def test_testcase_skip_property(testdir): +def test_trial_testcase_skip_property(testdir): + pytest.importorskip('twisted.trial.unittest') testpath = testdir.makepyfile(""" - import unittest + from twisted.trial import unittest class MyTestCase(unittest.TestCase): skip = 'dont run' def test_func(self): @@ -321,9 +322,11 @@ reprec = testdir.inline_run(testpath, "-s") reprec.assertoutcome(skipped=1) -def test_testfunction_skip_property(testdir): + +def test_trial_testfunction_skip_property(testdir): + pytest.importorskip('twisted.trial.unittest') testpath = testdir.makepyfile(""" - import unittest + from twisted.trial import unittest class MyTestCase(unittest.TestCase): def test_func(self): pass @@ -333,6 +336,32 @@ reprec.assertoutcome(skipped=1) +def test_trial_testcase_todo_property(testdir): + pytest.importorskip('twisted.trial.unittest') + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + todo = 'dont run' + def test_func(self): + assert 0 + """) + reprec = testdir.inline_run(testpath, "-s") + reprec.assertoutcome(skipped=1) + + +def test_trial_testfunction_todo_property(testdir): + pytest.importorskip('twisted.trial.unittest') + testpath = testdir.makepyfile(""" + from twisted.trial import unittest + class MyTestCase(unittest.TestCase): + def test_func(self): + assert 0 + test_func.todo = 'dont run' + """) + reprec = testdir.inline_run(testpath, "-s") + reprec.assertoutcome(skipped=1) + + class TestTrialUnittest: def setup_class(cls): cls.ut = pytest.importorskip("twisted.trial.unittest") diff -Nru pytest-2.4.2/tox.ini pytest-2.5.1/tox.ini --- pytest-2.4.2/tox.ini 2013-10-04 12:12:40.000000000 +0000 +++ pytest-2.5.1/tox.ini 2013-12-17 08:00:02.000000000 +0000 @@ -1,21 +1,21 @@ [tox] distshare={homedir}/.tox/distshare -envlist=py25,py26,py27,py27-nobyte,py32,py33,py27-xdist,trial +envlist=flakes,py26,py27,pypy,py27-pexpect,py33-pexpect,py27-nobyte,py32,py33,py27-xdist,py33-xdist,trial [testenv] changedir=testing commands= py.test --lsof -rfsxX --junitxml={envlogdir}/junit-{envname}.xml [] deps= - pexpect nose [testenv:genscript] changedir=. commands= py.test --genscript=pytest1 -[testenv:py25] -setenv = - PIP_INSECURE=1 +[testenv:flakes] +changedir= +deps = pytest-flakes>=0.2 +commands = py.test --flakes -m flakes _pytest testing [testenv:py27-xdist] changedir=. @@ -27,6 +27,28 @@ py.test -n3 -rfsxX \ --junitxml={envlogdir}/junit-{envname}.xml testing +[testenv:py33-xdist] +changedir=. +basepython=python3.3 +deps={[testenv:py27-xdist]deps} +commands= + py.test -n3 -rfsxX \ + --junitxml={envlogdir}/junit-{envname}.xml testing + +[testenv:py27-pexpect] +changedir=testing +basepython=python2.7 +deps=pexpect +commands= + py.test -rfsxX test_pdb.py test_terminal.py test_unittest.py + +[testenv:py33-pexpect] +changedir=testing +basepython=python2.7 +deps={[testenv:py27-pexpect]deps} +commands= + py.test -rfsxX test_pdb.py test_terminal.py test_unittest.py + [testenv:py27-nobyte] changedir=. basepython=python2.7 @@ -41,7 +63,6 @@ [testenv:trial] changedir=. deps=twisted - pexpect commands= py.test -rsxf \ --junitxml={envlogdir}/junit-{envname}.xml {posargs:testing/test_unittest.py} @@ -50,14 +71,6 @@ commands=py.test --doctest-modules _pytest deps= -[testenv:py32] -deps= - nose - -[testenv:py33] -deps= - nose - [testenv:doc] basepython=python changedir=doc/en @@ -97,7 +110,7 @@ minversion=2.0 plugins=pytester #--pyargs --doctest-modules --ignore=.tox -addopts= -rxs +addopts= -rxsX rsyncdirs=tox.ini pytest.py _pytest testing python_files=test_*.py *_test.py testing/*/*.py python_classes=Test Acceptance