Compare commits

...

1759 Commits
2.3.5 ... 2.8.2

Author SHA1 Message Date
Florian Bruhin
7c529e0afe Merge branch '2.8.2-release' 2015-10-07 17:51:34 +02:00
Florian Bruhin
b955473533 Add 2.8.2 release annoucement. 2015-10-06 22:37:59 +02:00
Florian Bruhin
2026ce0ed2 Update plugin_index. 2015-10-06 22:35:16 +02:00
Florian Bruhin
42937d4bb6 Prepare 2.8.2 release. 2015-10-06 21:06:25 +02:00
Bruno Oliveira
cfd259ae6f Merge pull request #1113 from demianbrecht/typo_fix
typo fix, changed position of context manager notes
2015-10-05 17:21:59 -03:00
Demian Brecht
493530ec6d typo fix, changed position of context manager notes 2015-10-05 12:13:25 -07:00
Florian Bruhin
4dea0892cb Merge pull request #1108 from nicoddemus/plugins_index
plugins_index was still generating ".txt" files, so it was effectively being ignored
2015-10-05 09:37:31 -07:00
Bruno Oliveira
9deab6c0fd Add a reminder on HOWTORELEASE to update plugins_index 2015-10-02 19:44:00 -03:00
Bruno Oliveira
f9e9413f52 plugins_index was still generating ".txt" files, so it was effectively being ignored
Fix #1105
2015-10-02 19:21:55 -03:00
Bruno Oliveira
5171d167ce Move "note" to the end of the main text
Fix #1097
2015-10-02 18:14:17 -03:00
Demian Brecht
2981bece55 pyflakes fix 2015-10-02 13:03:43 -07:00
Demian Brecht
fd211bf490 Add a note about usage of the context manager
Addesses #1097
2015-10-02 12:40:58 -07:00
Ronny Pfannschmidt
9263b3a051 Merge pull request #1096 from hackebrot/update-docs-skip-with-cli-option
Update docs skip with cli option
2015-10-01 18:31:55 +02:00
holger krekel
88209c6ac6 Merge pull request #1092 from nicoddemus/param-ids-fix
Param ids fix
2015-10-01 15:09:11 +02:00
Ronny Pfannschmidt
688f955f5e Merge pull request #1058 from nicoddemus/doc-how-disable-cache
Add docs on how to disable cache provider
2015-10-01 13:06:02 +02:00
Bruno Oliveira
f3cee8f0b5 Merge remote-tracking branch 'upstream/master' into param-ids-fix 2015-10-01 07:58:55 -03:00
Ronny Pfannschmidt
b7fd3f0031 Merge pull request #1093 from nicoddemus/relto-bug
Fix internal error when filtering tracebacks where one entry was generated by an exec() statement
Fixes #995
2015-10-01 06:00:40 +02:00
Bruno Oliveira
d1e00f6e19 Detect dynamic code explicitly in filter_traceback 2015-09-30 17:32:49 -03:00
Bruno Oliveira
c9480c5b8b Move imports outside _escape_bytes as suggested in review 2015-09-30 17:02:19 -03:00
Raphael Pierzina
4829eac1e1 Use a variable for the skipif marker as suggested by @nicoddemus 2015-09-30 21:53:34 +02:00
Raphael Pierzina
a10da0e540 Implement skipif marker for slow test based on pytest.config 2015-09-30 19:41:47 +02:00
Raphael Pierzina
7ac8a88a05 Remove pytest_runtest_setup from conftest.py 2015-09-30 19:25:57 +02:00
Bruno Oliveira
639ae0cfe0 Merge pull request #1095 from ionelmc/fix-hook-docs
Correct hook examples in docs.
2015-09-30 11:28:43 -03:00
Ionel Cristian Mărieș
c8f5a40fd9 Edit examples again to use hookimpl. 2015-09-30 16:58:12 +03:00
Ionel Cristian Mărieș
f4f23e8e09 Correct hook examples in docs. 2015-09-30 16:12:33 +03:00
Florian Bruhin
dc9ad12182 Merge pull request #1094 from nicoddemus/cache-fixture-docstring-fix
fix docstring for cache fixture regarding ``/`` on keys
2015-09-30 06:02:38 +02:00
Bruno Oliveira
a808e09204 fix docstring for cache fixture regarding `/` on keys 2015-09-30 00:27:52 -03:00
Bruno Oliveira
6ae16eba36 add entries for #1085 and #1087 to the CHANGELOG 2015-09-29 22:37:11 -03:00
Bruno Oliveira
11f100813e Fix internal error when filtering tracebacks where one entry was generated by an exec() statement
Fix #995
2015-09-29 22:29:43 -03:00
Bruno Oliveira
b64470443f Fix SystemError when using unicode_escape on Python 3
Fix #1087
2015-09-29 18:20:30 -03:00
Bruno Oliveira
8633c4cefd Fix encoding errors for parametrized tests with unicode parameters in py2
Fix #1085
2015-09-29 17:57:49 -03:00
Florian Bruhin
e9240f7eee Merge pull request #1090 from RonnyPfannschmidt/fix-flaky-getusertest
fix flaky get_user fallback tests
2015-09-29 21:35:45 +02:00
Ronny Pfannschmidt
04deea3c6d fix flaky get_user fallback tests 2015-09-29 21:00:12 +02:00
Bruno Oliveira
6ca8923ec7 Merge pull request #1088 from hpk42/docfix
remove unclear todo that irritates in the online docs
2015-09-29 13:26:54 -03:00
holger krekel
e3562be530 remove unclear todo that irritates in the online docs 2015-09-29 18:23:44 +02:00
holger krekel
c5fd42b699 start 2.8.2 development 2015-09-29 15:32:33 +02:00
holger krekel
afdbb6b17a Merge pull request #1084 from hpk42/branch-281
2.8.1 release
2015-09-29 15:19:07 +02:00
holger krekel
a0076460db avoid pullrequest picture and fix bugfix/feature target info.
I could not get the pullrequest picture to be included correctly
in both latex and html sphinx builders due to the "include" directive
from doc/en/contributing.rst
2015-09-29 13:48:38 +02:00
holger krekel
787c866191 hide some parts from generating latexpdf 2015-09-29 13:37:30 +02:00
holger krekel
95245b935c - fix a flaky test on py35-xdist by calling
importlib.invalidate_caches()

- bump version to 2.8.1

- regen docs

- amend changelog, authors
2015-09-29 13:10:59 +02:00
holger krekel
f61f39efdd Merge pull request #1052 from The-Compiler/no-std-prefix
Don't hardcode 'std' for captured stdout/stderr.
2015-09-29 09:19:40 +02:00
holger krekel
a73d517bee Merge pull request #1080 from vodik/master
fix #1034: Add missing nodeid on pytest_logwarning call in addhook.  Thanks Simon Gomizelj for the PR.
2015-09-29 09:07:43 +02:00
Simon Gomizelj
b3727438d6 Add missing nodeid on pytest_logwarning call in addhook.
Otherwise KeyError: 'nodeid' gets thrown, killing pytest. This may fix
issue 1034, but the details of it may be caused by something similar
somewhere else.
2015-09-28 20:23:54 -04:00
Bruno Oliveira
b184f391c6 Show known environment variables in py.test --help 2015-09-28 18:34:16 -03:00
Bruno Oliveira
5f860181b6 Remove print left by accident 2015-09-28 18:25:20 -03:00
Bruno Oliveira
6caa7083db Moved more detailed options on how to disable a plugin to plugins.rst 2015-09-28 18:23:08 -03:00
holger krekel
839909f3f6 Merge pull request #1081 from hunse/fix-pendingdep
`deprecated_call` detects pending warnings again
2015-09-28 19:05:44 +02:00
Eric Hunsberger
4194c9cce2 Check deprecated_call specific to deprecation
`deprecated_call` used to accept any warning. As of #897, it
is now specific to DeprecationWarnings, and another commit in
this PR extends this to PendingDeprecationWarnings. This commit
makes sure this stays the case.
2015-09-28 12:35:24 -04:00
Eric Hunsberger
e8261e0c77 deprecated_call detects pending warnings again
`deprecated_call` now looks for PendingDeprecationWarnings,
as it did previously but was broken by #897. Fixes #1037.

Also added a test so this does not happen again.
2015-09-28 12:11:52 -04:00
Ronny Pfannschmidt
22e1f4946e Merge pull request #1079 from hpk42/issue1073
fix issue #1073 -- shortcut plugin hook lookup if the attrname is not prefixed with pytest_.
2015-09-28 16:15:42 +02:00
holger krekel
971ebcbd77 simplify by removing the single-call "exclude_pytest_names" function 2015-09-28 15:43:55 +02:00
holger krekel
03aca9ea79 add changelog entry for fix #1073 2015-09-28 14:17:58 +02:00
holger krekel
1c0ffc5caf seems like pypy's callable builtin calls __getattr__ so we do the check
later.
2015-09-28 14:02:30 +02:00
holger krekel
4e3a807733 fix issue #1073 -- shortcut plugin hook lookup if the attrname is not
prefixed with pytest_.
2015-09-28 13:34:28 +02:00
holger krekel
d29084ec2c add changelog note for fix #704 2015-09-28 11:45:51 +02:00
holger krekel
c5faa00ace Merge pull request #1077 from nicoddemus/pluggy-0.3.1
Vendor pluggy-0.3.1
2015-09-28 11:44:07 +02:00
Bruno Oliveira
910b25d416 Vendor pluggy-0.3.1
Fix #704
2015-09-27 16:04:29 -03:00
Ronny Pfannschmidt
cb4b5bd684 Merge pull request #1072 from nicoddemus/use-more-py35-tox
Use py35 as preferred py3 interpreter for special test environments
2015-09-26 09:26:16 +02:00
Ronny Pfannschmidt
842aa5746f Merge pull request #1069 from nicoddemus/docs-contents-reorg
Reorganize "Contents" page
2015-09-26 09:18:42 +02:00
Ronny Pfannschmidt
c2c2451788 Merge pull request #1071 from nicoddemus/xml-xdist
Wrong xml report when used with pytest-xdist
2015-09-26 09:05:25 +02:00
Bruno Oliveira
cd7ca3de68 Test py27-xdist and py35 environments on AppVeyor 2015-09-26 03:46:03 -03:00
Bruno Oliveira
d52d0251b2 Test py35 on AppVeyor 2015-09-26 03:44:12 -03:00
Bruno Oliveira
cdead1a991 Update travis with new tox environments 2015-09-26 03:43:37 -03:00
Bruno Oliveira
031a20699c Use py35 as preferred py3 interpreter for special test environments 2015-09-26 03:37:21 -03:00
Bruno Oliveira
e4b18ea5c3 Update CHANGELOG 2015-09-26 03:28:30 -03:00
Bruno Oliveira
b72c3310bc Add note on docs about record_xml_property not working with xdist 2015-09-26 03:24:07 -03:00
Bruno Oliveira
748da0e5d7 Fix xml generation when used with pytest-xdist
pytest_runtest_logreport must be careful to not depend on setup/call/teardown
being called sequentially in that order, as xdist will call them as they are reported
from the slaves

Fix #1064
2015-09-26 03:21:24 -03:00
Bruno Oliveira
bc501a28af Merge pull request #1070 from oleg-alexandrov/master
Documentation clarification
2015-09-26 03:16:44 -03:00
Oleg Alexandrov
9d2d2d17af Clarify documentation
Fix doc markup
2015-09-25 21:46:06 -07:00
Bruno Oliveira
b403395cdb Reorganize "Contents" page
Change the organization in a more logical way to a newcomer
2015-09-26 01:09:50 -03:00
Bruno Oliveira
fbce3bb48f Small format fixes in HOWTORELEASE 2015-09-25 23:10:35 -03:00
Ronny Pfannschmidt
bf23a0f4b8 Merge pull request #1065 from The-Compiler/doc-fixes
Doc fixes
2015-09-25 19:18:09 +02:00
Florian Bruhin
448ec8b740 Mark sources correctly in parametrize.rst.
Sphinx didn't pick this up as monospace text.
2015-09-25 18:43:33 +02:00
Florian Bruhin
272f987b0c Fix test_time in parametrize doc.
The source was indented with a mixture of tabs and spaces, causing syntax
errors when executed.
2015-09-25 18:42:06 +02:00
Florian Bruhin
0ebac22bb2 Regenerate fixture list doc with cache docstring. 2015-09-25 18:41:07 +02:00
Bruno Oliveira
c55e42f856 Merge pull request #1063 from timstaley/docs-module-level-fixtures-pytestmark
Docs: Fixtures page - clarify usage of module-level pytestmark.
2015-09-25 12:42:35 -03:00
Tim Staley
eb2caa554c Docs: Fixtures page - clarify usage of module-level pytestmark.
It certainly wasn't clear to me that the variable assigned by
pytest.mark.usefixtures should also be called pytestmark,
so I was confused when::

  foo = pytest.mark.usefixtures('fixture_bar')

wasn't behaving as expected; correct usage is of course::

  pytestmark = pytest.mark.usefixtures('fixture_bar')

I assume this is by design, otherwise that's a separate issue, at
least current behaviour should be documented.
2015-09-25 14:57:08 +01:00
Florian Bruhin
7c5d2ea81d Merge pull request #1046 from RonnyPfannschmidt/docs
fix documentation regeneration, kill Makefile
2015-09-25 08:35:18 +02:00
Bruno Oliveira
b09d3724a0 Add docs on how to disable cache provider 2015-09-23 19:15:44 -03:00
Ronny Pfannschmidt
acb6b186f2 Merge pull request #1056 from icemac/patch-1
Remove duplicate line.
2015-09-23 09:10:20 +02:00
Ronny Pfannschmidt
a3fdcd9b17 Merge pull request #1031 from pytest-dev/unmarshable-parametrize
Parametrized values containing non-ascii bytes break cache
2015-09-23 09:03:51 +02:00
Ronny Pfannschmidt
e5c76cb22d Merge pull request #1054 from nicoddemus/cache-fixture-docstring
Add docstring to cache fixture
2015-09-23 09:00:01 +02:00
Michael Howitz
730114d088 Remove duplicate line. 2015-09-23 08:53:13 +02:00
Florian Bruhin
c0c685a5de Merge pull request #1055 from nicoddemus/fix-help-pytest-warnings
(w)warnings -> (w)pytest-warnings in "-r chars" help
2015-09-23 06:53:46 +02:00
Bruno Oliveira
79ebca3f30 (w)warnings -> (w)pytest-warnings in "-r chars" help 2015-09-23 01:09:09 -03:00
Bruno Oliveira
25d2cc4604 Add docstring to cache fixture
Fixes #1049
2015-09-22 23:46:05 -03:00
Bruno Oliveira
716fa97fa1 Update CHANGELOG 2015-09-22 23:21:36 -03:00
Bruno Oliveira
e1063678f1 escape bytes when creating ids for parametrized values 2015-09-22 23:18:09 -03:00
Bruno Oliveira
661495e5c5 Write failing test for parametrized tests with unmarshable parameters
Related to #1030; committing directly to pytest repository to
get feedback from others on how to proceed.
2015-09-22 23:18:07 -03:00
Bruno Oliveira
9d1ae0a149 Merge pull request #1048 from RonnyPfannschmidt/pytest-1029
fixes #1029 by handling access errors for cache dirs as pytest warning
2015-09-22 19:04:04 -03:00
Ronny Pfannschmidt
7f776fe19a skip chmod using cache access warning tests on windows 2015-09-22 20:49:11 +02:00
Florian Bruhin
c10f483b9f Don't hardcode 'std' for captured stdout/stderr.
This will make Item.add_report_sect more usable for plugins.
See https://github.com/eisensheng/pytest-catchlog/pull/7
2015-09-22 20:29:16 +02:00
Ronny Pfannschmidt
ea9a491fb3 add an acceptance test for cache write errors 2015-09-22 20:24:37 +02:00
holger krekel
ca460e11e6 Merge pull request #1051 from Akasurde/issue_1027
Added minor documentation change in python.py
2015-09-22 17:09:25 +02:00
Ronny Pfannschmidt
c3588b545f generate docs on python3.4 2015-09-22 16:52:35 +02:00
Abhijeet Kasurde
dc1ce51ac2 Added minor documentation change
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-09-22 20:15:49 +05:30
Ronny Pfannschmidt
6e51918353 update changelog 2015-09-22 16:33:27 +02:00
Bruno Oliveira
1d2afada83 Minor typo in CHANGELOG 2015-09-22 11:30:00 -03:00
Ronny Pfannschmidt
29f4da93d4 handle access errors when writing cache files silently as pytest warning, fixes #1039 2015-09-22 16:28:19 +02:00
Bruno Oliveira
5acbd7bc86 Fix git checkout command in CONTRIBUTING.rst 2015-09-22 10:54:37 -03:00
Ronny Pfannschmidt
5ff75a41ea fix erroring doc example 2015-09-22 15:05:56 +02:00
Ronny Pfannschmidt
89badfec0c update regendoc, substitutes PYTHON_PREFIX 2015-09-22 14:48:04 +02:00
Ronny Pfannschmidt
662d755974 fix documentation gegeneration, kill Makefile 2015-09-22 14:22:37 +02:00
holger krekel
bf9b94595c fix changelog 2015-09-22 11:18:19 +02:00
holger krekel
41d61ed221 Merge pull request #1023 from RonnyPfannschmidt/fix-877
Fix 877
2015-09-22 11:17:02 +02:00
holger krekel
e2f72ffed8 start bugfix changelog on master 2015-09-22 10:59:23 +02:00
Florian Bruhin
79c2abf531 Merge pull request #1038 from hpk42/newbranching
adapt contributing to new versioning and to python3.5 as latest.
2015-09-22 10:55:30 +02:00
holger krekel
a5ff345f7b fix another occurence of "macro" to "major" 2015-09-22 10:45:55 +02:00
holger krekel
f19ba6c2b1 fix naming 2015-09-22 10:29:12 +02:00
holger krekel
745cd26850 Merge branch 'master' into newbranching 2015-09-22 10:22:05 +02:00
holger krekel
71c5883d52 update according to discussion on pytest-dev and in PR 2015-09-22 10:21:01 +02:00
Floris Bruynooghe
c30eafa254 Update changelog for merged PR. 2015-09-21 14:59:48 +01:00
Floris Bruynooghe
7c3be72ac7 Merge pull request #1042 from Bjwebb/issue411
Add __eq__ method to assertion comparison example
2015-09-21 14:57:59 +01:00
Ben Webb
622e64320a Add __eq__ method to assertion comparison example
This makes the example make more sense, because now Foo(1) == Foo(1) is
true. Fixes #411
2015-09-21 14:23:26 +01:00
holger krekel
0efcfeed17 adapt contributing to new versioning and to python3.5 as latest. 2015-09-21 14:04:30 +02:00
Floris Bruynooghe
65de43e67d Mention fix for issue 766 in changelog
Fixes issue #766.
2015-09-21 12:21:24 +01:00
Floris Bruynooghe
cd4557cce8 Merge pull request #1036 from russel/rlw_766
Remove references to distutils as per Issue 766.
2015-09-21 12:19:14 +01:00
Russel Winder
714a97e452 Remove references to distutils as per Issue 766. 2015-09-21 12:00:48 +01:00
Floris Bruynooghe
80897f62a6 Merge pull request #974 from nicoddemus/addoption-conftest
Add warning about implementing pytest_addoption in conftest files
2015-09-21 11:28:31 +01:00
Floris Bruynooghe
dfd83b59f8 Merge pull request #1033 from mbirtwell/changes_to_contributing_rst
contributing: Add instructions from PyCon
2015-09-21 11:13:14 +01:00
Michael Birtwell
bb42e43ee7 contributing: Add instructions from PyCon
At PyCon we realised that the virtualenv created in the make file wasn't
used in the subsequent steps in CONTRIBUTING.rst. This change removes the
reference the make and suggesting installing tox directly.
Also changed the explanation that follows to make more sense with this
change
2015-09-21 10:56:05 +01:00
Bruno Oliveira
8fe5c704e3 Merge pull request #1024 from rouge8/tmpdir-uid-not-found
Make tmpdir resiliant to user ids that do not exist
2015-09-18 22:53:17 -03:00
Andy Freeland
b1c9b8b415 Make tmpdir resiliant to user ids that do not exist
Previously, the tmpdir fixture would fail if the current process's user
id does not correspond to a valid user (e.g. running pytest in a Docker
container with 'docker run -u').
2015-09-18 21:26:19 -04:00
Ronny Pfannschmidt
7658f60146 #877 - reencoding causes typeerrors on python2 2015-09-19 00:30:01 +02:00
Ronny Pfannschmidt
49c99a41ea reencode non-ascii python2 assertion reprs, fixes #877
i decided against using a warning since the problem goes away with python3
the support code can be removed once we drop python2 in 10 years or so
2015-09-19 00:30:01 +02:00
Bruno Oliveira
f02d9425f9 Bump version to 2.8.0 2015-09-18 19:04:20 -03:00
Ronny Pfannschmidt
1aca998f3f Merge pull request #1012 from lukas-bednar/junitxml_plugin
junitxml: align custom properties with junit format
2015-09-18 16:01:22 +02:00
holger krekel
2ba0fe2876 Merge pull request #1022 from nicoddemus/cxfreeze-tmpdir
Use temporary directory for cx_freeze testing
2015-09-18 09:28:33 +02:00
Bruno Oliveira
546093175e White list rm for cxfreeze env 2015-09-17 23:34:09 -03:00
Bruno Oliveira
e4d5f88257 Fix install cx_freeze 2015-09-17 23:32:27 -03:00
Bruno Oliveira
3a8e375efe Fix import 2015-09-17 14:52:51 -03:00
Bruno Oliveira
f5f3a2a928 Fix flaky failure about unused shutil 2015-09-17 12:54:02 -03:00
Bruno Oliveira
6bca5a1c25 Use temporary directory for cx_freeze testing 2015-09-17 11:54:44 -03:00
Lukas Bednar
02a2272cfe junitxml: move custom properties to properties element
<testsuite>
  <testcase>
    <properties>
      <property name="ABC" value="XYZ" />
      <property name="DEF" value="ZYX" />
    </properties>
  </testcase>
</testsuite>
2015-09-17 15:56:41 +02:00
Florian Bruhin
fe8def98e4 Merge pull request #1020 from hpk42/pluggy031
re-vendor pluggy to 0.3.1 release and also fix the README
2015-09-17 14:41:32 +02:00
holger krekel
f4bfd571ee re-vendor pluggy to 0.3.1 release and also fix the README 2015-09-17 13:54:23 +02:00
holger krekel (rather uses bitbucket/hpk42)
f32f3f1980 Merge pull request #1019 from mdboom/python3.5-docs
Various updates to the docs to mention support for Python 3.5
2015-09-17 13:45:35 +02:00
holger krekel
baf5b5d005 update changelog/author info, bump version number 2015-09-17 13:43:39 +02:00
holger krekel (rather uses bitbucket/hpk42)
3bcda48ba4 Merge pull request #1009 from mdboom/deprecation-warnings
avoid deprecation warnings, introduce helpers.
2015-09-17 13:37:26 +02:00
Michael Droettboom
16f90ffc92 Various Python 3.5 documentation mentions 2015-09-17 07:32:52 -04:00
Ronny Pfannschmidt
6520cf00e9 Merge pull request #1018 from hpk42/no_scm
revert setuptools_scm addition
2015-09-17 13:25:48 +02:00
holger krekel
7eb1211192 revert setuptools_scm addition introduced with f22d14b105 2015-09-17 12:58:04 +02:00
Florian Bruhin
f978b545c5 Merge pull request #1016 from hpk42/importappend3
revert importing test module behaviour to prepend by default
2015-09-17 12:41:28 +02:00
holger krekel
6192e74f03 remove __init__.py as advised by ronny 2015-09-17 10:51:03 +02:00
Michael Droettboom
7f71ce0ab2 Reorganize tests 2015-09-16 16:52:37 -04:00
holger krekel
a62d12634c revert importing test module behaviour to prepend by default 2015-09-16 22:12:20 +02:00
holger krekel (rather uses bitbucket/hpk42)
886ac82c43 Merge pull request #1013 from nicoddemus/issue1010
Make tmpdir more resilient in case environment variables required by getpass are missing
2015-09-16 21:57:44 +02:00
Florian Bruhin
2575053697 Merge pull request #1015 from hpk42/cache-integration
refined pytest-cache integration
2015-09-16 21:46:46 +02:00
Bruno Oliveira
130e6cf8a2 Use temproot as a fallback if the current user couldn't be obtained 2015-09-16 16:42:07 -03:00
holger krekel
3841e99720 avoid oldstyle funcarg usage 2015-09-16 21:06:44 +02:00
holger krekel
79d22bf334 some more doc refinements 2015-09-16 20:44:41 +02:00
holger krekel
45065e4e2e refine command line option naming and docs 2015-09-16 20:41:22 +02:00
Bruno Oliveira
558e5406e8 test_get_user should execute on windows only 2015-09-16 13:06:39 -03:00
Bruno Oliveira
1150e87e31 Extract get_user logic into a separate function 2015-09-16 12:47:50 -03:00
Bruno Oliveira
6676aeda5a Make tmpdir more resilient in case environment variables required by getpass are missing
Fix #1010
2015-09-16 12:20:07 -03:00
holger krekel
9a90aaca96 improve and integrate docs 2015-09-16 17:15:31 +02:00
Michael Droettboom
bf74401fd3 Use __code__.co_argcount 2015-09-16 11:05:54 -04:00
Michael Droettboom
9a84c9edb6 Add tests for argument formatting 2015-09-16 11:02:48 -04:00
Michael Droettboom
08a572086b Fix lookup of special values 2015-09-16 11:02:36 -04:00
Bruno Oliveira
2093889ac2 Merge pull request #1011 from hpk42/master
merge latest pytest-2.7 changes
2015-09-16 11:22:05 -03:00
Michael Droettboom
9c19728d2b Fix checking for args 2015-09-16 06:45:51 -04:00
Michael Droettboom
859259ddae Simplify 2015-09-16 06:43:16 -04:00
Michael Droettboom
a0cefb3213 Use inspect.signature instead of inspect.getargspec 2015-09-16 06:33:53 -04:00
holger krekel
fdd23878ec Merge latest changes from branch 'pytest-2.7'
Conflicts:
	_pytest/__init__.py
	doc/en/fixture.rst
	setup.cfg
	testing/test_runner.py
2015-09-16 09:26:55 +02:00
Floris Bruynooghe
b4c47c0ac0 Merge pull request #1006 from hpk42/pytest-2.7
some fixes, streamlines to get 2.7.3 out the door
2015-09-15 11:37:38 +01:00
holger krekel
5af262daa3 fix flakes problem, configure devpi upload to always upload wheels and sdist 2015-09-15 12:28:09 +02:00
holger krekel
16720b96b4 fix a few issues with pytest-2.7 branch and bump version number
- importorskip: skip a test if we have a minversion but cannot parse
  version numbers due to pkg_resources not present
- make runner tests work with latest xdist
2015-09-15 12:17:52 +02:00
Bruno Oliveira
b2b003dcac Merge pull request #1001 from RonnyPfannschmidt/exitcode-refactor
restrucure pytest.main.wrap_session to allow for non-testrun wraps
2015-09-14 15:56:04 -03:00
Ronny Pfannschmidt
c5bf148ed7 Merge pull request #959 from nicoddemus/vendor-pluggy
Vendor pluggy
2015-09-14 18:37:52 +02:00
Ronny Pfannschmidt
81018f1996 restrucure pytest.main.wrap_session to allow for non-testrun wraps 2015-09-14 18:34:29 +02:00
Bruno Oliveira
a13f23d218 Merge branch 'master' into vendor-pluggy 2015-09-14 12:22:18 -03:00
Anatoly Bubenkov
6d5641afce Merge pull request #999 from nicoddemus/fix-appveyor
Use pip and tox from py27 in appveyor
2015-09-14 17:20:46 +02:00
Bruno Oliveira
9396489b4c Remove unused run_with_env script 2015-09-14 11:28:07 -03:00
Ronny Pfannschmidt
2eb3bdf132 Merge pull request #998 from nicoddemus/py35
Use python "3.5" on travis
2015-09-14 16:16:42 +02:00
Bruno Oliveira
a0dd478637 Use pip and tox from py27 in appveyor 2015-09-14 10:59:10 -03:00
Bruno Oliveira
1d1eac4c6b Use python "3.5" on travis 2015-09-14 10:36:20 -03:00
Bruno Oliveira
d6bb5cb6c1 Ignore vendored_packages folder for coverage purposes 2015-09-14 10:30:58 -03:00
Bruno Oliveira
d79c89beba Merge pull request #997 from RonnyPfannschmidt/monkeypatch-cleanup
monkeypatch: ensure the internal _savesyspath attribute always exists
2015-09-14 10:25:09 -03:00
Ronny Pfannschmidt
2cfc183029 monkeypatch: ensure the internal _savesyspath attribute always exists 2015-09-14 07:42:23 +02:00
Ronny Pfannschmidt
e0645564fe more pep8 fixes 2015-09-13 21:49:01 +02:00
Ronny Pfannschmidt
cd475c7b27 minor flake8 fixes 2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
c06ff2a992 update docs on the json usage of builtin cache 2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
1e107e6bd1 restrucure pytest.main.wrap_session to allow for non-testrun wraps 2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
3d843edc69 minor doc reference fixes 2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
2e87cf4a62 create the previously missing cache fixture
there was a disabled test
2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
1de38a25fc use flake8 in the flakes testenv
and extend the ignored errors list so pytest is clean
we def have to trim down that one
2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
e035f57535 s/--cache/--show-cache/ 2015-09-13 19:55:44 +02:00
Ronny Pfannschmidt
e20216a1a8 merge the pytest-cache plugin into core 2015-09-13 19:55:44 +02:00
Bruno Oliveira
c7888d1d97 Add note in changelog about issue 960 2015-09-12 11:17:50 -03:00
Bruno Oliveira
41d2faccea Merge branch 'issue_960' of https://github.com/Akasurde/pytest 2015-09-12 10:57:23 -03:00
Abhijeet Kasurde
dd69394598 Added testcase and help for report option
Fix added to show help of new reporting option 'a'.
Also, added testcase for checking reporting functionality
with option 'a'.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-09-11 12:24:45 +05:30
Abhijeet Kasurde
c40947e651 Added fix for specifying every option for reporting
The fix will add option 'a' to reporting which will ease task of
adding all options or reporting at once.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-09-10 15:43:43 +05:30
Bruno Oliveira
b6f876e721 Fix --target parameter for pip install 2015-09-07 14:13:41 -03:00
Bruno Oliveira
5a1c679f78 Keep *dist-info directory on vendored_packages 2015-09-07 14:09:59 -03:00
Bruno Oliveira
0b3f1b4a7c Create _pytest.vendored_packages and _pytest._pluggy
- Replace imports from "pluggy" to "_pytest._pluggy"
- Fallback to import "pluggy" from global namespace if
  not found in _pytest.vendored_packges
2015-09-07 13:01:54 -03:00
Bruno Oliveira
e622975ffd Merge pull request #987 from benauthor/master
Document single-method usage
2015-09-04 17:24:15 -03:00
Evan Bender
6ffb659282 Document single-method usage
It is possible to run a single test method in a class, but the syntax is
not glaringly obvious and documentation would help people out.
2015-09-04 15:11:57 -04:00
Bruno Oliveira
8625eb643e Merge pull request #986 from RonnyPfannschmidt/early-logging
replay initial warnings when terminalreporter is loaded
2015-09-02 19:10:53 -03:00
Ronny Pfannschmidt
76f0988551 turn the pytest_logwarning hook historic 2015-09-02 18:49:49 +02:00
Ronny Pfannschmidt
348e519437 Merge pull request #962 from nicoddemus/doctest-skip
Make doctest SKIP option register doctests as SKIPPED rather than PASSED
2015-09-01 12:31:35 +02:00
Ronny Pfannschmidt
7292212d5a Merge pull request #976 from nicoddemus/ren-warnings-on-terminal
Rename "warnings" to "pytest-warnings" in terminal output
2015-09-01 07:56:42 +02:00
Bruno Oliveira
4ad56e84a8 Make doctest SKIP option register doctests as SKIPPED rather than PASSED
Fix 957
2015-08-31 21:25:11 -03:00
Bruno Oliveira
e3734ef337 Add CHANGELOG entry about renaming "warnings" to "pytest-warnings" 2015-08-31 21:21:29 -03:00
Bruno Oliveira
06a70b6d6d Merge pull request #982 from codewarrior0/patch-1
Add notes to docstring of `monkeypatch.undo()`
2015-08-31 21:18:53 -03:00
Ronny Pfannschmidt
3fa261564b replay initial warnings when terminalreporter is loaded 2015-08-31 21:54:12 +02:00
Anatoly Bubenkov
18d175708c Merge pull request #983 from The-Compiler/issue-979
Fix overriding of fixtures with parametrization.
2015-08-31 15:21:45 +02:00
Florian Bruhin
19791546da Add docstring. 2015-08-31 15:11:57 +02:00
Florian Bruhin
885e461ae3 Fix overriding of fixtures with parametrization.
Fixes #979, see #926.
2015-08-31 14:38:39 +02:00
David Vierra
3a27cd87ce Adjust phrasing in monkeypatch.undo docstring
s/test invocation/test function invocation/
2015-08-29 19:00:00 -10:00
David Vierra
6380e19f07 Add notes to docstring of monkeypatch.undo()
Note that calling `undo()` is generally not needed, and describe the "gotcha" discovered in #981.
2015-08-29 16:53:57 -10:00
Bruno Oliveira
c0eec5d61c Merge pull request #975 from nicoddemus/fix-regression-parse-known-args
Fix regression caused by changing the signature for parse_known_args
2015-08-29 23:44:32 -03:00
Brianna Laugher
c493f263b6 Merge branch 'Elizaveta239-master' closes #908 2015-08-29 17:34:35 +10:00
Floris Bruynooghe
553aef57aa Merge pull request #978 from nicoddemus/string-diff
Show a few diff lines when truncating string diffs
2015-08-28 09:04:39 +01:00
Florian Bruhin
9f30ae9850 Merge pull request #977 from nicoddemus/marks-fixtures-note
Add note that using marks on fixtures is not supported
2015-08-28 06:16:49 +02:00
Bruno Oliveira
dd7112d5ea Show a few diff lines when truncating string diffs
Fix #934
2015-08-27 22:20:13 -03:00
Brianna Laugher
b49bedcf0c Merge branch 'master' of git://github.com/Elizaveta239/pytest into Elizaveta239-master 2015-08-28 11:10:22 +10:00
Bruno Oliveira
87cb5bc5b7 Add note that using marks on fixtures is not supported
Fix #964
2015-08-27 20:11:18 -03:00
Bruno Oliveira
e59471766a Rename "warnings" to "pytest-warnings" in terminal output
Fix #970
2015-08-27 19:59:52 -03:00
Bruno Oliveira
4533a50542 Fix regression caused by changing the signature for parse_known_args
Fix #973
2015-08-27 19:35:32 -03:00
Bruno Oliveira
ccf7584fac Add warning about implementing pytest_addoption from conftest files 2015-08-27 19:14:56 -03:00
Bruno Oliveira
06b1b69fb7 Merge pull request #963 from nicoddemus/cookiecutter-docs
Mention cookie-cutter in the docs and fix broken links to <extplugin>
2015-08-26 16:41:56 -03:00
Bruno Oliveira
333cb27272 Merge pull request #961 from nicoddemus/args-after-options
Paths after normal options are now properly used to discover rootdir and ini files
2015-08-26 12:50:19 -03:00
Bruno Oliveira
d988d2006f Mention cookie-cutter in the docs and fix broken links to <extplugin> 2015-08-25 23:59:18 -03:00
Bruno Oliveira
42b43a7d7b Paths after normal options are now properly used to discover rootdir and ini files
Fix #949
2015-08-25 22:08:05 -03:00
elizabeth
e67d66a5d4 Merge branch 'pytest-dev'
# Conflicts:
#	AUTHORS
2015-08-24 22:55:11 +03:00
Ronny Pfannschmidt
b25e41e348 Merge pull request #956 from nicoddemus/record-xml-property
add preliminary support for extended junit xml properties
2015-08-24 09:13:04 +02:00
Bruno Oliveira
70da93145d Improve docs and using warning system for record_xml_property fixture 2015-08-23 11:56:27 -03:00
Bruno Oliveira
a20c6d072d Fix getdoctarget to ignore comment lines 2015-08-23 11:20:34 -03:00
elizabeth
06585f5bdd Always report error about parametrize data that doesn't correspond to fixtures in test functions. 2015-08-23 13:42:40 +03:00
David Diaz
44d9365da0 Add warning of "preliminary feature" to record_xml_property 2015-08-21 15:21:12 -06:00
David Diaz
2ddbac1f98 Correcting implementation based on pull request feed back 2015-08-21 14:31:53 -06:00
Ronny Pfannschmidt
287df16c9c Merge pull request #817 from nicoddemus/non-collection-exit-error
return non-zero exit code if no tests are collected
2015-08-21 18:30:57 +02:00
Bruno Oliveira
5f0e92a432 Merge pull request #942 from RonnyPfannschmidt/adapt-print
Adapt plugin name printing
2015-08-21 12:02:58 -03:00
Bruno Oliveira
d7d418cd47 Fix forked_run_report in pytest.xdist 1.13 2015-08-20 21:17:27 -04:00
David Diaz
24212fd97f Add support to record custom properties on xml output 2015-08-20 17:55:38 -06:00
Bruno Oliveira
3e41c3cbb3 Using packages from pypi 2015-08-18 09:19:51 -03:00
Bruno Oliveira
359f248729 Force to use xdist >= 1.13 2015-08-18 07:35:03 -03:00
Bruno Oliveira
f730291904 Make testsfailed and testscollected public Session attributes
As suggested by @flub in review
2015-08-18 07:35:02 -03:00
Bruno Oliveira
2ffd37b816 return non-zero exit code if no tests are collected
Fix #812
Fix #500
2015-08-18 07:35:02 -03:00
Ronny Pfannschmidt
7758bcd141 terminalwriter: extract plugin printing logic and add positive unittests 2015-08-17 09:10:01 +02:00
Ronny Pfannschmidt
740a97a8cc terinalwriter: use dash between plugin name and version 2015-08-17 08:48:38 +02:00
Ronny Pfannschmidt
2c42f15e00 adapt plugin printing
* print each distribution only once(xdist now has 3 entrypoints)
* include the distribution version
2015-08-17 08:41:24 +02:00
Ronny Pfannschmidt
37ed391cc2 Merge pull request #938 from nicoddemus/doctest-unicode
New ALLOW_UNICODE doctest option
2015-08-16 11:35:10 +02:00
Floris Bruynooghe
f22d14b105 Merge pull request #879 from RonnyPfannschmidt/setuptools-scm
use setuptools_scm to determine the version
2015-08-15 00:56:16 +01:00
Bruno Oliveira
d749021a31 Fix coverage
Also make sure a test that doesn't set ALLOW_UNICODE fails
on Python 2 and passes Python 3.
2015-08-12 22:49:41 -03:00
Bruno Oliveira
93aee0f814 Add docs and CHANGELOG for ALLOW_UNICODE option 2015-08-12 22:17:15 -03:00
Bruno Oliveira
420823070b Add ALLOW_UNICODE doctest option
When enabled, the ``u`` prefix is stripped from unicode strings in
expected doctest output. This allows doctests which use unicode
to run in Python 2 and 3 unchanged.

Fix #710
2015-08-12 22:16:44 -03:00
Ronny Pfannschmidt
ddbdcab522 Merge pull request #937 from ctheune/patch-1
Fix accidental inversion in skip example.
2015-08-12 07:51:59 +02:00
Christian Theune
2174f3ce37 Fix accidental inversion in skip example. 2015-08-12 07:38:04 +02:00
Bruno Oliveira
73fdda0e45 Merge pull request #926 from untitaker/multifixture
Don't skip fixtures that are substrings of params
2015-08-10 21:12:51 -03:00
Markus Unterwaditzer
1d5215ab4f Add myself to authors 2015-08-11 00:47:18 +02:00
Markus Unterwaditzer
cafd71eb29 Update changelog for #926
Also fix some inconsistencies in the changelog on the way.
2015-08-11 00:47:18 +02:00
Markus Unterwaditzer
41cef6f5f2 Don't skip fixtures that are substrings of params
Bug introduced with
https://bitbucket.org/pytest-dev/pytest/pull-requests/257/allow-to-override-parametrized-fixtures

Fix #736
2015-08-11 00:41:21 +02:00
Bruno Oliveira
681e502c12 Use "union" merge strategy for CHANGELOG
Credits: @The-Compiler 😄
2015-08-10 19:27:22 -03:00
Ronny Pfannschmidt
bc509b42e8 Merge pull request #933 from nicoddemus/hasplugin
Reintroduce hasplugin to PytestPluginManager
2015-08-10 09:40:52 +02:00
Bruno Oliveira
e103932aad Reintroduce hasplugin to PytestPluginManager
Fix #932
2015-08-09 19:30:49 -03:00
Ronny Pfannschmidt
1c680210c2 Merge pull request #931 from nicoddemus/docs-hookwrapper
Change docs to use hookwraper instead of __multicall__
2015-08-09 09:22:31 +02:00
Ronny Pfannschmidt
eb989c8257 Merge pull request #921 from tomviner/issue562-noseistest
Issue #562 - Ensure @nose.tools.istest is respected
2015-08-09 07:54:19 +02:00
TomV
14625907ae update changelog 2015-08-09 00:11:16 +01:00
TomV
353360dbe5 use local isclass 2015-08-09 00:11:15 +01:00
TomV
3497aa0766 check nose.istest __test__ attr issue526 2015-08-09 00:11:15 +01:00
Bruno Oliveira
d49fb8a2d5 Change cx_freeze example to not use regendoc 2015-08-08 19:17:50 -03:00
Bruno Oliveira
e8583f01a0 Replaced __multicall__ examples in docs by hookwrapper
Fix #929
2015-08-08 19:07:27 -03:00
TomV
e130a0257d add test for @nose.tools.istest 2015-08-08 21:08:05 +01:00
Bruno Oliveira
729b5e9b2f Merge pull request #923 from The-Compiler/parametrize-idfunc
Generate parametrize IDs for enum/re/class objects.
2015-08-08 15:09:54 -03:00
Brianna Laugher
36b86af4b9 Added more test cases 2015-08-08 19:20:09 +02:00
Brianna Laugher
40fa7b25c5 Merge branch 'master' of git://github.com/Elizaveta239/pytest into Elizaveta239-master
Fixed merge conflict in CHANGELOG
2015-08-08 18:54:53 +02:00
Florian Bruhin
4e21d1d77b Move enum import and adjust comments. 2015-08-08 15:25:10 +02:00
Florian Bruhin
84fdba129a More style changes. 2015-08-08 12:57:54 +02:00
Bruno Oliveira
9ae40e393a Fix PR image link 2015-08-07 22:32:22 -03:00
Florian Bruhin
18125c7d1f Clean up type comparisons. 2015-08-07 23:10:22 +02:00
Florian Bruhin
03d8a6c05d Update CHANGELOG. 2015-08-07 23:08:22 +02:00
Brianna Laugher
fd4d35d9a2 Merge pull request #924 from The-Compiler/parametrise
Alert user about other parametrize spellings.
2015-08-07 13:32:04 +02:00
Florian Bruhin
91a29932a6 Add CHANGELOG entry. 2015-08-07 07:58:13 +02:00
Florian Bruhin
b59376bea4 Alert user about other parametrize spellings. 2015-08-07 07:51:59 +02:00
Florian Bruhin
13c5456868 Generate parametrize IDs for enum/re/class objects. 2015-08-07 07:37:59 +02:00
Bruno Oliveira
4f83586f55 Give credit where it is due in CHANGELOG 😄
Related to #890
2015-08-06 22:51:32 -03:00
Bruno Oliveira
77f54dbdae Merge pull request #915 from Akasurde/issue-890
Converted docs from txt to rst
2015-08-06 22:47:53 -03:00
Bruno Oliveira
2bbe709bce Use testdir fixture in test_double_test to ensure controlled environment for execution
Because the test relies that two subsequent tests try to use pytest.warns to capture
the exact same warning, it is better to use testdir to ensure test execution
occurs in the order we expect (which might be different with pytest-xdist or
pytest-random for example)
2015-08-06 22:30:01 -03:00
Eric Hunsberger
39f1471e93 Warnings always raised in WarningsRecorder
This ensures that if tests for warnings are run more than once,
the warning is still raised as expected.
2015-08-06 15:05:01 -04:00
Abhijeet Kasurde
ab9befb197 Updated CHANGELOG and AUTHORS 2015-08-05 15:21:37 +05:30
Abhijeet Kasurde
6d446e7167 Converted documentation from txt to rst 2015-08-05 10:24:14 +05:30
Bruno Oliveira
02e742b7a6 Move WarningsChecker import in test to a local import to workaround flakes issue
See #897 for discussion
2015-08-04 19:27:13 -03:00
Abhijeet Kasurde
185e730feb Added makefile changes for docs
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-08-04 18:44:52 +05:30
Abhijeet Kasurde
e79413acc4 Updated documentation from txt to rst
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-08-04 16:41:02 +05:30
Bruno Oliveira
d761bfffd7 Merge pull request #897 from hunse/warns
Warns
2015-08-03 22:48:20 -03:00
elizabeth
f7bacd169e Update docs 2015-08-04 00:48:41 +03:00
Bruno Oliveira
8fca4781f1 Merge pull request #910 from oleksmarkh/patch-1
fix docs folder name in HOWTORELEASE
2015-08-03 18:12:14 -03:00
elizabeth
657ca97dbd Some refactorings after code review 2015-08-04 00:02:03 +03:00
Oleksii Markhovskyi
3868b61443 fix docs folder name in HOWTORELEASE 2015-08-03 23:01:03 +02:00
Bruno Oliveira
c605cf92f9 Merge pull request #909 from flub/assertdoc
Update docs to represent reality
2015-08-02 18:53:47 -03:00
Floris Bruynooghe
b097d8c0a6 Update docs to represent reality
This was changed after EuroPython 2014, now both the message and the
introspection is presented.
2015-08-02 22:36:19 +01:00
elizabeth
db9809d6dc Update test for error in 'indirect' parameter 2015-08-02 23:53:44 +03:00
elizabeth
63bac67fb5 Add test for bad value in argument 'indirect' 2015-08-02 23:06:24 +03:00
elizabeth
54a3d6210b Update CHANGELOG and AUTHORS 2015-08-02 20:39:31 +03:00
elizabeth
15b865f502 Rewrite test using @pytest.fixture 2015-08-02 20:30:23 +03:00
elizabeth
9846953597 Support for python 2.6 2015-08-02 17:28:27 +03:00
elizabeth
2fc7aede0b Request #714: Apply indirect=True on particular argnames 2015-08-02 16:40:40 +03:00
Ronny Pfannschmidt
f6506fa6ca Merge pull request #907 from nicoddemus/regendocs-fixture
Use smtp.gmail.com server for examples and fixes examples for python 3
2015-07-31 06:55:08 +02:00
Eric Hunsberger
52b4eb6c46 Added warns to assert warnings are thrown
Works in a similar manner to `raises`, but for warnings instead
of exceptions. Also refactored `recwarn.py` so that all the
warning recording and checking use the same core code.
2015-07-30 23:28:32 -04:00
Eric Hunsberger
aac371cf07 Added myself to AUTHORS 2015-07-30 23:28:32 -04:00
Bruno Oliveira
4d8e3cbcb0 Use smtp.gmail.com server for examples and fixes examples for python 3
Examples in py3 where showing the wrong message:

    TypeError: Type str doesn't support the buffer API
2015-07-30 23:54:24 -03:00
Bruno Oliveira
7a918a1617 Fix regendoc section in fixture.txt
Noticed thanks to #903
2015-07-30 23:21:19 -03:00
Ronny Pfannschmidt
0b83b4076a Merge pull request #898 from nicoddemus/tmpdir-factory-new-name
Use pytest-of-$user as base directory for tmpdir_factory
2015-07-29 13:58:42 +02:00
Bruno Oliveira
4302972c23 Use pytest-of-$user as base directory for tmpdir_factory
Before tmpdir_factory, pytest used to create a link named "pytest-$user" to the current numbered directory. Use
 a different name so there's no conflict when running different pytest versions.

Fix #894
2015-07-28 20:57:48 -03:00
Ronny Pfannschmidt
235f9da432 special-case _pytest.__init__ in genscript to avoid a python3 bug 2015-07-27 11:33:27 +02:00
Bruno Oliveira
9cf9900721 Merge pull request #892 from The-Compiler/multi-parametrize
Document and test stacking of parametrize.
2015-07-26 21:00:29 -03:00
Bruno Oliveira
2035c5f8be Merge pull request #893 from pfctdayelise/dupereleaseguides
Delete duplicate release guide
2015-07-26 20:59:07 -03:00
Brianna Laugher
5ebad5c96d Delete release.txt from docs, merge extra comments to HOWTORELEASE.rst 2015-07-26 15:20:32 +02:00
Florian Bruhin
2ab4bf13ab Document and test stacking of parametrize.
Closes #815.
2015-07-26 14:39:13 +02:00
Ronny Pfannschmidt
5098e5fc47 fix version import 2015-07-26 14:04:52 +02:00
Brianna Laugher
017ceffb76 minor tweaks to CONTRIBUTING 2015-07-26 12:19:39 +02:00
Floris Bruynooghe
e69e785b23 Mention fix for issue #683 2015-07-26 12:15:29 +02:00
jakubo
e8f4819876 Test file run twice fails if it contains marked class #683 2015-07-26 12:15:29 +02:00
Brianna Laugher
985fd0cc2b Mention Contributors team by name in CONTRIBUTING 2015-07-26 12:07:50 +02:00
Floris Bruynooghe
97e5f7d7e9 Merge merge branch
I suspect I don't yet know how to use git...  Surely I don't need two
merges to merge a contribution.
2015-07-26 11:49:42 +02:00
Floris Bruynooghe
011565ca10 Add changelog entry for capture improvement 2015-07-26 11:42:33 +02:00
Floris Bruynooghe
e68fa641ff Merge reset-capgture-on-reeadouterr-errors
Merge branch 'reset-capture-on-readouterr-errors' of github.com:davidszotten/pytest into merge-capmerge
2015-07-26 11:39:03 +02:00
David Szotten
3e6bee2fc6 fail if snap is removed in the future 2015-07-26 01:28:00 +02:00
David Szotten
983d249680 reset capture even if readouterr throws
otherwise that exception (and all following output) end up in /dev/null
2015-07-26 01:15:51 +02:00
Floris Bruynooghe
8338c692a3 Merge pull request #887 from maartenq/753content_of
changed contents -> content but still #753 did not solved, might be i…
2015-07-25 19:11:53 +02:00
Floris Bruynooghe
f64d5f1209 Merge pull request #884 from cpommranz/deprecate_genscript
Deprecate and warn about --genscript, fixes #730
2015-07-25 19:09:52 +02:00
Floris Bruynooghe
f38c632635 Merge branch 'jb-fix-751' 2015-07-25 19:04:59 +02:00
Floris Bruynooghe
251fc68ef9 Merge fix for #751
Merge branch 'fix-751' of github.com:JanBednarik/pytest into jb-fix-751
2015-07-25 19:03:44 +02:00
Maarten
df8a83b2a1 changed contents -> content but still #753 did not solved, might be issues with regendoc 2015-07-25 17:48:12 +02:00
Jan Bednařík
0b92650494 Update changelog. 2015-07-25 16:25:29 +02:00
Jan Bednařík
9906a19e29 Issue #751 - fix. 2015-07-25 15:38:27 +02:00
Jan Bednařík
f78d87ee38 Issue #751 - test. 2015-07-25 15:38:11 +02:00
Christian Pommranz
00e1a2122a Deprecate and warn about --genscript, fixes #730 2015-07-25 15:10:22 +02:00
Floris Bruynooghe
80ee620459 Merge pull request #881 from maartenq/master
setuptools not present issue deprecating gentest
2015-07-25 15:03:50 +02:00
Floris Bruynooghe
023687d8d0 Merge pull request #872 from nicoddemus/confcutdir-inifile
Avoid detecting conftest files upwards from setup.cfg/pytest.ini/tox.ini by default
2015-07-25 14:03:24 +02:00
Maarten
e3d60024aa setuptools not present issue deprecating gentest 2015-07-25 13:50:40 +02:00
Ronny Pfannschmidt
a060b8ff73 use setuptools_scm to determine the version 2015-07-25 10:44:18 +02:00
Bruno Oliveira
ae28e4ba0f Merge remote-tracking branch 'upstream/pytest-2.7'
Conflicts:
	.travis.yml
2015-07-24 20:02:12 -03:00
Bruno Oliveira
92c61b0de3 Merge pull request #876 from takluyver/travis-reenable-35-pt27
Re-enable Python 3.5 testing on Travis
2015-07-24 19:59:43 -03:00
Thomas Kluyver
ed2c06c8cd Re-enable Python 3.5 testing on Travis
This is PR #875, but reissued against the pytest-2.7 branch.

According to the docs, it looks like this should work:
http://docs.travis-ci.com/user/languages/python/

I've explicitly specified beta 3, so it will need updating when future
betas come out. You could instead specify '3.5-dev', which would give
less need to update, but then it's less clear whether a change in status
is due to a change in pytest or in Python itself.
2015-07-24 15:50:45 -07:00
Bruno Oliveira
033def0a7a Workaround for cmdexec bug on Windows
This bug fails the entire pytest suite when executed with the
--lsof option in Python 2 on Windows.
2015-07-24 19:24:31 -03:00
Bruno Oliveira
9f94e443ff Merge remote-tracking branch 'upstream/pytest-2.7'
Conflicts:
	testing/conftest.py
2015-07-24 19:24:21 -03:00
Bruno Oliveira
91e8e59cea Merge pull request #860 from nicoddemus/warn-plugins-as-str-main
Make passing plugins as str objects a more obvious failure
2015-07-24 19:13:39 -03:00
Bruno Oliveira
4f1ae8c45e Workaround for cmdexec bug on Windows
This bug fails the entire pytest suite when executed with the
--lsof option in Python 2 on Windows.
2015-07-24 18:05:30 -03:00
Bruno Oliveira
b84fcbc85e Merge pull request #873 from hunse/fix-dev-versions
Allow non-integer version strings in `importorskip`
2015-07-24 16:08:15 -03:00
Eric Hunsberger
3cd19a7e45 Use monkeypatch for setting modules in tests
Instead of directly setting `sys.modules`. This ensures that they
get removed at the end of the test.
2015-07-24 12:34:06 -04:00
Eric Hunsberger
d104487282 importorskip: Allow non-integer version strings
Use `pkg_resources.parse_version` to parse version strings.
This can handle 'dev', 'rc', alpha and beta version strings,
among others.
2015-07-24 12:34:06 -04:00
Bruno Oliveira
35bbcc39a2 Interpret strings to "plugins" arg in pytest.main() as module names
See #855
2015-07-23 23:37:09 -03:00
Bruno Oliveira
ab9e246ab0 Avoid detecting conftest files upwards from setup.cfg/pytest.ini/tox.ini files by default
As discussed in #82
2015-07-23 23:21:07 -03:00
Bruno Oliveira
df29120abe Merge branch 'pytest-2.7'
Conflicts:
	_pytest/config.py
	_pytest/genscript.py
	_pytest/mark.py
	tox.ini
2015-07-23 22:35:51 -03:00
Bruno Oliveira
5a17e797c7 Fix basepython for tox envs "doctesting" and "coveralls"
Because we are currently using "nighly" python for travis, which
uses python 3.6 as the default interpreter. This breaks the environments
listed above because "inspect.getargspec" has been removed in py36.
2015-07-23 21:15:45 -03:00
Bruno Oliveira
ce96973ed5 Merge pull request #864 from pytest-dev/consider-color-yes-everywhere
Consider --color option in more places which deal with TerminalWriters
2015-07-23 08:03:52 -03:00
Bruno Oliveira
77844ec5f3 Fixed typo in CHANGELOG: "testdirs" -> "testpaths" 2015-07-22 12:14:49 -03:00
Floris Bruynooghe
0e26de2218 Merge pull request #867 from nicoddemus/autouse-yield-fixture-class
Fix autouse fixtures defined in a TestCase subclass
2015-07-22 01:25:21 +02:00
Bruno Oliveira
81f18f8a0f Fix flakes 2015-07-21 19:55:01 -03:00
Bruno Oliveira
0769bb4898 Make pastebin use _pytest.config.create_terminal_writer 2015-07-21 12:55:18 -03:00
Bruno Oliveira
31cfbac1f4 Fix autouse fixtures defined in a TestCase subclass 2015-07-20 19:28:54 -03:00
Anatoly Bubenkov
045274e647 remove merge artifact 2015-07-19 15:49:43 +02:00
Anatoly Bubenkov
6af7172204 Merge branch 'pytest-2.7' 2015-07-19 15:25:04 +02:00
Anatoly Bubenkov
412b43b216 Merge pull request #865 from nicoddemus/skipif-reason-multiple
Report correct reason when using multiple skip/xfail markers
2015-07-19 15:14:47 +02:00
Bruno Oliveira
de65737cb1 Fix flakes 2015-07-18 18:23:17 -03:00
Bruno Oliveira
953916df49 Report correct reason when using multiple skip/xfail markers 2015-07-18 18:18:45 -03:00
Bruno Oliveira
2f7d0f8bd9 Consider --color option in more places which deal with TerminalWriters 2015-07-18 16:39:55 -03:00
Bruno Oliveira
23aaa8a62c Allow py35 to fail on Travis until it is properly supported (fix2)
Conflicts:
	.travis.yml
2015-07-18 15:39:22 -03:00
Bruno Oliveira
604a39f5ef Allow py35 to fail on Travis until it is properly supported (fix2) 2015-07-18 15:30:16 -03:00
Bruno Oliveira
a5bc98136d Allow py35 to fail on Travis until it is properly supported (fix) 2015-07-18 15:18:57 -03:00
Bruno Oliveira
7dab2e1efe Allow py35 to fail on Travis until it is properly supported 2015-07-18 14:46:36 -03:00
Bruno Oliveira
da1d5712cf Fix broken links
Fix #857
2015-07-18 14:15:07 -03:00
Bruno Oliveira
30ff723d57 Merge pull request #859 from pytest-dev/py35fix-port
Py35fix port
2015-07-18 13:53:11 -03:00
Thomas Kluyver
e227950b06 Style fix 2015-07-18 13:18:38 -03:00
Thomas Kluyver
6719a818e7 Match .travis.yml env list to tox envs
Conflicts:
	.travis.yml
2015-07-18 13:18:36 -03:00
Thomas Kluyver
08432c3e97 No more failures 2015-07-18 13:17:29 -03:00
Thomas Kluyver
15497dcd77 OK, try running flakes with 2.7 2015-07-18 13:16:47 -03:00
Thomas Kluyver
8a0867c580 Try running flakes tests with Python 3.4 2015-07-18 13:16:47 -03:00
Thomas Kluyver
d4789f1ac4 Fix AST rewriting with starred expressions in function calls 2015-07-18 13:16:47 -03:00
Thomas Kluyver
26e7532756 Move Interrupted exception class out of Session 2015-07-18 13:16:47 -03:00
Thomas Kluyver
570c4cc55a No Starred node type on Python 2 2015-07-18 13:16:46 -03:00
Matthias Bussonnier
728d8fbdc5 generify 2015-07-18 13:16:26 -03:00
Matthias Bussonnier
fad569ae1b simplify + fix 2015-07-18 13:16:26 -03:00
Matthias Bussonnier
a4dbb27fab a test 2015-07-18 13:16:26 -03:00
Matthias Bussonnier
ec5286ea8c nigh 2015-07-18 13:16:08 -03:00
Matthias Bussonnier
195afa0733 try isntall 35 on tox 2015-07-18 13:16:08 -03:00
Matthias Bussonnier
8bde0c5957 allow faillure on 35 2015-07-18 13:16:08 -03:00
Matthias Bussonnier
b18e6439bd Ast Call signature changed on 3.5
fix issue 744 on bitbucket

port of merge request 296

https://bitbucket.org/pytest-dev/pytest/pull-request/296/astcall-signature-changed-on-35
https://bitbucket.org/pytest-dev/pytest/issue/744/

Conflicts:
	CHANGELOG
2015-07-18 13:15:46 -03:00
Floris Bruynooghe
5e0235946b Merge pull request #801 from Carreau/test-35
Support Python 3.5
2015-07-18 11:30:36 +01:00
Anatoly Bubenkov
360c09a1e7 appveyor scripts 2015-07-16 21:21:55 -03:00
Anatoly Bubenkov
85f7aa2f9b appveyor integration 2015-07-16 21:21:47 -03:00
Bruno Oliveira
a7b4ed89da Use functools.partial name explicitly and simplify the code a bit as asked in review 2015-07-16 20:37:04 -03:00
Bruno Oliveira
dcdc823dd2 Support for tests created with functools.partial
Fix #811
2015-07-16 20:37:03 -03:00
Bruno Oliveira
30e7104b05 Merge pull request #845 from nicoddemus/tmpdir-improvements
Introduce tmpdir_factory session fixture
2015-07-16 20:02:08 -03:00
Bruno Oliveira
330de0a93d Use a subdirectory in the TEMP directory to speed up tmpdir creation
Fix #105
2015-07-16 19:50:49 -03:00
Bruno Oliveira
aa25fb05a9 Make sure marks in subclasses don't change marks in superclasses
Fix #842
2015-07-16 19:29:16 -03:00
Thomas Kluyver
4462b83258 Style fix 2015-07-16 11:04:36 -07:00
Bruno Oliveira
94cdec2cfe Update sidebar links from Bitbucket to GitHub 2015-07-16 03:08:06 +00:00
Bruno Oliveira
ebf32ae8a9 Update CONTRIBUTING documentation with GitHub instructions 2015-07-16 03:07:16 +00:00
Bruno Oliveira
74bc50e97c Fix flakes 2015-07-15 20:45:35 -03:00
Bruno Oliveira
0f52856f99 Use a subdirectory in the TEMP directory to speed up tmpdir creation
Fix #105
2015-07-15 20:03:58 -03:00
Thomas Kluyver
077f0d3d66 Match .travis.yml env list to tox envs 2015-07-15 16:03:14 -07:00
Thomas Kluyver
37a09a6c30 No more failures 2015-07-15 15:58:42 -07:00
Thomas Kluyver
4e98d2b7f1 OK, try running flakes with 2.7 2015-07-15 15:52:28 -07:00
Thomas Kluyver
d73c8e6a5e Try running flakes tests with Python 3.4 2015-07-15 15:49:15 -07:00
Thomas Kluyver
195422f9c0 Fix AST rewriting with starred expressions in function calls 2015-07-15 15:31:35 -07:00
Thomas Kluyver
62ca4ae963 Move Interrupted exception class out of Session 2015-07-15 14:28:43 -07:00
Thomas Kluyver
35bea86c9f No Starred node type on Python 2 2015-07-15 14:11:21 -07:00
Matthias Bussonnier
d774f3ca86 generify 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
167625d24d simplify + fix 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
3bc6c0f936 a test 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
3cf82c6594 nigh 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
71a00c3223 try isntall 35 on tox 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
e2e29284f0 allow faillure on 35 2015-07-15 13:49:40 -07:00
Matthias Bussonnier
26e64fc45c Ast Call signature changed on 3.5
fix issue 744 on bitbucket

port of merge request 296

https://bitbucket.org/pytest-dev/pytest/pull-request/296/astcall-signature-changed-on-35
https://bitbucket.org/pytest-dev/pytest/issue/744/
2015-07-15 13:49:40 -07:00
Bruno Oliveira
8f4f2c665d Mention pytest-runner in the docs
Fix #147
2015-07-13 21:59:37 -03:00
Bruno Oliveira
7a71b69a87 Pinning mock module to < 1.1 fo py26
It has been announced that mock>=1.1 will be
supported for python 2.7 only.

Conflicts:
	tox.ini
2015-07-13 13:43:03 -03:00
holger krekel (rather uses bitbucket/hpk42)
8910ec2870 Merge pull request #836 from nicoddemus/doctest-modules-fixtures
Consider session fixtures for doctest docstrings in modules
2015-07-13 18:02:51 +02:00
holger krekel (rather uses bitbucket/hpk42)
c5d26ae1bb Merge pull request #834 from nicoddemus/show-fixtures-bug
Fix: --fixtures only shows fixtures from first file
2015-07-13 17:59:42 +02:00
Bruno Oliveira
d6033037ac Consider session fixtures for doctest docstrings in modules
Fixes #768
2015-07-13 12:29:09 -03:00
Bruno Oliveira
5750ae784a Reword CHANGELOG a bit 2015-07-13 12:01:54 -03:00
holger krekel (rather uses bitbucket/hpk42)
194581ab5f Merge pull request #829 from nicoddemus/pep302-get-data-support
Add support for PEP302 get_data API
2015-07-13 16:55:16 +02:00
Bruno Oliveira
5ec2a17f08 --fixtures only shows fixtures from first file
Fix #833
2015-07-12 17:32:39 -03:00
Bruno Oliveira
7445c5bd70 Add support for PEP302 get_data API
Fix #808
2015-07-11 14:13:43 -03:00
Bruno Oliveira
1baa1a4d01 Merge pull request #822 from nicoddemus/extra-usage-info
Print inifile and rootdir when there's usage errors
2015-07-11 13:43:20 -03:00
Bruno Oliveira
40ec0ec97d Merge pull request #823 from nicoddemus/testdirs-option
Add new testdirs ini option
2015-07-11 13:42:54 -03:00
Bruno Oliveira
8a6aa5e17e Print inifile and rootdir when there's usage errors
Related to #821
2015-07-10 21:56:12 -03:00
Bruno Oliveira
854e603f84 Add new testdirs ini option
Fix #694
2015-07-10 21:52:47 -03:00
Bruno Oliveira
65c56d4c00 Pinning mock module to < 1.1 fo py26
It has been announced that mock>=1.1 will be
supported for python 2.7 only.
2015-07-10 19:57:48 -03:00
holger krekel (rather uses bitbucket/hpk42)
e7374c39ba Merge pull request #825 from nicoddemus/syntax-highlight-docs
Add syntax highlighting to missing snippets in the documentation and other fixes
2015-07-10 13:02:52 +02:00
Bruno Oliveira
0ee3ee7333 Add syntax highlighting to missing snippets in the documentation and other fixes
- Add explicit "code-block" for sessions without syntax highlight
- Moved Metafunc documentation to the class docstring and reused that in the
   docs;
2015-07-09 21:50:38 -03:00
Bruno Oliveira
0624a69964 Merge pull request #824 from hpk42/devpiupload
configure a plain "devpi upload" to create sdist and universal wheel
2015-07-09 12:08:52 -03:00
holger krekel
fe897c81be configure a plain "devpi upload" to create sdist and universal wheel 2015-07-09 14:56:56 +02:00
Bruno Oliveira
ae4c8b8635 Merge pull request #787 from pytest-dev/pluggy-bc-fix
Reintroduce get_plugin_manager() for backward-compatibility
2015-07-08 19:28:01 -03:00
Bruno Oliveira
d70a31168b Merge pull request #820 from jeffwidman/patch-1
Fix typo + grammar
2015-07-07 21:13:50 -03:00
Jeff Widman
4fa64a962e Fix typo + grammar 2015-07-07 16:35:21 -07:00
Bruno Oliveira
438ea86137 Fix flaky test_timing_function in Windows
This tests fails consistently on Windows due to small time
difference:

>       assert float(val) >= 0.03
E       assert 0.0299999713898 >= 0.03
E        +  where 0.0299999713898 = float('0.0299999713898')

Windows time.time() function is not as accurate as linux's,
so relaxed the test a bit.
2015-07-04 15:05:45 -03:00
Bruno Oliveira
d773c7498f Reword entry in the changelog to show case the new status bar colors better 2015-07-03 18:36:15 -03:00
Bruno Oliveira
4ef6cdfb68 Add small thanks note to Eric Siegerman 2015-07-03 18:31:15 -03:00
Bruno Oliveira
d10054a38d Merge branch 'esiegerman/summary_colors' of github.com:esiegerman/pytest 2015-07-03 18:29:17 -03:00
Bruno Oliveira
9293062221 Merge pull request #809 from kevincox/junitxml-file-attribute
Add `file` and `line` attributes to junit-xml output.
2015-07-03 08:24:36 -03:00
Kevin Cox
7fa27af408 Add file and line attributes to junit-xml output.
This adds the `file` and `line` attributes to the junit-xml output
which can be used by tooling to identify where tests come from. This can be
used for many things such as IDEs jumping to failures and test
runners evenly balancing tests among multiple executors.

Update test_junitxml.py

Foo.
2015-07-02 18:41:52 -04:00
Eric Siegerman
2c419c4790 Add CHANGELOG and AUTHORS entries 2015-07-02 15:47:03 -04:00
Eric Siegerman
afcad74be8 PEP8ify parametrized-test parameters 2015-07-02 13:39:05 -04:00
Eric Siegerman
6c395cb58c Default color is now yellow
Passing tests override that default, making the color green; but several other
"boring" statuses (xfailed, xpassed, deselected, skipped) have no effect.

Net effect: if only "boring" tests are seen, or no tests at all, the summary
bar is yellow.
2015-07-02 13:39:05 -04:00
Eric Siegerman
044d874c5b If there are warnings, make the status bar yellow
Also if we see any statuses the code doesn't know about.
2015-07-02 13:39:05 -04:00
Eric Siegerman
cb21d844d9 Add missing "error" status to the list 2015-07-02 13:39:05 -04:00
Eric Siegerman
0282da9ddf Refactor slightly
Check for the empty-key special case in the first loop,
not the second.
2015-07-02 13:39:05 -04:00
Eric Siegerman
e07144aeb4 Add tests for the empty-key special case 2015-07-02 13:39:05 -04:00
Eric Siegerman
7993afae46 test_summary_stats() now prints its parameter values
This makes it easier to identify failing tests.
2015-07-02 13:39:05 -04:00
Eric Siegerman
bfc3e48fd5 Factor out build_summary_stats_line(), and add tests
--HG--
branch : esiegerman/summary_colors
2015-07-02 13:39:04 -04:00
Bruno Oliveira
76497c2542 Fix plugins_index script and update plugins_index.txt 2015-06-30 19:01:28 -03:00
Bruno Oliveira
27a98788a8 start 2.7.3 CHANGELOG 2015-06-26 00:30:26 -03:00
Bruno Oliveira
9fb1637ce2 Test that deprecated_call keeps internal warnings structures intact 2015-06-26 00:26:59 -03:00
Pieter Mulder
75679f08c9 Update AUTHORS and CHANGELOG 2015-06-25 17:38:45 +02:00
Pieter Mulder
444cdfe6e3 Correct test_deprecated_call_preserves test.
Test if we preserve the correct functions.
2015-06-25 17:33:40 +02:00
Pieter Mulder
89b00d714f deprecated_call dit not revert functions back to original
Make sure that the warnings.warn and warnings.warn_explicit are reverted
to there original function after running the function in deprecated_call
2015-06-25 17:11:50 +02:00
Bruno Oliveira
3c2fd833ca Reintroduce get_plugin_manager() for backward-compatibility
PyCharm pytest runner depends on this function existing (see #787).

Added reference to get_plugin_manager() and PluginManager/PytestPluginManager to docs
2015-06-25 00:48:47 -03:00
holger krekel
01f5913826 try to fix coveralls env 2015-06-23 23:25:19 +02:00
holger krekel
0998170a01 check webhook again 2015-06-23 17:22:37 +02:00
holger krekel
28cf4c3226 small fix to test webhook 2015-06-23 17:14:08 +02:00
holger krekel (rather uses bitbucket/hpk42)
08613b621e Merge pull request #799 from pytest-dev/noconftest
Add a --noconftest option.
2015-06-23 16:53:22 +02:00
holger krekel
ee40ea5f6d Merge branch 'pytest-2.7'
Conflicts:
	AUTHORS
	_pytest/__init__.py
	setup.py
	testing/conftest.py
	tox.ini
2015-06-23 16:49:05 +02:00
holger krekel
e84c00efae finish pytest-2.7.2 release 2015-06-23 16:31:24 +02:00
Florian Bruhin
f78b6df8bc Return an empty list directly. 2015-06-23 14:05:44 +02:00
holger krekel (rather uses bitbucket/hpk42)
53021ea264 Merge pull request #800 from pytest-dev/confcutdir-test-fix
Check conftest.py is not loaded with --confcutdir.
2015-06-23 10:57:33 +02:00
Florian Bruhin
01d067ec2b Check conftest.py is not loaded with --confcutdir.
The test creates a conftest.py with "assert 0" which never should be loaded.
However, if it were loaded, the test would still pass as it never checks if it
was loaded or not.

See #799.
2015-06-23 10:12:30 +02:00
Florian Bruhin
8e0589af69 Add changelog entry. 2015-06-23 09:47:07 +02:00
Florian Bruhin
8664fc4102 Add a --noconftest option. 2015-06-23 09:38:54 +02:00
holger krekel (rather uses bitbucket/hpk42)
755d7b3787 Merge pull request #798 from radarhere/patch-1
Fixed typo
2015-06-23 09:00:42 +02:00
Andrew Murray
cba1ca6244 Fixed typo 2015-06-23 10:29:37 +10:00
holger krekel
cdd25c9512 bump version to 2.7, depend on py-1.4.29 2015-06-22 23:53:41 +02:00
holger krekel
898b63b665 change spelling, thanks Maciej Maciaszek 2015-06-22 11:34:00 +02:00
Anatoly Bubenkov
e947732bde Merge pull request #791 from pytest-dev/coverage-config
Improve coverage score by tweaking options
2015-06-21 00:54:25 +02:00
Bruno Oliveira
b0491e1a5e Merge pull request #792 from iKevinY/svg-badges
Use SVGs for all README badges
2015-06-20 16:10:55 -03:00
Kevin Yap
190326c186 Use SVGs for all README badges 2015-06-20 10:58:38 -07:00
Bruno Oliveira
0008bcb877 Add coveragerc file for coverage options 2015-06-20 00:58:41 -03:00
holger krekel (rather uses bitbucket/hpk42)
080dfb9841 Merge pull request #788 from pytest-dev/issue-767
Fix issue where pytest.raises() doesn't always return Exception instance in py26
2015-06-19 13:41:44 +02:00
Bruno Oliveira
02421790bf Merge pull request #786 from edisongustavo/pytest-2.7
Fix Python2 bug with PrettyPrinter raising with sets of unsortable elements
2015-06-19 08:39:15 -03:00
Edison Gustavo Muenz
48d91def7e Added workaround to still show the diff on containers with unsortable elements.
fix issue #718
2015-06-19 07:51:59 -03:00
Bruno Oliveira
eb73db56c7 Fix issue where pytest.raises() doesn't always return Exception instance in py26
Fixes #767
2015-06-19 07:46:47 -03:00
Bruno Oliveira
80b5ebc398 Merge pull request #790 from pytest-dev/irc-notifications
Adjust IRC notifications to use #pytest.
2015-06-19 07:31:50 -03:00
Florian Bruhin
94332ed1d8 Adjust IRC notifications to use #pytest.
It seems #pytest-dev is quite dead. Also I set it to only send notifications on
changes (i.e. success -> failure and vice-versa).
2015-06-19 11:37:10 +02:00
holger krekel
13c01193d6 Merge remote-tracking branch 'origin/pytest-2.7' 2015-06-19 10:03:37 +02:00
holger krekel (rather uses bitbucket/hpk42)
26f590babe Merge pull request #789 from pytest-dev/issue-114
Skip reports refer to pytest code instead of original test functions
2015-06-19 10:02:58 +02:00
Bruno Oliveira
f90b2f845c unittest.SkipTest now reports original function location
Fix #748
2015-06-18 22:27:43 -03:00
Bruno Oliveira
9d4e0365da Skipif marker report now refers to the skipped function
Fix #114
2015-06-18 21:59:44 -03:00
Anatoly Bubenkov
4d6fef36f4 Merge branch 'pytest-2.7' 2015-06-17 13:42:41 +02:00
Anatoly Bubenkov
0431b8bb74 Merge pull request #784 from pytest-dev/create-dirs-xml-log
Automatically create directories for junit-xml and resultlog
2015-06-17 13:28:07 +02:00
Bruno Oliveira
2653024409 Use os.path.isdir instead of os.path.exists
As suggested during review
2015-06-17 08:08:03 -03:00
Bruno Oliveira
923174718e Allow failure of py27-subprocess tox-env while on pytest-2.7
"inprocess by default" was introduced in 2.8, and the current travis
configuration was backported from master so this specific
tox-env will remain disabled while pytest-2.7 maintenance branch
lasts.
2015-06-17 00:53:38 -03:00
Anatoly Bubenkov
73f37d0989 split travis jobs
Conflicts:
	README.rst
2015-06-17 00:22:34 -03:00
Anatoly Bubenkov
0722b95e53 use travis containers 2015-06-17 00:21:32 -03:00
Bruno Oliveira
ae89436d97 Remove duplicated author from AUTHORS 2015-06-17 00:05:56 -03:00
Bruno Oliveira
af77a23501 Add docs for new tests 2015-06-17 00:04:25 -03:00
Bruno Oliveira
2a1424e563 Merge branch 'pytest-2.7' of github.com:curzona/pytest into pytest-2.7
Conflicts:
	AUTHORS
	CHANGELOG
2015-06-17 00:02:26 -03:00
curzona
1871d526ac Update CHANGELOG and AUTHORS 2015-06-16 19:33:26 -07:00
curzona
9346e18d8c Test creating directory for junit-xml and resultlog 2015-06-16 19:30:43 -07:00
curzona
1db5c95414 Automatically create directory for results 2015-06-16 19:30:19 -07:00
Punyashloka Biswal
0c05b906d4 backport fix for #713 2015-06-16 21:27:22 -03:00
Bruno Oliveira
f04e01f55f Sort AUTHORS names 2015-06-16 21:20:43 -03:00
Bruno Oliveira
a0da7b9774 Mention issue 713 in the test's docstring 2015-06-16 20:42:49 -03:00
Punyashloka Biswal
0b0406fa85 Handle reports that don't have a reprcrash
Closes #713 (which happens because ReprFailDoctest
doesn't have a reprcrash)
2015-06-16 18:53:20 -04:00
Anatoly Bubenkov
f1245b094f Merge pull request #779 from pytest-dev/coveralls-shields-badge
Use shields.io badge for coveralls
2015-06-16 04:09:49 +02:00
Bruno Oliveira
c840e5c06e Use shields.io badge for coveralls
All badges have a similar look
2015-06-15 23:08:17 -03:00
Anatoly Bubenkov
c7573a92b2 Merge pull request #778 from pytest-dev/pypi-badge
Use pypi version badge from shields.io
2015-06-16 04:05:30 +02:00
Bruno Oliveira
84a476af87 Use pypi version badge from shields.io
The old one from pypip.in seems to always be broken as of late
2015-06-15 23:03:53 -03:00
Anatoly Bubenkov
e890d60459 appveyor badge 2015-06-16 03:28:12 +02:00
Anatoly Bubenkov
5dbe565b6d Merge branch 'master' of github.com:pytest-dev/pytest 2015-06-16 03:25:39 +02:00
Anatoly Bubenkov
8f09904c06 appveyor scripts 2015-06-16 03:25:28 +02:00
Anatoly Bubenkov
c0db143d4a Merge pull request #777 from bubenkoff/appveyor-integration
appveyor integration
2015-06-16 03:05:14 +02:00
Anatoly Bubenkov
534dbacc80 appveyor integration 2015-06-16 02:58:07 +02:00
Anatoly Bubenkov
af439e7d74 Merge pull request #775 from bubenkoff/pass-coveralls-env
pass coveralls env
2015-06-16 02:39:17 +02:00
Anatoly Bubenkov
b38cadbecd pass coveralls env 2015-06-16 02:38:52 +02:00
Anatoly Bubenkov
edfadf3a7c pass coveralls env 2015-06-16 01:12:24 +02:00
Anatoly Bubenkov
ae66683998 Merge pull request #773 from pytest-dev/remove-hg-files
Remove hgignore and hgtags files
2015-06-16 01:06:47 +02:00
Bruno Oliveira
4a8a4cb21b Merge pull request #770 from bubenkoff/add-travis-badge
add travis badge
2015-06-15 20:04:32 -03:00
Anatoly Bubenkov
ccebf8e1d6 add travis badge 2015-06-16 01:03:38 +02:00
Bruno Oliveira
8663be34b4 Remove hgignore and hgtags files 2015-06-15 20:02:41 -03:00
Bruno Oliveira
502a372405 Merge pull request #771 from pytest-dev/use-travis-containers
use travis containers
2015-06-15 19:56:34 -03:00
Bruno Oliveira
088ead2477 Merge pull request #772 from bubenkoff/split-travis-jobs
split travis jobs
2015-06-15 19:56:20 -03:00
Anatoly Bubenkov
f2494ecb3d split travis jobs 2015-06-16 00:49:55 +02:00
Anatoly Bubenkov
e9e01f2c9c use travis containers 2015-06-16 00:22:16 +02:00
Bruno Oliveira
d4e77faea7 Update sidebar links from Bitbucket to GitHub 2015-06-15 19:18:03 -03:00
Bruno Oliveira
ff58ae66c0 Update CONTRIBUTING documentation with GitHub instructions 2015-06-15 18:54:44 -03:00
Bruno Oliveira
b40f760cc3 Change links from bitbucket to GitHub 2015-06-15 18:28:31 -03:00
Floris Bruynooghe
42e7456780 Merged in RonnyPfannschmidt/pytest/regendoc-upgrade (pull request #303)
use regendoc normalization and regenerate docs
2015-06-10 10:44:38 +01:00
Ronny Pfannschmidt
43d27ec7ed use regendoc normalization and regenerate docs
--HG--
branch : regendoc-upgrade
2015-06-06 23:30:49 +02:00
Ronny Pfannschmidt
645ddc917f make regendoc a direct requirement 2015-06-06 14:15:23 +02:00
Ronny Pfannschmidt
33a7f03ccc sort AUTHORS and add Janne 2015-06-06 13:38:25 +02:00
Ronny Pfannschmidt
8b53a72dde add Janne`s changes to CHANGELOG 2015-06-06 11:53:34 +02:00
Ronny Pfannschmidt
8ee73e028f Merged in jpvanhal/pytest/include-setup-teardown-duration-in-junitxml (pull request #287)
Include setup and teardown in junitxml test durations
2015-06-06 11:50:37 +02:00
holger krekel
ca44e88e54 backport fixed issue735
--HG--
branch : pytest-2.7
2015-06-04 07:52:25 +02:00
holger krekel
304fc4f222 Merged in issue735 (pull request #302)
use NameConstant node when it exists (fixes #735)
2015-06-04 07:48:53 +02:00
holger krekel
09edb813bc Close branch issue735
--HG--
branch : issue735
2015-06-04 07:48:53 +02:00
Benjamin Peterson
f3ad2e4ad2 use NameConstant node when it exists (fixes #735)
--HG--
branch : issue735
2015-06-03 18:07:10 -05:00
holger krekel
a2bb2ff164 port typo fix 2015-06-03 23:43:12 +02:00
holger krekel
b5fd3cfb84 fix typo
--HG--
branch : pytest-2.7
2015-06-03 23:42:38 +02:00
holger krekel
c037f52878 fix issue741: make running output from testdir.run copy/pasteable 2015-06-03 23:40:42 +02:00
holger krekel
584cccf7ec Merged in nicoddemus/pytest/issue-741-pytester-output (pull request #293)
Make "running" output from testdir.run copy/pastable
2015-06-03 23:40:08 +02:00
holger krekel
c92467df2f add changelog for latest merge 2015-06-03 23:39:00 +02:00
holger krekel
ad08bf79e7 Merged in The-Compiler/pytest (pull request #298)
Fix monkeypatch.setenv with string and raising=False.
2015-06-03 23:37:26 +02:00
holger krekel
dc727832a0 Close branch pytest-2.7
--HG--
branch : pytest-2.7
2015-06-03 23:34:38 +02:00
holger krekel
22c62dbd90 Merged in flub/pytest (pull request #299)
Ignore emacs' .dir-locals.el file
2015-06-03 23:34:13 +02:00
Floris Bruynooghe
d220be8468 Use platform.python_version() to show Python version number
This results in something like "3.5.0b2" for non-final releases
while still being "3.5.0" for final releases.
2015-05-31 20:31:31 +01:00
Floris Bruynooghe
b09be4e3ef Merged in flub/pytest (pull request #297)
Merge 2.7.1 release changes into default
2015-05-31 20:27:13 +01:00
Darren Yin
efce2ababa add in missing finalizer to doc example 2015-05-21 19:15:52 -07:00
Floris Bruynooghe
773b8b69dd Ignore emacs' .dir-locals.el file
This can be used to e.g. automatically set a specific syntax
checker or virtualenv to activate.
2015-05-20 10:33:13 +01:00
Florian Bruhin
ff8d787cd5 Fix monkeypatch.setenv with string and raising=False.
Fixes #746.
2015-05-19 22:59:49 +02:00
Floris Bruynooghe
d299f0d99f Merge changes from 2.7.1 release
This is mostly doc examples regeneration, other changes are:
- Add 2.7.1 tag to .hgtags
- Update changelog to use real versions
- Update HOWTORELEASE.rst
- Fix rst in doc/en/adopt.txt
- Fix CHANGELOG and release-2.7.0 rst formatting
2015-05-19 21:43:50 +01:00
Floris Bruynooghe
bf837164b4 Add how to upload a wheel and tag the release
--HG--
branch : pytest-2.7
2015-05-19 09:32:21 +01:00
Floris Bruynooghe
f6d589caa1 Added tag 2.7.1 for changeset edc1d080bab5
--HG--
branch : pytest-2.7
2015-05-19 09:26:59 +01:00
Floris Bruynooghe
738c8762df Regenerate docs using 2.7.1
--HG--
branch : pytest-2.7
2015-05-19 01:54:24 +01:00
Floris Bruynooghe
3d990a6237 Fix rest formatting and set final version number
--HG--
branch : pytest-2.7
2015-05-19 01:53:06 +01:00
Floris Bruynooghe
b024dbe794 Remove unused link
--HG--
branch : pytest-2.7
2015-05-19 01:52:33 +01:00
Floris Bruynooghe
83a93e5e9a More updates/fixes to release process
Some of this is temporary, but this is how I got things to work.

--HG--
branch : pytest-2.7
2015-05-19 01:52:06 +01:00
Floris Bruynooghe
504b6b72a9 Set 2.7.1 version number
--HG--
branch : pytest-2.7
2015-05-19 01:50:32 +01:00
holger krekel
3401049dea remove adopt pytest note 2015-05-12 13:36:43 +02:00
holger krekel
45851644c1 remove adopt message
--HG--
branch : pytest-2.7
2015-05-12 13:34:32 +02:00
Bruno Oliveira
a7f880fa1f Make "running" output from testdir.run copy/pastable
fix 741

--HG--
branch : issue-741-pytester-output
2015-05-09 10:24:33 -03:00
holger krekel
c4bd3c672b another try at ignoring cx_freeze during other tox envs 2015-05-07 12:19:35 +02:00
holger krekel
52354b9ab5 try to ignore cx_freeze from regular pytest runs and see if travis is happy 2015-05-07 12:02:14 +02:00
holger krekel
3c187c844e make default depend on just published py/pluggy releases 2015-05-07 11:50:08 +02:00
Ronny Pfannschmidt
45ed4c726e Merged in hpk42/pytest-patches/plug30 (pull request #291)
use new pluggy api (now at 0.3.0) for adding hookcall monitoring
2015-05-07 11:24:39 +02:00
holger krekel
d9a44098ce use new pluggy api (now at 0.3.0) for adding hookcall monitoring
and reraise real keyboard interrupts during inline pytest runs
to allow for better stopping of the pytest tests.

--HG--
branch : plug30
2015-05-07 11:02:55 +02:00
holger krekel
b93abfb3d1 Merged in hpk42/pytest-patches/pluggy1 (pull request #290)
integrate pluggy as external plugin manager
2015-05-06 15:02:05 +02:00
holger krekel
bb8141e27c - make sure sub pytest runs use the same basetemp
- depend on pluggy < 0.3

--HG--
branch : pluggy1
2015-05-06 14:58:46 +02:00
holger krekel
bddc88f09e adapt to pluggy naming, rename pytest.hookspec_opts to pytest.hookspec,s ame with hookimpl_opts
--HG--
branch : pluggy1
2015-05-06 10:08:08 +02:00
holger krekel
5ea7f0342b Merged default into pluggy1
--HG--
branch : pluggy1
2015-05-05 22:29:53 +02:00
holger krekel
13db045fc4 merge 2015-05-05 21:55:39 +02:00
holger krekel
23538bcd31 - some more adaptation to most recent pluggy API
- avoid using pluggin underscore api
- show pluggy version in header

--HG--
branch : pluggy1
2015-05-05 21:53:04 +02:00
holger krekel
a4f2236b36 merge default
--HG--
branch : pluggy1
2015-05-05 14:52:16 +02:00
holger krekel
88538f13ba adapt for current API changes of pluggy
--HG--
branch : pluggy1
2015-05-04 15:08:41 +02:00
holger krekel
920b5afe45 now that we are going to have wheels, py source code might be not be installed
and the resulting genscript is useless

--HG--
branch : pluggy1
2015-05-04 14:42:01 +02:00
holger krekel
e4b9603fa8 Merged in famousgarkin/pytest/famousgarkin/monkeypatchchdir-docstring-punctuation-1430453576841 (pull request #288)
monkeypatch.chdir docstring punctuation
2015-05-04 14:28:32 +02:00
holger krekel
ef7f627573 merging pytest-2.7 2015-05-04 14:27:09 +02:00
Eric Siegerman
5a06330f61 Doc typo
--HG--
branch : pytest-2.7
2015-05-01 11:18:17 -04:00
Janne Vanhala
93628fc0eb Include setup and teardown in junitxml test durations
--HG--
branch : include-setup-teardown-duration-in-junitxml
2015-05-01 14:55:52 +03:00
famousgarkin
47936643c9 monkeypatch.chdir docstring punctuation
--HG--
branch : famousgarkin/monkeypatchchdir-docstring-punctuation-1430453576841
2015-05-01 04:13:06 +00:00
Floris Bruynooghe
11ad61ba07 Use current regendocs location
--HG--
branch : pytest-2.7
2015-05-01 00:27:47 +01:00
Floris Bruynooghe
129549fd5b Some more tweaks of how to release
--HG--
branch : pytest-2.7
2015-05-01 00:27:04 +01:00
Floris Bruynooghe
652a353319 Some small corrections to release process
--HG--
branch : pytest-2.7
2015-04-30 22:55:01 +01:00
Floris Bruynooghe
d6d8d5b9d1 Prepare docs for bugfix release
--HG--
branch : pytest-2.7
2015-04-30 22:54:43 +01:00
Floris Bruynooghe
aa2ffb9805 Merge fix for issue 731 from pytest-2.7 2015-04-30 21:13:03 +01:00
Floris Bruynooghe
7f554f50e3 Fix collapse false to look at unescaped braces only
Sometimes the repr of an object can contain the "\n{" sequence which is
used as a formatting language, so they are escaped to "\\n{".  But the
collapse-false code needs to look for the real "\n{" token instead of
simply "{" as otherwise it may get unbalanced braces from the object's
repr (sometimes caused by the collapsing of long reprs by saferepr).

Fixes issue #731.

--HG--
branch : pytest-2.7
2015-04-30 02:31:12 +01:00
holger krekel
25963e0544 adapt pytest to pluggy's decoratorclass branch
--HG--
branch : pluggy1
2015-04-29 16:40:52 +02:00
holger krekel
5ee7ee0850 adapt pytest to using pluggy (current master)
--HG--
branch : pluggy1
2015-04-29 16:40:51 +02:00
holger krekel
d6670bd6a8 Merged in hpk42/pytest-patches/testrefactor (pull request #284)
majorly refactor pytester and speed/streamline  tests
2015-04-29 16:32:28 +02:00
holger krekel
9aec5cd52d use runpytest() instead of runpytest_inprocess if a test can run as subprocess as well
--HG--
branch : testrefactor
2015-04-28 12:05:08 +02:00
holger krekel
4d5161444c merge
--HG--
branch : testrefactor
2015-04-28 11:56:57 +02:00
holger krekel
db5649ec6a streamline pytester API majorly:
- integrate conftest into pytester plugin
- introduce runpytest() to either call runpytest_inline (default) or
  runpytest_subprocess (python -m pytest)
- move testdir.inline_runsource1 to pdb tests
- strike some unneccessary methods.
- a new section "writing plugins" and some better pytester docs

--HG--
branch : testrefactor
2015-04-28 11:54:53 +02:00
holger krekel
a8afba054a - refine lsof checking
- make runpytest() create an inline testing process instead of
  a subprocess one

--HG--
branch : testrefactor
2015-04-28 11:54:46 +02:00
holger krekel
d3e363b97a - make API between runpytest() and inline_run() more similar
- shift a number of tests to become inline_run() tests

--HG--
branch : testrefactor
2015-04-28 11:54:45 +02:00
holger krekel
2e3e1e9b7e Merged in hpk42/pytest-patches/plugtestfix (pull request #283)
make test suite more tolerable against xdist causing warnings itself
2015-04-28 11:52:53 +02:00
holger krekel
424e5d1394 make test suite more tolerable against xdist causing warnings itself (which it does
currently)

--HG--
branch : plugtestfix
2015-04-27 15:06:47 +02:00
Floris Bruynooghe
2d8f115d8c Merged in hpk42/pytest-patches/more_plugin (pull request #282)
another major pluginmanager refactor and docs
2015-04-27 13:17:40 +01:00
holger krekel
b2d66b9e7b simplify load_setuptools_entrypoints and refine comments/docstrings
--HG--
branch : more_plugin
2015-04-27 14:10:33 +02:00
holger krekel
c54afbe42e deprecate and warn about __multicall__ usage in hooks, refine docs about hook ordering,
make hookwrappers respect tryfirst/trylast

--HG--
branch : more_plugin
2015-04-27 12:50:34 +02:00
holger krekel
dea1c96031 actually revert back to using older simpler method for subset hook
calling.  It is slightly more inefficient but easier to implement and
read.

--HG--
branch : more_plugin
2015-04-26 17:17:59 +02:00
holger krekel
16c922bf53 merge contribution fix 2015-04-26 01:06:17 +02:00
holger krekel
e94f5727c4 Merged in contributing-fix (pull request #281)
Remove duplicated step in CONTRIBUTING

--HG--
branch : pytest-2.7
2015-04-26 01:05:50 +02:00
holger krekel
35da487d46 Close branch contributing-fix
--HG--
branch : contributing-fix
2015-04-26 01:05:50 +02:00
holger krekel
d2ea7387f2 re-add tryfirst/trylast marker documentation, mark it as to be removed
--HG--
branch : more_plugin
2015-04-26 00:47:24 +02:00
holger krekel
8e009ee31c move consider_setuptools_entrypoints to core pluginmanager
--HG--
branch : more_plugin
2015-04-26 00:41:29 +02:00
holger krekel
0c961deeaa fix some doc strings
--HG--
branch : more_plugin
2015-04-26 00:22:34 +02:00
holger krekel
32165d82b1 introduce a new subset_hook_caller instead of remove make_hook_caller
and adapat and refine conftest/global plugin management accordingly

--HG--
branch : more_plugin
2015-04-26 00:10:52 +02:00
holger krekel
d422247433 specialize make_hook_caller to work with a subset of the registered plugins.
--HG--
branch : more_plugin
2015-04-25 22:13:42 +02:00
holger krekel
a042c57227 ensure proper get_name references
--HG--
branch : more_plugin
2015-04-25 20:42:41 +02:00
holger krekel
3a1374e69c simplify plugins bookkeeping further, refine API
--HG--
branch : more_plugin
2015-04-25 20:17:32 +02:00
holger krekel
1c0582eaa7 simplify addition of method and scanning of plugins
--HG--
branch : more_plugin
2015-04-25 18:15:42 +02:00
holger krekel
1e883f5979 simplify tracing mechanics by simply going through an indirection
--HG--
branch : more_plugin
2015-04-25 18:15:39 +02:00
holger krekel
9c5495832c avoid direct circular reference between config and pluginmanager
--HG--
branch : more_plugin
2015-04-25 18:14:41 +02:00
holger krekel
7364647f2f fix issue732: make sure removed plugins remove all hook callers.
--HG--
branch : more_plugin
2015-04-25 18:14:39 +02:00
holger krekel
4e116ed503 make pytest_plugin_registered a historic hook
--HG--
branch : more_plugin
2015-04-25 13:38:30 +02:00
holger krekel
e7a2e53108 Streamline data structures
--HG--
branch : more_plugin
2015-04-25 13:38:29 +02:00
holger krekel
2f8a1aed6e properly perform hook calls with extra methods
--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
a63585dcab introduce historic hook spec which will memorize calls to a hook
in order to call them on later registered plugins

--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
ea50ef1588 split plugin documentation into "using" and "writing plugins",
referencing each other.  Also add tryfirst/trylast examples.

--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
d2a5c7f99b add documented hookimpl_opts and hookspec_opts decorators
so that one doesn't have to use pytest.mark or function-attribute setting anymore

--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
bbbb6dc2e3 remove _do_register indirection between PluginManager and PytestPluginManager
--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
f41528433b also incrementally remove plugins from hook callers
--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
02a4042dca incrementally update hook call lists instead of regenerating the whole
list on each registered plugin

--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
b03c1342ac allow to register plugins with hooks that are only added later
--HG--
branch : more_plugin
2015-04-25 11:29:11 +02:00
holger krekel
d8e91d9fee Merged in hpk42/pytest-patches/plugin_no_pytest (pull request #278)
Refactor pluginmanagement
2015-04-25 09:08:21 +02:00
Bruno Oliveira
a4ddec1157 Remove duplicated step in CONTRIBUTING
--HG--
branch : contributing-fix
2015-04-25 00:48:11 -03:00
holger krekel
9020bf48b7 remove useless check
--HG--
branch : plugin_no_pytest
2015-04-24 14:09:57 +02:00
holger krekel
237ac8562f minimize HookCaller attributes: avoid passing in hookrelay to HookCallers
--HG--
branch : plugin_no_pytest
2015-04-24 13:02:49 +02:00
holger krekel
feb4b2249a remove some redundancy when parsing import spec
--HG--
branch : plugin_no_pytest
2015-04-23 13:15:34 +02:00
holger krekel
95dd2eb1da streamline and document handling of builtin module special casing.
--HG--
branch : plugin_no_pytest
2015-04-23 12:39:11 +02:00
holger krekel
8fde2f98ae merge default
--HG--
branch : plugin_no_pytest
2015-04-23 12:35:15 +02:00
holger krekel
2b80caf1af merge cxfreeze fix 2015-04-23 12:07:12 +02:00
holger krekel
b4a655af52 Merged in nicoddemus/pytest/cx_freeze_ubuntu (pull request #280)
Fix py27-cxfreeze tox environment

--HG--
branch : pytest-2.7
2015-04-23 12:03:14 +02:00
Floris Bruynooghe
e450218daa Merge _pytest fixture reintroduction from pytest-2.7 branch
This was accidentally removed while some plugins depend on it.
2015-04-23 00:55:58 +01:00
Floris Bruynooghe
0cc9d7e6b6 Merged in hpk42/pytest-patches/reintroduce_pytest_fixture (pull request #279)
reintroduced _pytest fixture of the pytester plugin

--HG--
branch : pytest-2.7
2015-04-23 00:52:13 +01:00
Bruno Oliveira
6fe5493c3c Fix py27-cxfreeze tox environment
Use a custom script to install a patched version of cx_freeze,
as required in Ubuntu 14.04 systems

--HG--
branch : cx_freeze_ubuntu
2015-04-22 19:46:06 -03:00
holger krekel
a3aebfaefe accomodate Floris' comments. (The reason was i just reinstanted the old code :)
--HG--
branch : reintroduce_pytest_fixture
2015-04-22 21:04:36 +02:00
holger krekel
9d5182eaad reintroduced _pytest fixture of the pytester plugin which is used
at least by pytest-xdist.

--HG--
branch : reintroduce_pytest_fixture
2015-04-22 17:06:00 +02:00
holger krekel
27589eb7e1 reshuffle pluginmanager methods and add some docstrings.
--HG--
branch : plugin_no_pytest
2015-04-22 16:42:41 +02:00
holger krekel
d5db9faba8 shuffle PluginManager method order to first have the public API
and then the internal.

--HG--
branch : plugin_no_pytest
2015-04-22 16:34:42 +02:00
holger krekel
715a235b45 remove shutdown logic from PluginManager and add a add_cleanup() API
for the already existing cleanup logic of the config object.
This simplifies lifecycle management as we don't keep two
layers of shutdown functions and also simplifies the pluginmanager
interface.

also add some docstrings.

--HG--
branch : plugin_no_pytest
2015-04-22 16:33:20 +02:00
holger krekel
f746c190ac slight cleanup of plugin register() functionality
--HG--
branch : plugin_no_pytest
2015-04-22 14:54:28 +02:00
holger krekel
d632a0d5c2 merge conftest management into PytestPluginManager
--HG--
branch : plugin_no_pytest
2015-04-22 14:15:42 +02:00
holger krekel
894d7dca22 avoid undocumented special casing of "pytest_" prefix
--HG--
branch : plugin_no_pytest
2015-04-22 13:44:37 +02:00
holger krekel
20d6c0b560 simplify exception capturing
--HG--
branch : plugin_no_pytest
2015-04-22 13:37:42 +02:00
holger krekel
c08dfdc330 move bookkeeping of conftest plugins in core pluginmanager to PytestPluginManager
--HG--
branch : plugin_no_pytest
2015-04-22 13:33:01 +02:00
holger krekel
7049ebe4e2 avoid prepend to register api as it's redundant wrt to hooks
--HG--
branch : plugin_no_pytest
2015-04-22 13:31:46 +02:00
holger krekel
1ef49ac5ab minimize HookRelay to become a pure container, refactor initialization and
tests of plugin management to be a bit better split between pytest
and pytest-independent bits

--HG--
branch : plugin_no_pytest
2015-04-22 13:31:46 +02:00
holger krekel
db650de372 remove redundant py check as our setup.py excludes py <=1.4 already
--HG--
branch : plugin_no_pytest
2015-04-22 10:04:13 +02:00
Floris Bruynooghe
d9885388d0 Merge pull request #277 from pytest-2.7 branch
This removes the drone.io badge from the README as it doesn't make
sense to have it on the cheeseshop status page.

Fixes issue #726.
2015-04-21 15:04:08 +01:00
Floris Bruynooghe
a6b5f583a7 Merged in hpk42/pytest-patches/nodrone (pull request #277)
strike drone badge as it doesn't make sense on PYPI (where the README is rendered)

--HG--
branch : pytest-2.7
2015-04-21 15:01:42 +01:00
holger krekel
cfe9c9c169 strike drone badge as it doesn't make sense on PYPI (where the README is rendered)
--HG--
branch : nodrone
2015-04-21 15:55:48 +02:00
Floris Bruynooghe
240cd1f28d Merge cleaning of sys.modules after pytester.inline_run()
Merged in schettino72/pytest/pytester-inline-run-clean-sys-modules
(pull request #278).
2015-04-21 11:00:32 +01:00
Floris Bruynooghe
31af381c56 Merged in hpk42/pytest-patches/prefer_installed (pull request #275)
change test module importing behaviour to append to sys.path
2015-04-21 10:47:33 +01:00
Eduardo Schettino
bc0ecd1d06 pytester: add method `TmpTestdir.delete_loaded_modules()`
, and call it from ``inline_run()`` to allow temporary modules to be reloaded.

--HG--
branch : pytester-inline-run-clean-sys-modules
2015-04-21 10:18:04 +08:00
Eduardo Schettino
c792ab8aed fix regendoc repository location on requirements-docs.txt.
--HG--
branch : pytester-inline-run-clean-sys-modules
2015-04-21 10:16:04 +08:00
holger krekel
bac1ccd5b3 merge fix of issue553 on pytest-2.7 2015-04-17 22:32:49 +02:00
holger krekel
0b361c62c8 Merged in getsourcelines-error-issue-553-pytest2.7 (pull request #273)
Handle inspect.getsourcelines failures in FixtureLookupError

--HG--
branch : pytest-2.7
2015-04-17 22:31:55 +02:00
holger krekel
282f4ce920 Close branch getsourcelines-error-issue-553-pytest2.7
--HG--
branch : getsourcelines-error-issue-553-pytest2.7
2015-04-17 22:31:55 +02:00
holger krekel
5c8e5acf9d change test module importing behaviour to append to sys.path
instead of prepending.  This better allows to run test modules
against installated versions of a package even if the package
under test has the same import root.  In this example::

   testing/__init__.py
   testing/test_pkg_under_test.py
   pkg_under_test/

the tests will preferrably run against the installed version
of pkg_under_test whereas before they would always pick
up the local version.

--HG--
branch : prefer_installed
2015-04-17 22:25:35 +02:00
Floris Bruynooghe
fb07a09964 Merge pull request #274 from pytest-2.7
fixed regression to 2.6.4 which surfaced e.g. in lost stdout capture printing
2015-04-17 11:10:47 +01:00
Floris Bruynooghe
6e2bc7712c Merged in hpk42/pytest-patches/systemexit (pull request #274)
fixed regression to 2.6.4 which surfaced e.g. in lost stdout capture printing

--HG--
branch : pytest-2.7
2015-04-17 11:07:24 +01:00
holger krekel
173bd13ece backport Y->y fix from floris
--HG--
branch : pytest-2.7
2015-04-17 11:57:09 +02:00
holger krekel
e04273df57 fixed regression to 2.6.4 which surfaced e.g. in lost stdout capture printing
when tests raised SystemExit.

--HG--
branch : systemexit
2015-04-17 11:47:29 +02:00
Bruno Oliveira
15328c04eb Handle inspect.getsourcelines failures in FixtureLookupError
Fixes #553

--HG--
branch : getsourcelines-error-issue-553-pytest2.7
2015-04-15 19:31:22 -03:00
Floris Bruynooghe
c7a60af666 Use capital Y as the tests look for that 2015-04-13 09:08:10 +01:00
Floris Bruynooghe
09dff73607 Merge pytest-2.7 for issue660 fix 2015-04-13 00:04:53 +01:00
Floris Bruynooghe
6591d7a209 Merged in issue660 (pull request #268)
fix issue660

--HG--
branch : pytest-2.7
2015-04-13 00:00:40 +01:00
Floris Bruynooghe
220d177e76 Close branch issue660
--HG--
branch : issue660
2015-04-13 00:00:40 +01:00
Floris Bruynooghe
ddffa9d1cc Merge wheel support from pytest-2.7 branch
Merged in pytest-2.7 (pull request #269).
2015-04-12 23:47:10 +01:00
Floris Bruynooghe
9cae9a2a97 Add wheel support in the changelog
--HG--
branch : pytest-2.7
2015-04-12 23:36:43 +01:00
Floris Bruynooghe
129bb5393b Do imports at the head of the file
--HG--
branch : pytest-2.7
2015-04-12 23:36:28 +01:00
Floris Bruynooghe
bf0b70aa66 Some docstrings for the pytester plugin
These aren't quite complete but are a jolly good start anyway.  It
seems better to commit this now then leave it lingering until it
gets lost.
2015-04-11 17:07:37 +01:00
Ionel Cristian Maries
db08dcab14 Rename function and add nice docstring.
--HG--
branch : pytest-2.7
2015-04-10 22:11:17 +03:00
Ionel Cristian Maries
edd6c0f9b3 Make argpase a dependency for python 3.0 and 3.1 too.
--HG--
branch : pytest-2.7
2015-04-10 21:59:47 +03:00
Ionel Cristian Maries
a58cb3b95c Test for setuptools 0.7.2, turns out there's no 0.7 release on pypi.
--HG--
branch : pytest-2.7
2015-04-10 21:58:59 +03:00
Ionel Cristian Maries
40a682476d Improve version test (use pkg_resources to compare versions). Also log failures to stderr.
--HG--
branch : pytest-2.7
2015-04-10 21:44:27 +03:00
Ionel Cristian Maries
b7d43c5a5d Add support for building proper wheels (universal and proper dependency evnironment markers for argparse/colorama if setuptools is new-ish).
--HG--
branch : pytest-2.7
2015-04-10 21:08:50 +03:00
holger krekel
236cac86b1 add me as author of PR
--HG--
branch : issue660
2015-04-04 16:36:32 +02:00
holger krekel
79c0515945 merge pytest-2.7 branch
--HG--
branch : issue660
2015-04-04 16:35:14 +02:00
holger krekel
74019025b9 shift default to 2.8.0.dev 2015-04-04 16:32:25 +02:00
holger krekel
0e916460d8 add changelog entries
--HG--
branch : pytest-2.7
2015-04-04 16:29:38 +02:00
holger krekel
1ab93a5f1d Merged in release-checklist (pull request #266)
add a release checklist
2015-04-04 16:27:07 +02:00
holger krekel
69a0eacb4f Close branch release-checklist
--HG--
branch : release-checklist
2015-04-04 16:27:07 +02:00
holger krekel
d9d932aef5 Merged in yield-experimental-docs (pull request #267)
Removed note about yield fixtures being experimental
2015-04-04 16:25:24 +02:00
holger krekel
421c43a873 Close branch yield-experimental-docs
--HG--
branch : yield-experimental-docs
2015-04-04 16:25:24 +02:00
Bruno Oliveira
6558c7245f Brought back discussion session
Reworded it a bit to bring it to par with the current status

--HG--
branch : yield-experimental-docs
2015-04-03 19:44:06 -03:00
Bruno Oliveira
b3d646455a Fixed straightforward spelling
--HG--
branch : yield-experimental-docs
2015-04-03 17:06:51 -03:00
Bruno Oliveira
161d9e5971 Removed "discussion" session
Kept a note about exceptions after yield not being reraised

--HG--
branch : yield-experimental-docs
2015-04-03 16:59:33 -03:00
Bruno Oliveira
30260361dd Reviewed wording about yield being a "new" feature
--HG--
branch : yield-experimental-docs
2015-04-03 16:55:10 -03:00
Bruno Oliveira
c1b935adbd Removed note about yield fixtures being experimental
--HG--
branch : yield-experimental-docs
2015-04-03 16:28:20 -03:00
holger krekel
7f05cd8bfc more streamlining of release checklist
--HG--
branch : release-checklist
2015-04-02 10:55:24 +02:00
holger krekel
b55d66d0cf - avoid setting of versions and targets in conf.py and Makefile
as discussed on pytest-dev

- "make help" now prints pytest specific information.

- add a "_getdoctarget.py" helper

- make ``setup.py`` read the version from ``_pytest/__init__.py``

--HG--
branch : release-checklist
2015-04-02 10:38:25 +02:00
holger krekel
3ed3e51997 fix issue660: properly report fixture scope mismatches independent
from fixture argument ordering.

--HG--
branch : issue660
2015-04-01 18:42:48 +02:00
holger krekel
81d7883884 refine release process according to Bruno's feedback
--HG--
branch : release-checklist
2015-03-27 09:27:31 +01:00
holger krekel
ad137d46a2 add a release checklist
--HG--
branch : release-checklist
2015-03-26 14:04:33 +01:00
holger krekel
e16983d265 bump versions to dev, including changing the doc-install target to "dev"
instead of "latest"
2015-03-26 13:48:59 +01:00
holger krekel
fd6ff9bc01 Added tag 2.7.0 for changeset 7ed701fa2fb5 2015-03-26 13:44:58 +01:00
holger krekel
d2a8866bce bump verrsion to python2.7, fix a too precise test for windows, regen docs 2015-03-26 09:34:10 +01:00
Anatoly Bubenkov
c69978fbb0 revert verbosity 2015-03-24 13:41:49 +01:00
Anatoly Bubenkov
c1eaa72883 correct config 2015-03-24 11:56:59 +01:00
Anatoly Bubenkov
55f3ffd2ba add verbosity to the tests 2015-03-24 10:51:45 +00:00
Anatoly Bubenkov
55eb82c434 fix pep257 2015-03-23 21:28:29 +01:00
Anatoly Bubenkov
d94a29e866 merge almarklein/default 2015-03-23 21:25:10 +01:00
Anatoly Bubenkov
a7d2a82caa merge pfctdayelise/issue463 2015-03-23 20:42:16 +01:00
Anatoly Bubenkov
ce95437dee merge with default
--HG--
branch : issue463
2015-03-23 20:41:27 +01:00
Brianna Laugher
3ba3112a85 update changelog
--HG--
branch : issue463
2015-03-23 20:28:04 +01:00
Brianna Laugher
c019e489d2 Change docstring style
--HG--
branch : issue463
2015-03-23 20:27:53 +01:00
Brianna Laugher
43e4fcf6dd Raise specific MarkerError rather than generic ValueError
--HG--
branch : issue463
2015-03-23 20:01:58 +01:00
tigeraniya
65ca554230 duplicate assignment 2015-03-23 20:47:34 +05:30
holger krekel
52a2999a91 merge 2015-03-23 10:10:26 +01:00
holger krekel
f3580bee2d fix issue435: make reload() work when assert rewriting is active.
Thanks Daniel Hahler.
2015-03-23 10:08:47 +01:00
Brianna Laugher
deb163d237 Change string format syntax from {} to {0} for py2.6
--HG--
branch : issue463
2015-03-21 23:57:06 +01:00
Brianna Laugher
6f81602ba2 Use hasattr instead of try/except
--HG--
branch : issue463
2015-03-21 23:30:13 +01:00
Brianna Laugher
ac17f20d98 #463
Raise a ValueError early if user misspells 'parametrize' as 'parameterize'.

--HG--
branch : issue463
2015-03-21 23:06:25 +01:00
Almar Klein
a9b7de8bf0 address reviewer comments 2015-03-21 17:26:23 +01:00
Almar Klein
0fc75c9622 Storing sys.last_traceback: test, docs and changelog 2015-03-21 17:06:24 +01:00
Almar Klein
9726fafa98 allow postmortem debugging on failed test 2015-03-21 09:26:35 +01:00
Floris Bruynooghe
cf7bb70809 Mention requirement for licensing information
Repositories should always have proper licensing information.
2015-03-19 11:53:32 +00:00
holger krekel
03c3930734 add a project someone reported a while ago 2015-03-17 13:21:44 +01:00
holger krekel
25a4d7d882 remove default-verbose running 2015-03-17 13:19:26 +01:00
Bruno Oliveira
eead0365b5 Merged in parametrized-fixture-override (pull request #257)
allow to override parametrized fixtures with non-parametrized ones and vice versa
2015-03-12 09:40:56 -03:00
Bruno Oliveira
eb3b989286 Close branch parametrized-fixture-override
--HG--
branch : parametrized-fixture-override
2015-03-12 09:40:56 -03:00
Anatoly Bubenkov
cdb46e9f16 Merged in blueyed/pytest/strip-docstrings-from-fixtures (pull request #260)
Strip docstrings in output with `--fixtures`
2015-03-12 08:12:43 +01:00
Anatoly Bubenkov
ead25634fe Merged in link-update (pull request #261)
update website sidebar links for repo move
2015-03-12 08:11:46 +01:00
Anatoly Bubenkov
3f3521c826 Close branch link-update
--HG--
branch : link-update
2015-03-12 08:11:46 +01:00
Benjamin Peterson
0c2dfb9683 update website sidebar links for repo move
--HG--
branch : link-update
2015-03-11 20:04:14 -05:00
Daniel Hahler
5d6b0a59c0 Strip docstrings in output with --fixtures
Fixes https://bitbucket.org/pytest-dev/pytest/issue/550.

--HG--
branch : strip-docstrings-from-fixtures
2015-03-04 17:00:24 +01:00
Daniel Hahler
c629f6b18b Fix reload() with modules handled via python_files
If a module exists in `sys.modules` already, `load_module` has to return it.

Fixes https://bitbucket.org/pytest-dev/pytest/issue/435

--HG--
branch : fix-reload
2015-03-04 16:21:27 +01:00
Anatoly Bubenkov
b48eda6d7d update regendocs
--HG--
branch : parametrized-fixture-override
2015-03-02 22:07:42 +01:00
Anatoly Bubenkov
81243657be add docs target
--HG--
branch : parametrized-fixture-override
2015-03-02 21:43:31 +01:00
Anatoly Bubenkov
24fe051803 use make develop in contribution guide
--HG--
branch : parametrized-fixture-override
2015-03-02 20:48:09 +01:00
Anatoly Bubenkov
16bcfa749e merge with upstream
--HG--
branch : parametrized-fixture-override
2015-03-02 20:18:31 +01:00
Anatoly Bubenkov
d083153548 fix typo
--HG--
branch : parametrized-fixture-override
2015-03-02 20:18:06 +01:00
Ronny Pfannschmidt
41e6b04f0b Merged in eks/pytest/issue616 (pull request #258)
Add comments
2015-03-02 14:38:10 +01:00
Anatoly Bubenkov
33c2a3a3e5 make loop more readable
--HG--
branch : parametrized-fixture-override
2015-03-02 08:55:57 +01:00
Eric Siegerman
97d5da5c99 Add comments
--HG--
branch : issue616
2015-03-01 17:32:00 -05:00
Anatoly Bubenkov
d1005ebb8f document fixture override techniques
--HG--
branch : parametrized-fixture-override
2015-03-01 18:54:24 +01:00
Anatoly Bubenkov
c4623939af support override of the parametrized fixture on the test level
--HG--
branch : parametrized-fixture-override
2015-03-01 15:15:37 +01:00
Anatoly Bubenkov
060609317a allow to override parametrized fixtures with non-parametrized ones and vice versa
--HG--
branch : parametrized-fixture-override
2015-03-01 13:54:43 +01:00
Anatoly Bubenkov
bae0f7f46a Merged in plugincompat-move (pull request #256)
moved pytest-plugs to plugincompat
2015-02-28 21:32:57 +01:00
Anatoly Bubenkov
09a50b6e6d Close branch plugincompat-move
--HG--
branch : plugincompat-move
2015-02-28 21:32:57 +01:00
Bruno Oliveira
200fe072f1 moved pytest-plugs to plugincompat
also plugins_index is ready for 2.7.0 release

--HG--
branch : plugincompat-move
2015-02-28 17:22:42 -03:00
holger krekel
ff9ec13ddb mention "pytestdotorg" twitter account 2015-02-28 20:02:31 +01:00
Ronny Pfannschmidt
9384ff38c9 Close branch issue616
--HG--
branch : issue616
2015-02-28 10:02:58 +01:00
Ronny Pfannschmidt
1e6e373913 Merged in issue616 (pull request #252)
fix issue616 - conftest visibility fixes.
2015-02-28 10:02:58 +01:00
holger krekel
e510eb0d45 a few more fixes 2015-02-27 16:42:03 +01:00
holger krekel
2e2d6a8bef make "Adopt pytest" note more prominent, fix link from plugins page. 2015-02-27 15:49:25 +01:00
Benjamin Peterson
44cd1c9862 merge dead branch 2015-02-27 09:34:33 -05:00
Benjamin Peterson
f6f084fa01 close branch
--HG--
branch : update-issues
2015-02-27 09:34:16 -05:00
holger krekel
b7d212c0c9 Merged in update-issues (pull request #255)
another update for get_issues.py to account for repository move
2015-02-27 15:32:13 +01:00
Benjamin Peterson
bda3e53df6 another update for get_issues.py to account for repository move
--HG--
branch : update-issues
2015-02-27 09:12:00 -05:00
Anatoly Bubenkov
9d4354c0a4 Merged in docs_community (pull request #254)
added documentationo on the new pytest-dev teams on bitbucket and
2015-02-27 14:58:27 +01:00
Anatoly Bubenkov
f99ddbfdf2 Close branch docs_community
--HG--
branch : docs_community
2015-02-27 14:58:27 +01:00
holger krekel
019dc14fc4 fix typos, clarify git/hg
--HG--
branch : docs_community
2015-02-27 13:38:45 +01:00
holger krekel
dbb58b39d9 switch to push to latest docs, because otherwise people get misled to old repos which don't exist anymore
--HG--
branch : docs_community
2015-02-27 12:53:14 +01:00
holger krekel
c3ca44b46f change links to go to the new pytest-dev bitbucket team's repo location
--HG--
branch : docs_community
2015-02-27 12:27:40 +01:00
holger krekel
f6df3b0b97 added documentationo on the new pytest-dev teams on bitbucket and
github.  See https://pytest.org/latest/contributing.html (tentative)
Thanks to Anatoly for pushing and initial work on this.

--HG--
branch : docs_community
2015-02-27 11:54:17 +01:00
holger krekel
e9d4853296 Merged contributing-community into default 2015-02-27 11:17:14 +01:00
holger krekel
28c2327f73 move conftest visibility tests and their setup into a class, accomodates @nicoddemus 's comment
--HG--
branch : issue616
2015-02-27 09:51:53 +01:00
holger krekel
8ed5b77aba fix issue650: introduce new --doctest-ignore-import-errors option courtesy
of Charles Cloud.
2015-02-26 22:02:49 +01:00
holger krekel
660b84a052 Merged in cpcloud/pytest/ignore-doctest-import-errors (pull request #243)
Add option to ignore import errors in doctests
2015-02-26 21:59:54 +01:00
holger krekel
d73e689991 fix issue616 - conftest visibility fixes. This is achieved by
refactoring how nodeid's are constructed.  They now are always
relative to the "common rootdir" of a test run which is determined by
finding a common ancestor of all testrun arguments.

--HG--
branch : issue616
2015-02-26 21:56:44 +01:00
Phillip Cloud
c773ea664b Add test for command line usage
--HG--
branch : ignore-doctest-import-errors
2015-02-26 12:39:36 -05:00
holger krekel
aa757f7715 change "install" targets to use pytest-dev user so that Brianna, Ronny, me
and others can push to pytest.org
2015-02-23 16:14:54 +01:00
Ronny Pfannschmidt
4222a806f1 Merged in LucasC/pytest (pull request #247)
Fixing description of --dist=load in the --help documentation for the xdist plugin
2015-02-22 20:04:05 +01:00
Ronny Pfannschmidt
415c76b255 Merged in tush/pytest/junit-verbose-failures (pull request #240)
Made failure message in junit xml report more informative
2015-02-22 19:13:07 +01:00
Ronny Pfannschmidt
f1c9554f42 merge 2015-02-22 12:29:26 +01:00
Ronny Pfannschmidt
3d0b756877 merge in the 2.6 maintenance branch 2015-02-22 11:45:07 +01:00
holger krekel
ea4e9fa4e2 Merged in msabramo/pytest/remove_pdbpp_xfail (pull request #250)
Remove pdbpp xfails; don't seem necessary anymore
2015-02-19 12:42:23 +01:00
Marc Abramowitz
777bde7c60 Remove xfail_if_pdbpp_installed from test_pdb.py
--HG--
branch : remove_pdbpp_xfail
2015-02-19 03:22:05 -08:00
Marc Abramowitz
e19f3c260f Remove pdbpp xfails; don't seem necessary anymore
It seems that they're no longer necessary as the tests pass now

    [marca@marca-mac2 pytest]$ pip freeze
    backports.inspect==0.0.2
    fancycompleter==0.4
    funcsigs==0.2
    ordereddict==1.1
    -e hg+ssh://hg@bitbucket.org/antocuni/pdb@4bda65ac8f8cc9b1850e0301669aac39200f2f9a#egg=pdbpp-fix_pytest_doctest_NoneType_object_has_no_attribute_lower
    py==1.4.26
    Pygments==1.6
    pyrepl==0.8.4
    -e hg+ssh://hg@bitbucket.org/hpk42/pytest@5fc366c50b56a94638c959be8456d2cb3c7e7c1c#egg=pytest-dev
    wmctrl==0.1
    [marca@marca-mac2 pytest]$ py.test testing/test_doctest.py --tb=short
    ============================================================================= test session starts ==============================================================================
    platform darwin -- Python 2.7.9 -- py-1.4.26 -- pytest-2.7.0.dev1
    collected 22 items

    testing/test_doctest.py ......................

    ========================================================================== 22 passed in 1.61 seconds ===========================================================================

See https://bitbucket.org/antocuni/pdb/issue/24/doctests-fail-when-pdbpp-is-installed

--HG--
branch : remove_pdbpp_xfail
2015-02-19 03:03:56 -08:00
Lucas Cimon
5025478ac2 Fixing description of --dist=load in the --help documentation for the xdist plugin 2015-02-14 00:07:19 +01:00
Floris Bruynooghe
5b73de92c2 Merged in jeffwidman/pytest/jeffwidman/fix-faq-grammar-and-spelling-1423641159173 (pull request #246)
Fix FAQ grammar and spelling
2015-02-12 09:32:32 +00:00
Jeff Widman
6a237bd49f Changed back to "parametrized" to match the API
--HG--
branch : jeffwidman/fix-faq-grammar-and-spelling-1423641159173
2015-02-11 19:27:51 +00:00
Jeff Widman
89710b4901 Fix: FAQ grammar and spelling
--HG--
branch : jeffwidman/fix-faq-grammar-and-spelling-1423641159173
2015-02-11 07:52:48 +00:00
Floris Bruynooghe
459d6e610c Merged in davehunt/pytest/env-addopts (pull request #241)
Support setting configuration using the PYTEST_ADDOPTS environment variable
2015-02-09 16:33:36 +00:00
Dave Hunt
d1adbf4a5c Added documentation for PYTEST_ADDOPTS environment variable, updated CHANGELOG and AUTHORS.
--HG--
branch : env-addopts
2015-02-09 14:11:54 +00:00
holger krekel
c11cc36997 Merged in pfctdayelise/pytest_new/adopt-pytest-docs (pull request #244)
#676 Add docs page describing 'adopt pytest month'
2015-02-09 12:40:41 +01:00
Brianna Laugher
2b7fae2368 #676
Add  docs page describing 'adopt pytest month'

--HG--
branch : adopt-pytest-docs
2015-02-09 11:59:15 +01:00
Phillip Cloud
f2ca0b8170 Add option to ignore import errors in doctests
--HG--
branch : ignore-doctest-import-errors
2015-02-08 01:25:23 -05:00
Dave Hunt
912c8f0540 Use monkeypatch to set the PYTEST_ADDOPTS environment variable in the test.
--HG--
branch : env-addopts
2015-01-29 10:52:01 +00:00
Dave Hunt
8f12269db7 Use shlex to split the arguments from PYTEST_ADDOPTS.
--HG--
branch : env-addopts
2015-01-26 10:39:21 +00:00
Dave Hunt
7325a5fe2e Support setting configuration using the PYTEST_ADDOPTS environment variable.
--HG--
branch : env-addopts
2015-01-23 20:09:42 +00:00
tush home
9f4d0be895 Failure message in junit xml report now are more informative
--HG--
branch : junit-verbose-failures
2015-01-20 01:45:26 +03:00
holger krekel
394367e1d2 Merged in nicoddemus/pytest/pastebin-xdist (pull request #239)
Using pytest-xdist and --paste=all results in error
2015-01-19 22:34:43 +01:00
Bruno Oliveira
7e15fb7f2d Attempting to patch terminal only if terminalreporter is available
This fixes the flag "--paste=all" when running tests with xdist, as slaves would
attempt to patch a non-existing terminal during pytest_configure. Only the master
node has a terminalreporter installed.

--HG--
branch : pastebin-xdist
2015-01-19 19:20:01 -02:00
holger krekel
8859936301 Merged in okin/pytest/okin/only-one-import-on-one-line-if-this-shou-1421239108222 (pull request #238)
Only one import on one line.
2015-01-15 21:22:49 +01:00
okin
d580f5bac8 Only one import on one line.
If this should show good practices, the code should not set a bad example ;)

--HG--
branch : okin/only-one-import-on-one-line-if-this-shou-1421239108222
2015-01-14 12:38:37 +00:00
Ronny Pfannschmidt
5941b2e071 fix issue 655: crude workarounds around python2/3 exception leaks 2015-01-09 19:55:49 +01:00
James Tatum
bca19a1156 Cleaning up the docstrings in monkeypatch.py 2015-01-08 17:15:22 -08:00
Floris Bruynooghe
3df5989326 Revert pypi badge again as the svg broke
This reverts the pypi badge back to the pypip.in provided one
because the shields.io one failed to render properly (and also
wasn't on https).
2014-11-24 08:48:09 +00:00
Floris Bruynooghe
98b9de4ff1 Merged in techtonik/pytest/techtonik/readmerst-fix-link-to-pypi-1416719991514 (pull request #234)
README.rst fix link to PyPI
2014-11-24 08:41:53 +00:00
anatoly techtonik
0e248c9aed README.rst fix link to PyPI
--HG--
branch : techtonik/readmerst-fix-link-to-pypi-1416719991514
2014-11-23 05:20:01 +00:00
holger krekel
883b3ca2c1 add a py.test placeholder setup that errors out when trying to get installed
(this is registered at pypi.python.org already)
2014-10-30 11:38:13 +01:00
Floris Bruynooghe
e4bb48995a Mention fix for issue 615 in changelog
Fixes issue 615.
2014-10-28 13:31:09 +00:00
Floris Bruynooghe
1d15bb2880 Merged in tomviner/pytest/format_boolop_percent6 (pull request #231)
fix for issue #615: _format_boolop must escape %
2014-10-28 13:26:21 +00:00
holger krekel
959395b796 fix py26 compatibility 2014-10-27 10:02:15 +01:00
TomV
f6caf230f8 fix for issue615: _format_boolop must escape %
fix test for issue615: expression must eval False

--HG--
branch : format_boolop_percent6
2014-10-27 08:57:58 +00:00
holger krekel
f2cdbe776e bump version to 2.7 on default 2014-10-26 10:52:04 +01:00
holger krekel
97c9c10f3c remove "universal wheel" again until the py26/py27 difference (argparse) does not play a role anymore. 2014-10-25 07:21:21 +02:00
holger krekel
f74930db79 Merged in alex_gaynor/pytest-1/alex_gaynor/mark-pytest-as-a-universal-wheel-1414169551518 (pull request #230)
Mark pytest as a universal wheel
2014-10-24 20:04:13 +02:00
Alex Gaynor
5a88a9b22a Mark pytest as a universal wheel
--HG--
branch : alex_gaynor/mark-pytest-as-a-universal-wheel-1414169551518
2014-10-24 16:52:43 +00:00
holger krekel
d0d4759c96 fix changelog -- we should have all changes in trunk that are in 2.6.4 2014-10-24 17:19:54 +02:00
holger krekel
749316623b Added tag 2.6.4 for changeset f03b6de8325f
--HG--
branch : pytest-2.6
2014-10-24 17:12:24 +02:00
holger krekel
60cdb875ed backport pastebin fix
--HG--
branch : pytest-2.6
2014-10-24 15:24:44 +02:00
holger krekel
e0251ecb41 regen docs
--HG--
branch : pytest-2.6
2014-10-24 15:08:43 +02:00
holger krekel
0834b63560 backport fixed issue620 (doc for genscript)
--HG--
branch : pytest-2.6
2014-10-24 13:53:39 +02:00
Dinu Gherman
0c8569dcb0 Added explanation for the binary blob in runtests.py 2014-10-24 13:04:20 +02:00
holger krekel
5f2444d2a2 Merged in nicoddemus/pytest/fix-pastebin (pull request #228)
Fix --pastebin option
2014-10-23 09:08:30 +02:00
Bruno Oliveira
537dca477b Fixing --pastebin option by using a POST request instead of a XMLRPC call
fixes #614

--HG--
branch : fix-pastebin
2014-10-22 21:52:40 -02:00
Floris Bruynooghe
8480111012 closing branch
--HG--
branch : python-classes-glob
2014-10-22 23:21:58 +01:00
Floris Bruynooghe
c63dc62294 Mention issue351/PR161 in changelog 2014-10-22 23:20:27 +01:00
Floris Bruynooghe
8d19ccb56f Merged in pfctdayelise/pytest/issue351 (pull request #161)
Fixes issue351: Add ability to specify parametrize ids as a
callable, to generate custom test ids. + tests, docs

Hg branch merge
2014-10-22 23:18:01 +01:00
holger krekel
eac4514227 Merged in nicoddemus/pytest/python-classes-glob (pull request #225)
added support for glob-style patterns to python_classes and python_functions config options
2014-10-22 07:14:10 +02:00
Bruno Oliveira
16f0d100cc added changelog entry about glob-patterns in python_classes and python_functions
- also fixed small typo

--HG--
branch : python-classes-glob
2014-10-21 19:22:53 -02:00
Bruno Oliveira
0b620c304b checking that option contains glob characters before calling fnmatch
requested during code review

--HG--
branch : python-classes-glob
2014-10-20 18:36:31 -02:00
David Röthlisberger
7371d436d2 Fix assertion.rewrite on read-only filesystem 2014-10-17 21:18:37 +01:00
Bruno Oliveira
b928928942 added support for glob-style patterns to python_classes and python_functions config options
fixes #600

--HG--
branch : python-classes-glob
2014-10-16 19:27:10 -03:00
Floris Bruynooghe
4337e9c4ba Merged in tomviner/pytest/assert_percent_test (pull request #223)
Test for issue615: compound assert with percent
2014-10-15 20:44:24 +01:00
holger krekel
8dfd6c17e3 add changelog note for tom's PR about parametrized markers. 2014-10-14 10:12:45 +02:00
holger krekel
de7c97aa1e Merged in tomviner/pytest (pull request #222)
fix issue552: Add a note to the docs about marking single callables
2014-10-14 10:02:21 +02:00
holger krekel
ace668ae8f Merged in tomviner/pytest/some_spelling_fixes (pull request #224)
A few spelling fixes
2014-10-14 09:59:49 +02:00
TomV
857db415bc fix some spelling mistakes
--HG--
branch : some_spelling_fixes
2014-10-13 23:16:26 +01:00
TomV
f8623a6668 test for issue615: compound assert with percent
--HG--
branch : assert_percent_test
2014-10-13 09:26:18 +01:00
TomV
4cadc600d5 fix issue552: note about marking single callables 2014-10-12 19:07:03 +01:00
Bruno Oliveira
d62ec2985d Adding "auto" to help for "--tb" option 2014-10-10 20:43:33 +00:00
Bruno Oliveira
b2341899c5 Adding "auto" to help for "--tb" option 2014-10-10 20:43:33 +00:00
holger krekel
2c84e9ddac remove unused import 2014-10-09 22:45:33 +02:00
holger krekel
b7dd8eac8e remove unused import 2014-10-09 22:45:33 +02:00
holger krekel
61d0209093 fix changelog 2014-10-09 17:06:39 +02:00
holger krekel
8b9bb5ff54 fix changelog 2014-10-09 17:06:39 +02:00
holger krekel
cb2c89a070 Merged in HolgerPeters/pytest (pull request #221)
Make doctest flags configurable
2014-10-09 17:05:48 +02:00
holger krekel
cea9367739 Merged in HolgerPeters/pytest (pull request #221)
Make doctest flags configurable
2014-10-09 17:05:48 +02:00
Holger Peters
e1a66d54b9 link fix: Use restructured text :doc: link instead of html link 2014-10-09 16:59:42 +02:00
Holger Peters
a37f9f19d4 link fix: Use restructured text :doc: link instead of html link 2014-10-09 16:59:42 +02:00
holger krekel
91aa6ab0df add changelog entry for new hookwrapper mechanism 2014-10-09 12:29:57 +02:00
holger krekel
c85c5d05c5 add changelog entry for new hookwrapper mechanism 2014-10-09 12:29:57 +02:00
holger krekel
34df678bc3 some docs and refined semantics for wrappers 2014-10-09 12:21:01 +02:00
holger krekel
8c91ffc701 some docs and refined semantics for wrappers 2014-10-09 12:21:01 +02:00
holger krekel
eda39f361d re-scan methods during plugin register and unregister and not
during hook calling anymore.  Simplify register/getplugin api of PluginManager
2014-10-09 10:47:32 +02:00
holger krekel
c58770bfef re-scan methods during plugin register and unregister and not
during hook calling anymore.  Simplify register/getplugin api of PluginManager
2014-10-09 10:47:32 +02:00
holger krekel
d9858844c3 improve docstring, remove unused custom Exception 2014-10-09 09:55:46 +02:00
holger krekel
04b8111f8f improve docstring, remove unused custom Exception 2014-10-09 09:55:46 +02:00
holger krekel
0253f7b8d5 remove all occurences of "__multicall__" on hook impls in pytest/*.
also simplify pytest_runtest_markereport hook in _pytest/skipping.py
while touching the code anyway.
2014-10-08 20:23:40 +02:00
holger krekel
5999368002 remove all occurences of "__multicall__" on hook impls in pytest/*.
also simplify pytest_runtest_markereport hook in _pytest/skipping.py
while touching the code anyway.
2014-10-08 20:23:40 +02:00
Holger Peters
bf2f2dc2a6 Add a doctest for module docstrings 2014-10-08 15:54:08 +02:00
Holger Peters
787b0212d1 Add a doctest for module docstrings 2014-10-08 15:54:08 +02:00
Holger Peters
1de5af66da Add documentation for doctest flags and remove dead code 2014-10-08 15:48:41 +02:00
Holger Peters
61caa4f776 Add documentation for doctest flags and remove dead code 2014-10-08 15:48:41 +02:00
Holger Peters
9ca7e46a0a Add configuration option for doctest flags 2014-10-08 14:31:17 +02:00
Holger Peters
f66e0825b2 Add configuration option for doctest flags 2014-10-08 14:31:17 +02:00
holger krekel
f5f924d293 - refactor wrapped call support to also accomodate
pytest.mark.hookwrapper
- introduce a CallOutcome class to hold the result/excinfo status of
  calling a function.
- rename add_method_controller to add_method_wrapper
2014-10-08 11:27:14 +02:00
holger krekel
c3d1986101 - refactor wrapped call support to also accomodate
pytest.mark.hookwrapper
- introduce a CallOutcome class to hold the result/excinfo status of
  calling a function.
- rename add_method_controller to add_method_wrapper
2014-10-08 11:27:14 +02:00
Floris Bruynooghe
89de87dce1 Document the ids keyword for fixture parametrisation
--HG--
branch : issue351
2014-10-08 00:43:27 +01:00
Floris Bruynooghe
ab005a4261 Functional tests for id function
--HG--
branch : issue351
2014-10-08 00:11:32 +01:00
holger krekel
3d6ad054c0 merge pytest default 2014-10-07 18:11:15 +02:00
holger krekel
b6e619413f merge pytest default 2014-10-07 18:11:15 +02:00
holger krekel
a43fb9cd93 fix add_method_controller to deal properly in the event of exceptions.
add a docstring as well.
2014-10-07 16:16:47 +02:00
holger krekel
68f3818562 fix add_method_controller to deal properly in the event of exceptions.
add a docstring as well.
2014-10-07 16:16:47 +02:00
holger krekel
1ed1ef3c71 open up pytest-2.6 branch in case we want to release a 2.6.4 before 2.7.0 happens
--HG--
branch : pytest-2.6
2014-10-07 11:14:57 +02:00
holger krekel
b6475b058f Merged in bubenkoff/pytest/test_for_issue_604 (pull request #220)
Escape % character in the assertion message
2014-10-07 09:06:47 +02:00
holger krekel
e39556ada0 Merged in bubenkoff/pytest/test_for_issue_604 (pull request #220)
Escape % character in the assertion message
2014-10-07 09:06:47 +02:00
Anatoly Bubenkov
966c63d477 merge with default
--HG--
branch : test_for_issue_604
2014-10-07 01:06:15 +02:00
Anatoly Bubenkov
a298077461 merge with default 2014-10-07 01:06:15 +02:00
Anatoly Bubenkov
e1aed27c15 Escape % character in the assertion message. closes #604
--HG--
branch : test_for_issue_604
2014-10-07 01:01:21 +02:00
Anatoly Bubenkov
a759da0208 Escape % character in the assertion message. closes #604 2014-10-07 01:01:21 +02:00
holger krekel
6ab36592ea docs for "pytest_addhooks" hook. Thanks Bruno Oliveira.
updated plugin index docs.  Thanks Bruno Oliveira.

fix issue557: with "-k" we only allow the old style "-" for negation
at the beginning of strings and even that is deprecated.  Use "not" instead.
This should allow to pick parametrized tests where "-" appeared in the parameter.
2014-10-06 14:26:03 +02:00
holger krekel
c45b7012f5 docs for "pytest_addhooks" hook. Thanks Bruno Oliveira.
updated plugin index docs.  Thanks Bruno Oliveira.

fix issue557: with "-k" we only allow the old style "-" for negation
at the beginning of strings and even that is deprecated.  Use "not" instead.
This should allow to pick parametrized tests where "-" appeared in the parameter.
2014-10-06 14:26:03 +02:00
holger krekel
1d10db4bab cleanup core collection of python methods and remove unncessary cache 2014-10-06 14:06:17 +02:00
holger krekel
767e44ef29 cleanup core collection of python methods and remove unncessary cache 2014-10-06 14:06:17 +02:00
Anatoly Bubenkov
4a11edfb68 Merged in issue557 (pull request #218)
fix issue557: with "-k" we only allow the old style "-" for negation
2014-10-06 13:42:53 +02:00
Anatoly Bubenkov
e53bb1af45 Merged in issue557 (pull request #218)
fix issue557: with "-k" we only allow the old style "-" for negation
2014-10-06 13:42:53 +02:00
Anatoly Bubenkov
e5d0862fa5 Close branch issue557
--HG--
branch : issue557
2014-10-06 13:42:53 +02:00
Anatoly Bubenkov
2ed4c2135a Close branch issue557 2014-10-06 13:42:53 +02:00
holger krekel
8cfec56a82 simplify internal pytester machinery 2014-10-06 13:37:57 +02:00
holger krekel
818a412d29 simplify internal pytester machinery 2014-10-06 13:37:57 +02:00
holger krekel
39158957f4 fix issue557: with "-k" we only allow the old style "-" for negation
at the beginning of strings and even that is deprecated.  Use "not" instead.
This should allow to pick parametrized tests where "-" appeared in the parameter.

--HG--
branch : issue557
2014-10-06 12:11:48 +02:00
holger krekel
2cb0145bce fix issue557: with "-k" we only allow the old style "-" for negation
at the beginning of strings and even that is deprecated.  Use "not" instead.
This should allow to pick parametrized tests where "-" appeared in the parameter.
2014-10-06 12:11:48 +02:00
holger krekel
dfda9acd6d add some changelog entries 2014-10-06 11:56:56 +02:00
holger krekel
c6951d5184 add some changelog entries 2014-10-06 11:56:56 +02:00
holger krekel
f85648bbf8 Merged in nicoddemus/pytest/defer-hook-example (pull request #216)
Documentation for new hooks and how to use them
2014-10-06 11:55:35 +02:00
holger krekel
dd1ee22293 Merged in nicoddemus/pytest/defer-hook-example (pull request #216)
Documentation for new hooks and how to use them
2014-10-06 11:55:35 +02:00
holger krekel
9def8522f3 Merged in nicoddemus/pytest (pull request #214)
added plugins_index page generation to tox
2014-10-06 11:23:41 +02:00
holger krekel
a999fcd36a Merged in nicoddemus/pytest (pull request #214)
added plugins_index page generation to tox
2014-10-06 11:23:41 +02:00
pytry
24468a6f34 Added test for ValueError in custom assert message with % sign (issue #604)
https://bitbucket.org/hpk42/pytest/issue/604/valueerror-unsupported-format-character-in

--HG--
branch : test_for_issue_604
2014-10-05 14:49:15 +02:00
pytry
ba8ae427e2 Added test for ValueError in custom assert message with % sign (issue #604)
https://bitbucket.org/hpk42/pytest/issue/604/valueerror-unsupported-format-character-in
2014-10-05 14:49:15 +02:00
Bruno Oliveira
d6d2e6c615 Adding docs on how to properly add new hooks and using them in 3rd party plugins
--HG--
branch : defer-hook-example
2014-10-04 14:48:19 -03:00
Bruno Oliveira
7f93063945 Adding docs on how to properly add new hooks and using them in 3rd party plugins 2014-10-04 14:48:19 -03:00
holger krekel
63f070317c simplify method to record calls 2014-10-04 15:49:31 +02:00
holger krekel
3d84f35850 simplify method to record calls 2014-10-04 15:49:31 +02:00
holger krekel
3d794b6b38 factor out a small "wrapping" helper 2014-10-04 15:49:31 +02:00
holger krekel
d8f4663f49 factor out a small "wrapping" helper 2014-10-04 15:49:31 +02:00
Dj Gilcrease
34b9f90f35 Merged in dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250 (pull request #1)
change the defaults from a tuple to a list so I can use config.addinivalue_line("norecursedirs", "...") to append new options in my own plugins
2014-10-02 14:33:48 -07:00
Dj Gilcrease
5ec1dd2609 Merged in dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250 (pull request #1)
change the defaults from a tuple to a list so I can use config.addinivalue_line("norecursedirs", "...") to append new options in my own plugins
2014-10-02 14:33:48 -07:00
Dj Gilcrease
b691cbd7e2 Close branch dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250
--HG--
branch : dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250
2014-10-02 14:33:48 -07:00
Dj Gilcrease
d7ada40130 Close branch dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250 2014-10-02 14:33:48 -07:00
Dj Gilcrease
2f141bbc54 change the defaults from a tuple to a list so I can use config.addinivalue_line("python_files", "...") to append new options in my own plugins
--HG--
branch : dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250
2014-10-02 21:32:35 +00:00
Dj Gilcrease
a098226ee4 change the defaults from a tuple to a list so I can use config.addinivalue_line("python_files", "...") to append new options in my own plugins 2014-10-02 21:32:35 +00:00
Dj Gilcrease
fd2572a39d change the defaults from a tuple to a list so I can use config.addinivalue_line("norecursedirs", "...") to append new options in my own plugins
--HG--
branch : dgilcrease/change-defaults-from-a-tuple-to-a-list-1412285169250
2014-10-02 21:27:19 +00:00
Dj Gilcrease
05d4a3f9eb change the defaults from a tuple to a list so I can use config.addinivalue_line("norecursedirs", "...") to append new options in my own plugins 2014-10-02 21:27:19 +00:00
holger krekel
2161b54555 remove overhead for tracing of hook calls and remove some old unused code 2014-10-02 15:25:42 +02:00
holger krekel
69ff29bf44 remove overhead for tracing of hook calls and remove some old unused code 2014-10-02 15:25:42 +02:00
holger krekel
de83d35994 optimize argument slicing when calling plugin hooks 2014-10-01 14:55:54 +02:00
holger krekel
c7c4f62f77 optimize argument slicing when calling plugin hooks 2014-10-01 14:55:54 +02:00
holger krekel
e635f9f9b2 simplify _scan_plugin implementation and store argnames on HookCaller 2014-10-01 13:57:35 +02:00
holger krekel
f250e912eb simplify _scan_plugin implementation and store argnames on HookCaller 2014-10-01 13:57:35 +02:00
holger krekel
351931d5ca call scanning of plugins directly, code is shifted from helpconfig.py to core.py 2014-10-01 12:20:11 +02:00
holger krekel
28c785a0d1 call scanning of plugins directly, code is shifted from helpconfig.py to core.py 2014-10-01 12:20:11 +02:00
holger krekel
3de715ec13 refine internal management of plugins and conftest files 2014-10-01 12:19:11 +02:00
holger krekel
ea5fb0c153 refine internal management of plugins and conftest files 2014-10-01 12:19:11 +02:00
holger krekel
9e549a1acf removed outdated japanese docs from source tree. 2014-09-29 12:31:15 +02:00
holger krekel
c7a45d6eaf removed outdated japanese docs from source tree. 2014-09-29 12:31:15 +02:00
Bruno Oliveira
37631dbfa0 added plugins_index page generation to tox
Also minor improvements in the page:
- Removed version from plugin name
- Using "home" instead of "repo", seems more appropriate
- Reduced default verbosity
2014-09-27 12:28:29 -03:00
Bruno Oliveira
e9f240a9a3 added plugins_index page generation to tox
Also minor improvements in the page:
- Removed version from plugin name
- Using "home" instead of "repo", seems more appropriate
- Reduced default verbosity
2014-09-27 12:28:29 -03:00
Bruno Oliveira
531be22a87 Fixed minor typo in plugins.txt 2014-09-27 11:59:59 -03:00
Bruno Oliveira
be93fdf11d Fixed minor typo in plugins.txt 2014-09-27 11:59:59 -03:00
Floris Bruynooghe
f05cb934a9 Merged in bubenkoff/pytest/better-diff-on-verbose-2 (pull request #213)
Improve assertion failure reporting on iterables, by using ndiff and pprint.
2014-09-27 09:09:16 +01:00
Floris Bruynooghe
82d806deb6 Merged in bubenkoff/pytest/better-diff-on-verbose-2 (pull request #213)
Improve assertion failure reporting on iterables, by using ndiff and pprint.
2014-09-27 09:09:16 +01:00
Anatoly Bubenkov
72e6f55b45 Improve assertion failure reporting on iterables, by using ndiff and pprint.
--HG--
branch : better-diff-on-verbose-2
2014-09-27 01:29:47 +00:00
Anatoly Bubenkov
9a0f2a9fb7 Improve assertion failure reporting on iterables, by using ndiff and pprint. 2014-09-27 01:29:47 +00:00
holger krekel
49b7237581 bump version to 2.6.4.dev 2014-09-24 16:27:34 +02:00
holger krekel
814d348e7d add release announce 2014-09-24 16:00:06 +02:00
holger krekel
88c14cad94 Added tag 2.6.3 for changeset 2967aa416a4f 2014-09-24 14:59:57 +02:00
holger krekel
b57545bd21 fix doc release version 2014-09-24 14:59:55 +02:00
holger krekel
2eef674615 regen and fix some docs (tox -e regen)
bump versions, depend on already released py-1.4.25
2014-09-24 14:46:56 +02:00
holger krekel
bf7c5ea32c add changelog: check xfail/skip also with non-python function test items. Thanks
Floris Bruynooghe.
2014-09-24 13:55:55 +02:00
Anatoly Bubenkov
d99243c1a7 rename orgname to pytest-dev
--HG--
branch : contributing-community
2014-09-24 10:53:08 +00:00
Floris Bruynooghe
62b8712ca9 Let xfail work on non-python Items
For some reason xfail was only implemented on non-python Item
instances.  This removes this guard which means plugins creating new
items can raise pytest.xfail.Exception and it will work as expected.
2014-09-23 23:55:26 +01:00
holger krekel
68105b3ae4 mention Wolfang wrt pytest_enter_pdb 2014-09-23 15:43:46 +02:00
holger krekel
be503f1c43 Merged in wosc/pytest (pull request #204)
Introduce pytest_enter_pdb hook
2014-09-23 14:04:47 +02:00
holger krekel
5abca55412 Merged in nicoddemus/pytest (pull request #203)
fix issue575: xunit-xml reporting collection errors as failures
2014-09-22 19:25:34 +02:00
holger krekel
79d2edcbff Merged in flub/pytest (pull request #207)
Show both user assertion msg as explanation (issue549)
2014-09-22 19:16:10 +02:00
holger krekel
e2c6a77f06 Merged in davidszotten/pytest/stop_leaking_fds (pull request #206)
stop leaking file descriptors
2014-09-22 15:02:48 +02:00
David Szotten
35eec99d41 stop leaking file descriptors
tripps --lsof on os x but not on linux. there's possibly a bug in the leak
detector (not investigated here)

--HG--
branch : stop_leaking_fds
2014-09-22 13:56:07 +01:00
holger krekel
e4fde1048b Merged in davidszotten/pytest/dontreadfrominput-encoding (pull request #205)
add `encoding` attr to DontReadFromInput
2014-09-22 13:34:50 +02:00
David Szotten
bc4eecbbac add encoding attr to DontReadFromInput
required by https://docs.python.org/2/library/stdtypes.html#file.encoding

and used e.g. by ipdb at _import_ time

--HG--
branch : dontreadfrominput-encoding
2014-09-22 12:19:27 +01:00
Wolfgang Schnerring
1408c9f077 Introduce pytest_enter_pdb hook 2014-09-18 14:58:42 +02:00
Bruno Oliveira
418607846a fix issue575: xunit-xml reporting collection errors as failures 2014-09-15 22:04:46 -03:00
holger krekel
6aa5611ae5 fix issue584: fix py3 syntax errors for example/special.txt.
Thanks Bruno Oliveira.
2014-09-15 15:04:09 +02:00
holger krekel
c5c9fb93aa fix link to pylib 2014-09-15 14:04:31 +02:00
Anatoly Bubenkov
86961291e5 add badges to the readme 2014-09-15 11:07:28 +00:00
Anatoly Bubenkov
7c1dadee51 Merged in conftest-nodeid (pull request #202)
fix conftest related fixture visibility issue
2014-09-15 13:04:07 +02:00
Anatoly Bubenkov
b16553e34e Close branch conftest-nodeid
--HG--
branch : conftest-nodeid
2014-09-15 13:04:07 +02:00
holger krekel
b6dcfd4377 fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.

--HG--
branch : conftest-nodeid
2014-09-15 12:44:16 +02:00
holger krekel
1a80487e71 fix issue589: fix bad interaction with numpy and others when showing
exceptions.  check for precise "maximum recursion depth exceed" exception
instead of presuming any RuntimeError is that one (implemented in py dep)
Thanks Charles Cloud for analysing the issue.
2014-09-14 17:24:27 +02:00
holger krekel
488720da8d fix a broken link 2014-09-10 09:57:12 +02:00
holger krekel
0264121c10 fix issue587: claim only python2.6 compat in README/pypi project page, thanks sscarwell 2014-09-09 11:22:39 +02:00
Floris Bruynooghe
d2f448ecee Improve pytest.raises examples
Fixes issue #586.
2014-09-08 14:26:31 +01:00
Floris Bruynooghe
c692a0ee9c Remove jython from tested python versions
After testing with the jython 2.7 beta it seems it will require some
work to get jython back working.  So for now remove it from this list
so it doesn't get picked up by normal test runs.
2014-09-06 18:44:18 +01:00
Anatoly Bubenkov
8844d9d04f detalize the plugin development proposal
--HG--
branch : contributing-community
2014-09-06 02:37:48 +02:00
Floris Bruynooghe
4063b7f8e0 Mention PR #194 in the changelog 2014-09-06 00:00:43 +01:00
Floris Bruynooghe
a8dfe34bfb Merged in uweschmitt/pytest/default (pull request #194) 2014-09-05 23:57:18 +01:00
Floris Bruynooghe
7d9d502a01 Use py3k compatible .__getattr__() code
From the python-dev thread it seemed like using
object.__getattribute__(self, 'name') is the cleanest way of
implementing a class wich uses .__getattr__() and should be
pickelable.  That only works on new-style classes so this also turns
HookProxy into a new-style class on py2.

This also re-writes the test to not use cPickle so it runs on py3k.
2014-09-05 23:55:14 +01:00
holger krekel
09a44f4cac fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny
Pfannschmidt.
2014-09-05 15:34:01 +02:00
holger krekel
b14b9515a5 mention XXX regendoc for release process 2014-09-05 13:55:58 +02:00
holger krekel
2a504a5bcd regen docs for 2.6.2 2014-09-05 13:55:00 +02:00
holger krekel
dfcdf644fe Added tag 2.6.2 for changeset a4f25c5e6498 2014-09-05 13:47:48 +02:00
holger krekel
7dad3cb157 prepare 2.6.2, release announcement, also add HOWTORELEASE.rst 2014-09-05 13:13:23 +02:00
holger krekel
745737e337 strike python2.5 from test code cc @flub 2014-09-05 09:50:40 +02:00
Floris Bruynooghe
eae1055fb0 Merged in nocoddemus/pytest/cx_freeze-support (pull request #189) 2014-09-03 21:55:46 +01:00
holger krekel
2e1c36bbb6 merged in flub/pytest (PR #195) 2014-09-02 12:33:19 +02:00
holger krekel
e3cea41dcd fix issue572 - python3 compat of tmpdir example in docs. 2014-09-02 12:20:16 +02:00
Benjamin Peterson
c0f091d540 remove debugging turd 2014-09-01 16:51:44 -04:00
Benjamin Peterson
d4cd1aad8e improvements to rewrite cache invalidation
- stat the source path before it is read.
- Validate the source size in addition to mtime.
2014-09-01 16:51:27 -04:00
Floris Bruynooghe
39a297afe6 Improve test by also matching expected output 2014-08-30 21:57:01 +01:00
Floris Bruynooghe
068548f7a9 Merged in flub/pytest (pull request #196) 2014-08-27 21:00:24 +01:00
Bruno Oliveira
0c163ce624 Updating plugins_index
Also fixed duplicated links when repository is not github or
bitbucket
2014-08-26 20:38:19 -03:00
Floris Bruynooghe
7760cf1881 Fix doctest tox run
The new failures in the failure demo apparently affect the
doctests tox run.
2014-08-23 19:01:26 +02:00
Floris Bruynooghe
37bd1e03cb Show user assertion messages and instrospection together
User provided messages, or any valid expression given as second
argument to the assert statement, are now shown in addition to the
py.test introspection details.  Formerly any user provided message
would entirely replace the introspection details.

Fixes issue549.
2014-08-23 18:14:25 +02:00
Bruno Oliveira
fc95877622 Added changelog entry for freeze_includes()
--HG--
branch : cx_freeze-support
2014-08-23 10:10:32 -03:00
Bruno Oliveira
03b694a1d0 merging with default
--HG--
branch : cx_freeze-support
2014-08-23 10:05:40 -03:00
Floris Bruynooghe
79c2a47985 Improve the docstring further 2014-08-23 12:10:16 +02:00
Floris Bruynooghe
9289d77a80 Mention why no universal wheel in changelog
Fixes issue566.
2014-08-22 20:22:51 +02:00
Floris Bruynooghe
2eee2d0099 Merged in sontek/pytest/fix_universal (pull request #198)
Removed marking pytest as universal, py26 and py27 are not compatible.
2014-08-22 20:16:17 +02:00
sontek@gmail.com
0ea46e6aef Removed marking pytest as universal, py26 and py27 are not compatible.
--HG--
branch : fix_universal
2014-08-21 12:47:53 -07:00
Anatoly Bubenkov
54e00429e4 plugin organization proposal
--HG--
branch : contributing-community
2014-08-20 00:52:40 +02:00
Floris Bruynooghe
b0ac3581dd Mention doc fix in changelog 2014-08-19 21:00:46 +02:00
Floris Bruynooghe
e7ed45a5d4 Explain why this is important 2014-08-19 20:50:25 +02:00
uweschmitt
d1bde69c1e added smoke test for bug fixed in 3716:dc080608b6d1 2014-08-19 12:57:37 +02:00
Thomas Weißschuh
7cf859085e [doc] fix requests monkeypatch example 2014-08-18 19:44:34 +00:00
Floris Bruynooghe
424479cf0f Escape newlines in repr for assertion rewriting
The assertion formatting mini-language depends on newlines being
escaped.  Unfortunately if the repr of an object contained
newlines the rewriting module did not escape those, which is now
fixed.

Fixes issue453.
2014-08-18 20:07:38 +02:00
Floris Bruynooghe
98dcd764bc Depend on newer version of py
This fixes issue560, a test for which is included here as well.
2014-08-14 23:23:04 +01:00
Bruno Oliveira
ccd67733fb standard lib modules no longer required in freeze_includes() and updated docs
--HG--
branch : cx_freeze-support
2014-08-11 20:20:41 -03:00
Bruno Oliveira
5873ca5146 Merging with default
--HG--
branch : cx_freeze-support
2014-08-11 20:07:11 -03:00
Bruno Oliveira
d2903507d8 Moved freeze_includes() to genscript
--HG--
branch : cx_freeze-support
2014-08-11 20:03:14 -03:00
uweschmitt
224b3a2eda hopefully final fix for strange infinite recursion bug 2014-08-11 12:57:47 +02:00
uweschmitt
5d024c7433 hopefully final fix for strange infinite recursion bug 2014-08-11 12:42:36 +02:00
holger krekel
9232b88df3 actually regen fixture docs with python3.4 instead of python2.7 (doh) 2014-08-08 15:25:16 +02:00
holger krekel
e98f77037e fix issue561 example adapted to python3. 2014-08-08 15:20:37 +02:00
holger krekel
672e42e558 fix doc config for latex 2014-08-07 23:05:02 +02:00
holger krekel
36d7df4542 Added tag 2.6.1 for changeset a4f9639702ba 2014-08-07 22:55:17 +02:00
holger krekel
e5eaf02e19 finalize pytest-2.6.1 release, regen docs 2014-08-07 21:41:51 +02:00
uweschmitt
c0d1f3f7ef even better fix as replacement for last commit which was wrong 2014-08-07 17:17:05 +02:00
uweschmitt
9597d3dafe better fix as replacement for last commit 2014-08-07 16:56:45 +02:00
uweschmitt
f7282b84bd fixed strange infinite recursion bug 2014-08-07 16:13:12 +02:00
holger krekel
1d7b574b31 fix issue555: just add "errors" attribute to internal Capture stream. 2014-08-07 11:05:42 +02:00
holger krekel
d16fdb378c merge PR192, streamline a bit. 2014-08-07 10:42:23 +02:00
Bruno Oliveira
cc092afd3b updated CHANGELOG and trace error message as requested in review
fixes issue #437

--HG--
branch : assertionrewrite-currupted-pyc
2014-08-04 20:38:50 -03:00
Bruno Oliveira
fd4485a540 Fixed assertionrewrite._read_pyc to handle corrupted pyc files properly
This seems to be the cause for issues #437 and #301.

--HG--
branch : assertionrewrite-currupted-pyc
2014-08-02 18:01:28 -03:00
Floris Bruynooghe
3b8779ad17 Mention change in -v output in changelog 2014-08-01 23:11:25 +01:00
Floris Bruynooghe
3e875178ad Merge default 2014-08-01 23:06:24 +01:00
holger krekel
97b671057d put some imports back to function-level and streamline py2/py3 compat in one place 2014-08-01 10:12:53 +02:00
holger krekel
d6fc489b2b Backed out changeset e57017ad86ce -- logging should not be imported 2014-08-01 08:13:44 +02:00
Floris Bruynooghe
4e8438afc8 Simply show the node ID for verbose output
This strips the line number, /@\d/, from the verbose output so it is
directly the node ID of the test.  This in turn means no special logic
for accepting the line number as part of the node ID is needed when
parsing the command line.
2014-08-01 00:29:35 +01:00
Bruno Oliveira
b1f8038abf Minor fixed in test_capture
This test failed only in py34. We don't import logging directly,
but it seems that one of the standard modules that are now
globally imported started including this on py34.

Just removed the assert as it doesn't seem central to the
test's objective.
2014-07-31 19:52:08 -03:00
Bruno Oliveira
5603a0cd4b Removing py.std usage from _pytest 2014-07-31 19:13:40 -03:00
Bruno Oliveira
3c649cf91d guarding scripts with __main__ and doc changes
tox-flakes environment tries to import the modules for
checking, and that may fail because of its dependencies

--HG--
branch : cx_freeze-support
2014-07-30 22:28:03 -03:00
Bruno Oliveira
82d573e391 fixed line endings for test_doctest.txt
--HG--
branch : cx_freeze-support
2014-07-30 21:57:19 -03:00
Bruno Oliveira
b7b96b24d8 Docs about cx_freeze support and minor adjustments
--HG--
branch : cx_freeze-support
2014-07-30 21:50:00 -03:00
Bruno Oliveira
990e7bf3b9 first implementation and tox environment for cx-freeze support
--HG--
branch : cx_freeze-support
2014-07-30 19:16:51 -03:00
holger krekel
bcdc3d0154 reorder talks, more talks from pelme and others 2014-07-29 15:06:37 +02:00
holger krekel
faea7e1407 add flub and pelme talks at EuroPython2014, remove one past training note 2014-07-29 15:00:45 +02:00
holger krekel
7c701948d5 Merged in nicoddemus/pytest/cx_freeze-docs (pull request #188)
Documentation example on how to integrate pytest and cx_freeze
2014-07-29 12:43:04 +02:00
Bruno Oliveira
899b804ec1 Improved the text a little
--HG--
branch : cx_freeze-docs
2014-07-28 22:46:57 -03:00
Bruno Oliveira
66bd4e485a Adding blurb about using pytest runner and cx_freeze
--HG--
branch : cx_freeze-docs
2014-07-28 22:40:23 -03:00
Anatoly Bubenkov
8ff8dd3ae9 Merged in fix_initial_parsing (pull request #186)
Fix issue544 and fix another issue with parsing ``::``
2014-07-28 14:16:02 +02:00
holger krekel
0d17dc1e19 add a comment for why we only consider .py files when removing @
--HG--
branch : fix_initial_parsing
2014-07-28 13:56:10 +02:00
holger krekel
83e0b52294 speedup @ replacement for the massive lists from pytest-bdd :)
--HG--
branch : fix_initial_parsing
2014-07-28 13:53:53 +02:00
holger krekel
1265612465 fix issue547 2.6 regression: capsys/capfd now work again when output capturing ("-s") is disabled. 2014-07-28 13:17:37 +02:00
holger krekel
40eed363e8 fix issue544 by only removing "@NUM" at the end of a part (parts are
separated by "::") and if the part has an .py extension.

--HG--
branch : fix_initial_parsing
2014-07-28 12:07:15 +02:00
holger krekel
5ccd3f2fc5 fix conftest detection if commandline arguments contain "::" syntax
--HG--
branch : fix_initial_parsing
2014-07-28 11:48:37 +02:00
holger krekel
ba878c6d9d add changelog entry and refactor unittest.mock.patch fix a bit 2014-07-28 10:34:01 +02:00
holger krekel
8792261df1 Merged in ticosax/pytest/mock-unittest-252 (pull request #184)
Injection of fixture doesn't work when decorated with unittest.mock.patch
2014-07-28 10:31:31 +02:00
holger krekel
c2ed29070a address issue170 by merging David Mohr's PR on adding "raises" as an optional
argument to pytest.mark.xfail.
2014-07-28 09:59:22 +02:00
holger krekel
38104dfc92 Merged in squisher/pytest/xfail-cause (pull request #183)
Add mark.xfail argument raises so that unexpected exceptions show up as test failures.
2014-07-28 09:55:02 +02:00
Nicolas Delaby
2e55c4ba61 unittest.mock from stdlib should come last
--HG--
branch : mock-unittest-252
2014-07-27 12:11:39 +02:00
Nicolas Delaby
e6ad6e02d2 Handle also unittest.mock
Move handling in dedicated function to isolate its logic

--HG--
branch : mock-unittest-252
2014-07-27 10:43:50 +02:00
david@mcbf.net
d08c4ce0ad Tiny example update for clarification
--HG--
branch : xfail-cause
2014-07-26 18:24:55 +02:00
david@mcbf.net
309e3d38a0 Directly pass multiple parameters with mark.parametrize()
--HG--
branch : xfail-cause
2014-07-26 18:19:27 +02:00
david@mcbf.net
91e2b23258 Update documentation
--HG--
branch : xfail-cause
2014-07-26 18:10:32 +02:00
david@mcbf.net
6a4492a22d isinstance() on exception value instead of comparing types, consolidate tests
--HG--
branch : xfail-cause
2014-07-26 17:46:50 +02:00
Nicolas Delaby
0dd378da30 Injection of fixture doesn't work when decorated with unittest.mock.patch
This is a continuation of #182

--HG--
branch : mock-unittest-252
2014-07-26 17:26:18 +02:00
david@mcbf.net
7b273b8577 Add mark.xfail argument raises so that unexpected exceptions show up as test failures.
--HG--
branch : xfail-cause
2014-07-26 15:11:05 +02:00
holger krekel
d98521b0d9 Added tag 2.6.0 for changeset 88af949b9611 2014-07-20 13:15:44 +02:00
holger krekel
52011e84d3 merge 2014-07-20 13:15:21 +02:00
holger krekel
de583ed7a3 some notes about upcoming trainings 2014-07-20 13:07:38 +02:00
holger krekel
f8480caae4 Added tag 2.6.0 for changeset 60725b17a9d1 2014-07-20 13:03:11 +02:00
holger krekel
47d9e6ca1f fix release announce 2014-07-20 11:07:18 +02:00
Bruno Oliveira
6f0a33dfdc Updating plugins_index 2014-07-18 21:10:50 -03:00
Floris Bruynooghe
1641d00cb1 Merge default 2014-07-18 01:34:08 +01:00
Floris Bruynooghe
2d7a32f7ea Add test case for using different modules 2014-07-18 01:30:29 +01:00
holger krekel
06acbb9f5e bump doc version 2014-07-17 17:22:44 +02:00
holger krekel
7b630d9080 mention next open trainings at EP2014 and in Freiburg in November 2014 2014-07-17 17:21:45 +02:00
holger krekel
98de64badc regen docs for pytest-2.6 2014-07-17 16:55:24 +02:00
holger krekel
1e241e1f2a mention py34 compatibility 2014-07-17 16:49:10 +02:00
holger krekel
ff2c18fedb bump version, preliminary announcement 2014-07-17 16:38:54 +02:00
holger krekel
bf64a800d6 pytest depends on the freshly released 1.4.22 to function properly 2014-07-17 10:55:52 +02:00
Jurko Gospodnetić
efc57391eb remove extra parentheses - stylistic code change 2014-07-17 08:35:36 +02:00
Benjamin Peterson
dc65aa1fea avoid importing old assertion interpretation code by default (fixes #537) 2014-07-16 17:21:18 -07:00
holger krekel
80ad3fb8ed Merged in wooparadog/pytest (pull request #163)
Also replace `report.longrepr` with `bin_xml_escape`ed skipreason
2014-07-15 22:17:15 +02:00
holger krekel
bc7110931a Merged in alex_gaynor/pytest/alex_gaynor/marked-pytest-as-being-a-universal-wheel-1405267754279 (pull request #179)
Marked pytest as being a universal wheel.
2014-07-15 11:26:08 +02:00
holger krekel
8c508612ec with pypy this tests leaks one FD but it's probably a residual effect of the testing machinery and Pypy's lazy GC. 2014-07-14 09:17:04 +02:00
Alex Gaynor
b7d046527e Marked pytest as being a universal wheel.
--HG--
branch : alex_gaynor/marked-pytest-as-being-a-universal-wheel-1405267754279
2014-07-13 16:09:24 +00:00
holger krekel
42804c52e8 Merged in bmcorser/pytest-1/bmcorser/scratching-an-itch-love-pytest-1404943207227 (pull request #178)
Scratching an itch. Love py.test!
2014-07-10 09:00:24 +02:00
bmcorser
d88a3712c5 Scratching an itch. Love py.test!
--HG--
branch : bmcorser/scratching-an-itch-love-pytest-1404943207227
2014-07-09 22:00:24 +00:00
Bruno Oliveira
abfedd692e Updating plugins_index 2014-07-08 20:08:19 -03:00
holger krekel
d0b048c86d Merged in msabramo/pytest/norecursedirs_add_star_dot_egg (pull request #177)
Add *.egg to default for norecursedirs
2014-07-03 16:51:17 +02:00
Marc Abramowitz
b6f069f4c3 Add *.egg to default for norecursedirs
--HG--
branch : norecursedirs_add_star_dot_egg
2014-07-03 07:49:03 -07:00
holger krekel
edc2e5ab82 Merged in msabramo/pytest/fix_norecursedirs_doc_typos (pull request #176)
doc/en/customize.txt: Fix norecursedirs typo
2014-07-03 16:47:58 +02:00
Marc Abramowitz
6da9a087f8 doc/en/customize.txt: Fix norecursedirs typo
and update documented default to match current default.

--HG--
branch : fix_norecursedirs_doc_typos
2014-07-03 07:36:07 -07:00
holger krekel
e19462d581 fix ordering of import line of last commit 2014-07-03 13:20:51 +02:00
holger krekel
a811fabb43 avoid importing "py.test" (an old alias module for "pytest") 2014-07-03 12:58:12 +02:00
holger krekel
07e76cbef2 fix issue364: shorten and enhance tracebacks representation by default.
The new "--tb=auto" option (default) will only display long tracebacks
for the first and last entry.  You can get the old behaviour of printing
all entries as long entries with "--tb=long".  Also short entries by
default are now printed very similarly to "--tb=native" ones.
2014-06-29 13:32:53 +02:00
holger krekel
76d5c9e4f4 Merged in c_henz/pytest/explicit-ini-filename (pull request #175)
Implement the "-c" command line switch that allows to explicitly specifiy the config file to load.
2014-06-29 12:08:29 +02:00
holger krekel
abcadc4202 colors as used on the live web page 2014-06-29 09:47:50 +02:00
Christian Henz
b7f6a9f3fd Cleaner implementation of early handling of the '-c' command line switch.
--HG--
branch : explicit-ini-filename
2014-06-28 12:03:55 +02:00
christian@christian-linux.sarrazin.local
c8264385ea Implement the "-c" command line switch that allows to explicitly specifiy the config file to load.
This feature was requested in issue #174.

--HG--
branch : explicit-ini-filename
2014-06-27 17:42:37 +02:00
Floris Bruynooghe
ad8131be9e Re-add accidentally removed changelog items 2014-06-24 22:46:57 +01:00
holger krekel
54c88a6cf3 fix flakes issues 2014-06-16 11:27:32 +02:00
Floris Bruynooghe
115f15600f Add test for inter-dependent fixtures
Together with cc0a46a13ac4 this fixes issue 467.
2014-06-15 19:57:52 +01:00
Bruno Oliveira
65a145e2a7 Updated plugins index 2014-06-10 19:04:52 -03:00
holger krekel
5719a72eeb Merged in zyegfryed/pytest/zyegfryed/fixed-typo-noticed-by-dcramer-httpstwitt-1401780587159 (pull request #172)
Fixed typo noticed by @zeeg (https://twitter.com/zeeg/status/473676721128886272)
2014-06-03 09:49:02 +02:00
Sébastien Fievet
4bc4495115 Fixed typo noticed by @dcramer (https://twitter.com/zeeg/status/473676721128886272)
--HG--
branch : zyegfryed/fixed-typo-noticed-by-dcramer-httpstwitt-1401780587159
2014-06-03 07:30:14 +00:00
holger krekel
c66e9f8f0f fix typo, thanks @dcramer 2014-06-03 07:21:02 +02:00
holger krekel
52eafdc21e also add favicon 2014-06-01 12:36:31 +02:00
holger krekel
85c0d5481b incorporate the new pytest logo 2014-06-01 12:01:40 +02:00
Benjamin Peterson
fd9055fd11 fix test on Python 3.2 2014-05-31 14:51:05 -07:00
Benjamin Peterson
780bdda95a assert reinterpretation: try mangling attributes that look like private class vars (fixes #514) 2014-05-31 14:37:02 -07:00
Bruno Oliveira
fd4b461290 Updated plugins_index and updated python 3 to 3.4 2014-05-28 23:16:49 -03:00
holger krekel
040062e40c improve example for pytest integration with "python setup.py test"
which now has a generic "-a" or "--pytest-args" option where you
can pass additional options as a quoted string.  Thanks Trevor Bekolay.
2014-05-19 20:32:09 +02:00
holger krekel
d853e9167a Merged in tbekolay/pytest/tbekolay/better-setuptools-integration-in-goodpra-1400520902689 (pull request #171)
Better setuptools integration in goodpractices
2014-05-19 20:30:54 +02:00
Trevor Bekolay
d50ad270f0 Better setuptools integration in goodpractices
--HG--
branch : tbekolay/better-setuptools-integration-in-goodpra-1400520902689
2014-05-19 17:35:28 +00:00
holger krekel
30c93701a7 fix issue516: tell in getting-started about current dependencies.
cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
2014-05-14 09:58:34 +02:00
holger krekel
b507e1754c fix issue512 : document dependencies in getting-started doc. 2014-05-14 09:14:40 +02:00
holger krekel
748fce94fd Merged in jurko/pytest/setup cleanup (pull request #169)
setup.py cleanup/update (updated from pull request #167)
2014-05-14 09:10:13 +02:00
holger krekel
d6281b4206 - restore compatibility to old getvalueorskip behaviour
- introduce a better NOTSET representation to improve docs
2014-05-14 07:36:31 +02:00
holger krekel
b61ed2cf7e Merged in jurko/pytest/python 3.1 fix (pull request #168)
use py.builtin.callable instead of raw callable in _pytest/runner.py
2014-05-13 22:41:12 +02:00
Jurko Gospodnetić
9263f30c88 use py.builtin.callable instead of raw callable in _pytest/runner.py
This is consistent with how callable() is called from the rest of pytest code
(see _pytest/nose.py & _pytest/python.py) plus, as a nice side-effect, it
makes pytest work correctly on Python 3.1.

--HG--
branch : python 3.1 fix
2014-05-13 21:05:53 +02:00
Jurko Gospodnetić
8f9a88ef7a update the list of officially supported Python versions in setup.py
Removed Python 3.0 & 3.1 off the list and added Python 3.4.

--HG--
branch : setup cleanup
2014-05-13 19:03:17 +02:00
Jurko Gospodnetić
c64af0d9ce stylistic setup.py code cleanup
--HG--
branch : setup cleanup
2014-05-13 19:02:02 +02:00
holger krekel
9181df42da Merged in msabramo/pytest/require_argparse_for_py3_lt_32 (pull request #166)
setup.py: Require argparse for PY3 < 3.2
2014-05-11 19:30:11 +02:00
holger krekel
74e1a49dd7 remove the idea that nose support should be moved to a plugin. 2014-05-10 14:00:09 +02:00
holger krekel
468b1241a5 fix issue512: show "<notset>" for arguments which might not be set
in monkeypatch plugin.  Improves output in documentation.
2014-05-10 13:49:24 +02:00
Marc Abramowitz
24744cf5cf setup.py: Require argparse for PY3 < 3.2
E.g.: python3.1; noticed py31 failure while running tox for six

--HG--
branch : require_argparse_for_py3_lt_32
2014-05-09 23:40:06 -07:00
Floris Bruynooghe
ffc969b6c2 Do not list python 2.5 as supported in the docs 2014-05-01 22:25:03 +01:00
WooParadog
0567a8ee77 Add test for skipped case with utf-8 message 2014-04-24 10:45:39 +08:00
WooParadog
580c8525f0 Use processced skipreason for generating skip Junit node 2014-04-23 15:38:40 +08:00
WooParadog
d6010aa0c9 Also replace report.longrepr with bin_xml_escapeed skipreason 2014-04-23 14:50:21 +08:00
Brianna Laugher
4e35c00ab0 issue351: Add ability to specify parametrize ids as a callable, to generate custom test ids. + tests, docs
--HG--
branch : issue351
2014-04-17 15:08:49 -04:00
Floris Bruynooghe
c46e2cbbc7 Cache exception raised in fixtures according to their scope
Without this if a session scoped fixture fails it's setup it will
be re-tried each time it is requested.  Especially in case of
skip or failure exceptions this can be undesirable, but caching
makes sense for all exceptions.
2014-04-15 22:22:41 -04:00
Floris Bruynooghe
c47835f5ec Merge pull request #158, fixes issue 504 2014-04-15 11:43:38 -04:00
Floris Bruynooghe
412b56f7cf Changelog for issue 475 2014-04-14 18:12:29 -04:00
Floris Bruynooghe
faba432996 Improve error message if pytest.raises is used wrongly
If the type is not checked then an incomprehensible error will occur
later.  This enforces the type and raies the same exception/msg as
CPython does in that case.

Docstring unmodified, just re-justified for pep8 compat.
2014-04-14 18:09:10 -04:00
Andy Freeland
2ba23e8d08 issue504: verbose output displays node IDs for each test
Replace the verbose per-test reporting format of `file:line test_name RESULT`
with the node ID of the test, i.e. `file@line::class::method[param] RESULT`.

This patch does not update the examples in the docs; @hpk42 has a script
to regenerate those.

--HG--
branch : issue504
2014-04-14 17:42:02 -04:00
Floris Bruynooghe
d74f852fd6 Merged in rouge8/pytest/issue499 (pull request #157)
fix issue499: document selecting tests by node ID
2014-04-14 14:31:07 -04:00
Andy Freeland
1728798e81 Interal link to node ID explanation
--HG--
branch : issue499
2014-04-14 14:24:13 -04:00
Andy Freeland
53a8d20d88 fix issue499: document selecting tests by node ID
--HG--
branch : issue499
2014-04-14 12:27:55 -04:00
Floris Bruynooghe
61446faa17 Update changelog with last change 2014-04-12 17:01:05 -04:00
Floris Bruynooghe
9711e335d9 Change XPASS colour to be yellow rather then red
Unfortunately I'm not sure how to test this.
2014-04-12 10:27:12 -04:00
Anatoly Bubenkov
080a9d2f12 Merged in hpk42/pytest-hpk/nose_test_attr (pull request #154)
support nose-style __test__ attribute to disable collection of test modules/classes/functions
2014-04-10 22:38:53 +02:00
holger krekel
15af7e1662 fix tests to properly fail on failed collectiosn (which was hiding an error)
and also implement __test__=False for test functions properly.

--HG--
branch : nose_test_attr
2014-04-10 13:37:39 +02:00
holger krekel
e42cbc714f fix wrong merge
--HG--
branch : nose_test_attr
2014-04-10 12:58:10 +02:00
holger krekel
5e26e6e553 fix typo in changelog
--HG--
branch : nose_test_attr
2014-04-10 12:56:14 +02:00
holger krekel
d0a4d348fe merge default
--HG--
branch : nose_test_attr
2014-04-10 12:53:33 +02:00
holger krekel
494be731e3 support nose-style `__test__` attribute on modules, classes and
functions, including unittest-style Classes.  If set to True, the
test will not be collected.

--HG--
branch : nose_test_attr
2014-04-10 12:46:27 +02:00
Ronny Pfannschmidt
8ae244a06a Merged in hpk42/pytest-hpk/issue473 (pull request #152)
fix issue473: work around mock putting an unbound method into a class
2014-04-09 06:46:01 +02:00
holger krekel
f91049cec9 fix issue473: work around mock putting an unbound method into a class
dict when double-patching.

--HG--
branch : issue473
2014-04-08 12:50:13 +02:00
Ronny Pfannschmidt
270d0f89ba Merged in hpk42/pytest-hpk/issue498 (pull request #151)
fix issue498: if a fixture finalizer fails, make sure that the fixture
2014-04-07 13:51:03 +02:00
holger krekel
e382ed4245 fix issue439: clarify that capsys/capfd capture output during
test execution, not test setup.
2014-04-07 13:42:48 +02:00
holger krekel
ef7cb47b1e fix issue498: if a fixture finalizer fails, make sure that the fixture
is still invalidated.

--HG--
branch : issue498
2014-04-07 13:29:57 +02:00
holger krekel
6efde60b8b Merged in jurko/pytest/jurko/tox_usage (pull request #150)
runtox.py cleanup
2014-04-06 08:16:24 +02:00
Jurko Gospodnetić
fd059359cc make runtox.py not import external modules unless run as a script
Was not needed since the script actually does nothing unless run as a script.

--HG--
branch : jurko/tox_usage
2014-04-05 08:51:00 +02:00
Jurko Gospodnetić
c2c504797e stylistic runtox.py code cleanup
--HG--
branch : jurko/tox_usage
2014-04-05 08:49:30 +02:00
Jurko Gospodnetić
84f9f45f98 fix runtox.py failure when 'tox' is not available on the current system path
Now just assumes that the tox module is available in the executing Python
environment.

--HG--
branch : jurko/tox_usage
2014-04-05 08:47:04 +02:00
holger krekel
28aa4c891e bump version to 2.6.0.dev1 because i think we are going for a 2.6.0 release next
and not just a 2.5 maintenance one.
2014-04-03 22:27:04 +02:00
holger krekel
6ff0fdb977 fix issue443: fix skip examples to use proper comparison. Thanks Alex
Groenholm.
2014-04-03 22:26:10 +02:00
holger krekel
b0837693d0 add some changelog entries 2014-04-03 10:04:09 +02:00
holger krekel
52851e4388 Merged in jurko/pytest/fix_capfd_fixture_docstring (pull request #149)
correct a capfd fixture docstring typo
2014-04-03 10:02:00 +02:00
holger krekel
cbe31f3748 Merged in msabramo/pytest/makepyfile_utf8 (pull request #134)
Make makepyfile accept UTF-8 so a few cookie tests in test_assertrewrite.py
2014-04-03 10:00:24 +02:00
Jurko Gospodnetić
c9bbdf4f10 correct a capfd fixture docstring typo
--HG--
branch : fix_capfd_fixture_docstring
2014-04-03 09:59:04 +02:00
holger krekel
f984e94fca Merged in jurko/pytest/break_ExceptionInfo_reference_cycles (pull request #144)
break reference cycles caused by storing local reference to exception info
2014-04-03 09:47:41 +02:00
Anatoly Bubenkov
b4fe91943d Merged in hpk42/pytest-hpk/conftest-clean (pull request #148)
cleanup internal conftest handling and avoid the strange None entry in the conftest cache.
2014-04-03 09:38:47 +02:00
Anatoly Bubenkov
7d6317802e Merged in hpk42/pytest-hpk/issue486 (pull request #147)
fix issue486: better reporting and handling of early conftest loading failures
2014-04-03 00:19:05 +02:00
holger krekel
0365e5c3a0 cleanup internal conftest handling and avoid the strange None entry in the conftest cache.
(There is basically no reason to ask for conftestmodules without specifying a path.)

--HG--
branch : conftest-clean
2014-04-02 22:30:45 +02:00
holger krekel
e6859406f1 fix test on py33, thanks msabramo1 2014-04-02 20:49:57 +02:00
holger krekel
51cff6f106 fix issue486: better reporting and handling of early conftest loading failures
--HG--
branch : issue486
2014-04-02 20:42:41 +02:00
holger krekel
68e58e1493 add a test for robustness of capturing when a test closes FD1/2 2014-04-02 20:29:10 +02:00
holger krekel
9f7eac0ba1 Merged in msabramo/pytest/add_drone_io_to_README_rst (pull request #143)
README.rst: Add drone.io link
2014-04-02 19:13:26 +02:00
Floris Bruynooghe
b0e31dca86 Mention fix for issue 453 in changelog 2014-04-02 18:00:25 +01:00
holger krekel
7d10a57514 Merged in msabramo/pytest/remove_unused_import (pull request #146)
testing/test_capture.py: Remove unused stuff for PEP8 compliance
2014-04-02 18:56:46 +02:00
Marc Abramowitz
2c0f6207e9 test_capture.py: More PEP8. Remove unused cap in with.
--HG--
branch : remove_unused_import
2014-04-02 09:48:08 -07:00
Floris Bruynooghe
adb12d0d4f Escape newlines in result from assertrepr hook
The result from the pytest_assertrepr_compare hook should not include
any newlines since that will confuse the mini-formatting language used
by assertion.util.format_explanation.  So simply escape the included
newlines, this way hook writers do not have to worry about this at
all.

Fixes issue 453.
2014-04-02 17:35:22 +01:00
Floris Bruynooghe
844c141d10 Style fixes for pep8
Includes a quotation change for consistent style.
2014-04-02 17:16:37 +01:00
Marc Abramowitz
02d94e69f0 testing/test_capture.py: Remove unused import tempfile
--HG--
branch : remove_unused_import
2014-04-02 09:14:16 -07:00
Marc Abramowitz
1bc56f9838 README.rst: Remove drone.io build badge; keep link
hpk had concerns about the build badge confusing folks when shown on PyPI.

--HG--
branch : add_drone_io_to_README_rst
2014-04-02 06:41:33 -07:00
Jurko Gospodnetić
98ea8fae32 break reference cycles caused by storing local reference to exception info
Such reference cycles unnecessarily cause Python interpreter not to garbage
collect the objects referenced in those cycles as soon they could be collected,
and in turn cause the tests to use more memory than is strictly necessary.

--HG--
branch : break_ExceptionInfo_reference_cycles
2014-04-02 15:34:36 +02:00
holger krekel
36288c5134 fix issue493: don't run tests in doc directory with `python setup.py test`
(use tox -e doctesting for that)
2014-04-02 12:48:35 +02:00
holger krekel
83a3cc9c94 fix issue492: avoid leak in test_writeorg. Thanks Marc Abramowitz. 2014-04-02 12:32:30 +02:00
holger krekel
0c04b44919 fix issue492: avoid leak in test_writeorg 2014-04-02 12:32:21 +02:00
Marc Abramowitz
a5e8860feb README.rst: Add drone.io link and build badge image
--HG--
branch : add_drone_io_to_README_rst
2014-04-02 03:11:35 -07:00
holger krekel
8d95f89a6a fix issue496: add pytest-sugar github repo override and regen index pages, upload it. 2014-04-02 12:03:08 +02:00
holger krekel
3bca62e9e4 fix issue436: improved finding of initial conftest files from command
line arguments by using the result of parse_known_args rather than
the previous flaky heuristics.  Thanks Marc Abramowitz for tests
and initial fixing approaches in this area.
2014-04-02 11:29:23 +02:00
holger krekel
72b4534a0c add changelog entry for some PRs: improvements to pytest's own
test-suite leakage detection, courtesy of PRs from Marc Abramowitz
2014-04-02 09:51:24 +02:00
holger krekel
21b4280126 Merged in msabramo/pytest/test_writeorg_close_tempfile (pull request #136)
test_writeorg: Close a tempfile
2014-04-02 09:30:55 +02:00
holger krekel
30a9debaf1 Merged in msabramo/pytest/refactor_LsofFdLeakChecker (pull request #138)
testing/conftest.py: Refactor lsof fd leak checking
2014-04-02 09:24:16 +02:00
holger krekel
4c5718c78d Merged in msabramo/pytest/doc_plugins_pytest_sugar (pull request #141)
doc/en/plugins_index/index.txt: Update pytest-sugar
2014-04-02 09:20:42 +02:00
Marc Abramowitz
c93b949878 Update entry for pytest-sugar; GitHub icon instead of BitBucket, correct description
--HG--
branch : doc_plugins_pytest_sugar
2014-04-01 18:59:42 -07:00
Marc Abramowitz
cf34adb75f doc/en/plugins_index/index.txt: Update pytest-sugar
--HG--
branch : doc_plugins_pytest_sugar
2014-04-01 18:52:36 -07:00
Marc Abramowitz
f824a73143 Remove cast of fd to int and sorting
Casting of fd can break for non-numeric fd (e.g.: "rtd" on Linux) and isn't
necessary since we don't need to sort.

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 15:36:54 -07:00
Marc Abramowitz
e45a33f029 testing/conftest.py: Reintialize config._openfiles for each test
And no longer need getopenfiles or config._numfiles

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 14:13:11 -07:00
Marc Abramowitz
064e79761c Improve LsofFdLeakChecker; more reliable and useful leak checking
* Make it invoke lsof with options for machine-readable output
* Parse out file descriptor and filename from lsof output
* Draw attention to file descriptors now open that weren't open before

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 13:41:35 -07:00
Marc Abramowitz
f7713c47e8 testing/conftest.py: Refactor lsof fd leak checking
Isolate the logic into one class to make easier to understand, more maintainable.
This may aid in later plugging in an alternative implementation, such as one
that uses psutil
(https://bitbucket.org/hpk42/pytest/pull-request/137/use-psutil-to-detect-open-files-in-tests/diff)

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 10:15:27 -07:00
holger krekel
8e4e2ba244 merge main 2014-04-01 15:06:44 +02:00
holger krekel
3b8935c533 remove dupped_stdout logic and related changes, also simplify pytest_runtest_* calls to not use a contextlib with-decorator anymore. 2014-04-01 15:03:17 +02:00
holger krekel
ce8678e6d5 remove non-documented per-conftest capturing option and simplify/refactor all code accordingly. Also make capturing more robust against tests closing FD1/2 and against pdb.set_trace() calls. 2014-04-01 14:32:12 +02:00
holger krekel
2e1f6c85f6 introduce resume/suspend functionality for FDCapture and SysCapture,
fixing problems with early bailouts (from argparse's parse() function e.g.)
that wrote to stdout.
2014-04-01 14:19:58 +02:00
holger krekel
ca5e6830c6 avoid some redundancy by using SysCapture from FDCapture for manipulating sys.std{out,in,err} 2014-04-01 14:19:55 +02:00
holger krekel
69cbac8fb5 rename StdCaptureBase to MultiCapture 2014-04-01 14:19:52 +02:00
Marc Abramowitz
7301981f32 test_writeorg: Close a tempfile
--HG--
branch : test_writeorg_close_tempfile
2014-03-31 08:25:35 -07:00
Marc Abramowitz
555ba4159d Simplify tests; don't use u literal not supported in py32
--HG--
branch : makepyfile_utf8
2014-03-28 12:11:33 -07:00
Marc Abramowitz
f47ae74981 Make makepyfile accept UTF-8 so a few cookie tests in test_assertrewrite.py
don't need to be dedented.

--HG--
branch : makepyfile_utf8
2014-03-28 09:44:18 -07:00
holger krekel
e061ace099 fix toxenv spec for py33-pexpect, thanks Daniel Grana. 2014-03-28 14:51:00 +01:00
holger krekel
85d52481b1 fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR. 2014-03-28 14:47:34 +01:00
holger krekel
47379d4a79 Merged in dangra/pytest (pull request #132)
no need for im_func and it does not exists in python3
2014-03-28 14:46:34 +01:00
Daniel Grana
0cb9d26d83 add py33-trial tox environment 2014-03-28 10:44:51 -03:00
holger krekel
95cc114b34 add changelog entry:
fix issue412: messing with stdout/stderr FD-level streams is now
captured without crashes.
2014-03-28 11:29:29 +01:00
holger krekel
9d716a39d6 fix issue412 and other encoding issues. Streamline dupfile() into
a new more thoughtful safe_text_dupfile helper.
2014-03-28 11:27:02 +01:00
holger krekel
923dcfd620 cleanup and refine issue412 test (still failing on py33) 2014-03-28 09:46:38 +01:00
holger krekel
b5467645d3 merge 2014-03-28 09:27:44 +01:00
holger krekel
a65380941d Merged in msabramo/pytest/sys_meta_path_remove_hook_only_if_present (pull request #133)
Only try to remove hook from sys.meta_path if it's present
2014-03-28 09:10:58 +01:00
Marc Abramowitz
17d7c60735 test_sys_meta_path_munged: Simplify with makepyfile
--HG--
branch : sys_meta_path_remove_hook_only_if_present
2014-03-28 01:03:52 -07:00
Marc Abramowitz
81f822d528 Only try to remove hook from sys.meta_path if it's present
Prevent error on exit if some code messes with sys.meta_path and removes the
assertionrewrite hook (CaptureMock seems to do this):

      File "/Users/marca/dev/hg-repos/pytest/_pytest/assertion/__init__.py", line 64, in pytest_unconfigure
        sys.meta_path.remove(hook)
    ValueError: list.remove(x): x not in list

--HG--
branch : sys_meta_path_remove_hook_only_if_present
2014-03-28 00:33:12 -07:00
holger krekel
0b340aa1f6 simplify some capturing tests 2014-03-28 07:55:07 +01:00
holger krekel
859915dc5e simplify capturing funcarg handling 2014-03-28 07:13:08 +01:00
holger krekel
a8f4f49a82 simplify reset/stop_capturing and fix capturing wrt to capturing simple os.write() calls 2014-03-28 07:11:25 +01:00
holger krekel
e18c3ed494 unify and normalize Sys/FD Capturing classes
* * *
more unification
2014-03-28 07:03:37 +01:00
holger krekel
2263fcf6b7 remove unused "suspend/resume" on capturing, some formatting cleanup 2014-03-28 07:03:34 +01:00
Daniel Grana
b96d552dbd no need for im_func and it does not exists in python3 2014-03-27 23:57:18 -03:00
Ronny Pfannschmidt
2b2c1e5b7b condition for python3 of the xfailing test for 412 2014-03-27 14:01:38 +01:00
holger krekel
7b63fa5966 merge in current default 2014-03-27 13:57:54 +01:00
Ronny Pfannschmidt
b18040337a xfailing test for issue 412 2014-03-27 13:53:59 +01:00
holger krekel
42e0d7970c Merged in nloadholtes/pytest/nloadholtes/slight-change-to-the-wording-for-readabi-1395890493571 (pull request #131)
Slight change to the wording for readability
2014-03-27 06:40:35 +01:00
Nick Loadholtes
ed0a4fe23b Slight change to the wording for readability
--HG--
branch : nloadholtes/slight-change-to-the-wording-for-readabi-1395890493571
2014-03-27 03:21:58 +00:00
holger krekel
bb0632c7ad extend test 2014-03-26 19:37:49 +01:00
holger krekel
84ab194516 add changelog: merge PR123: improved integration with mock.patch decorator on tests. 2014-03-26 19:06:56 +01:00
holger krekel
530cae9204 Merged in cgilling/pytest (pull request #123)
Fix to work properly when @patch is used with new not equal to DEFAULT
2014-03-26 19:05:46 +01:00
holger krekel
9dc43e84dc Merged in msabramo/pytest/help_show_args_with_equals_instead_of_space (pull request #130)
_pytest/config.py: In --help, show args with `=` instead of space.
2014-03-26 19:04:35 +01:00
Marc Abramowitz
8af265da04 _pytest/config.py: In --help, show args with = instead of space.
The `=` is better because it encourages folks to use the form that doesn't
suffer from issue #436 (https://bitbucket.org/hpk42/pytest/issue/436), which
can cause the arg to be treated as an "anchor" and used as the (unexpected)
path for searching for conftest.py files.

--HG--
branch : help_show_args_with_equals_instead_of_space
2014-03-26 10:47:30 -07:00
Chris Gilling
e3b9382122 use sys.modules.get correctly and reference DEFAULT with respect to it 2014-03-26 09:36:02 -07:00
Chris Gilling
c3f4eb6d57 change try/except to sys.module.get and a conditional 2014-03-26 09:27:33 -07:00
holger krekel
892aa457be fix issue472: clarify that `pytest.config.getvalue()` cannot work
if it's triggered ahead of command line parsing.
2014-03-26 07:15:54 +01:00
holger krekel
8f7b53e55b fix issue490: include pytest_load_initial_conftests in documentation
and improve docstring.
2014-03-25 14:43:58 +01:00
holger krekel
d27c377817 tentatively fix py33 and py25 compat 2014-03-14 15:58:16 +01:00
holger krekel
50abe43216 fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
during collection/loading of test modules.  Thanks to Marc Schlaich
for the complete PR.
2014-03-14 15:44:39 +01:00
holger krekel
ddc67ca13a Merged in schlamar/pytest (pull request #129)
Fixed race condition with SkipTest when module not in sys.modules on collection.
2014-03-14 15:39:01 +01:00
holger krekel
a1d3da4027 Merged in nicoddemus/pytest/integrate-plugin-index-docs (pull request #120)
Integrating plugin_index docs and misc improvements
2014-03-14 15:34:03 +01:00
schlamar
85e7b11ef5 Removed unnecessary iteration in nose.pytest_runtest_makereport. 2014-03-14 15:29:42 +01:00
schlamar
77e1f93ca1 Fixed pyflakes errors. 2014-03-14 14:25:36 +01:00
schlamar
94b1ce65c6 Fixed race condition with SkipTest when module not in sys.modules on collection. 2014-03-14 14:04:54 +01:00
holger krekel
f5b992f68a Merged in jurko/pytest/doc_typo_correction (pull request #122)
fix documentation typo
2014-03-14 13:10:33 +01:00
holger krekel
24a458b4c8 Merged in graingert/pytest/graingert/pep8-good-practices-code-1394196858258 (pull request #125)
pep8 good practices code
2014-03-14 13:06:53 +01:00
holger krekel
ac1d277225 simplify pdb disabling of capturing, also accomodate the new semantics
that capturing is always on during a test session.
2014-03-14 12:49:37 +01:00
holger krekel
9777703e03 - turn on capturing before early conftest loading and make terminal writer
use the original stream.

- avoid resetting capture FDs/sys.stdout for each test by keeping capturing
  always turned on and looking at snapshotted capturing data during runtest
  and collection phases.
2014-03-14 12:49:36 +01:00
holger krekel
f43cda9681 implement a new hook type: hook wrappers using a "yield" to distinguish
between working at the front and at the end of a hook call chain.
The idea is to make it easier for a plugin to "wrap" a certain hook
call and use context managers, in particular allow a major cleanup of
capturing.
2014-03-14 12:49:35 +01:00
holger krekel
b47fdbe0a7 remove externally setting and dealing with "item.outerr" from capturing in favor of a direct interface for adding reporting sections to items.
* * *
refactor makereport implementation to avoid recursion with __multicall__
2014-03-14 12:49:34 +01:00
holger krekel
cde970be69 remove unneccessary indirections and options 2014-03-14 12:49:34 +01:00
holger krekel
cfd43a9b02 add changelog for warning system, bump internal version 2014-03-14 08:15:38 +01:00
holger krekel
ebd10aa6b4 shrink and merge the somewhat obscure and undocumented internal hinting
system with the new warnings one
2014-03-11 22:10:51 +01:00
holger krekel
24db492f53 warn if instances are callable and have a test name 2014-03-11 22:10:18 +01:00
holger krekel
1b387bea62 introduce warning system with this API:
- node.warn() for a node-specific warning
- config.warn() for a global non-node specific warning

Each warning is accompanied by a "warning number" so that we can later
introduce mechanisms for surpressing them.

Each warning will trigger a call to pytest_report_warn(number, node, message)
which is by default implemented by the TerminalReporter which introduces
a new option "-rw" to show details about warnings.
2014-03-11 22:10:17 +01:00
Thomas Grainger
9528b64f7f pep8 good practices code
--HG--
branch : graingert/pep8-good-practices-code-1394196858258
2014-03-07 12:51:51 +00:00
holger krekel
b96559149c Merged in jurko/pytest/pdb_doc_update (pull request #118)
update PDB related pytest docs
2014-03-06 08:36:42 +01:00
Chris Gilling
3388d82c1c Fix to work properly when @patch is used with new not equal to DEFAULT
also updated test_mock to include this situation
2014-03-03 10:36:59 -08:00
Jurko Gospodnetić
9985a7cdca fix documentation typo
--HG--
branch : doc_typo_correction
2014-03-02 22:52:38 +01:00
Bruno Oliveira
1d00c5e109 Using github and bitbucket icons on plugins_index page
--HG--
branch : integrate-plugin-index-docs
2014-02-18 22:40:36 -03:00
Bruno Oliveira
0559f11aa5 Improved text on plugins_index
- Removed "beta" status from it;
- Added links to pytest-plugs app;

--HG--
branch : integrate-plugin-index-docs
2014-02-18 21:33:13 -03:00
Bruno Oliveira
2893cddb68 plugins_index no longer has the package names hard-coded
small number of changes:
- removed hard-coded links to package release versions, using
  a placeholder "latest" instead which is understood by pytest-plugs
- testing against pytest-2.5.2

This changes were implemented so this page only needs
to be updated after pytest releases, not after each package version changes;.
2014-02-11 23:38:30 -02:00
Jurko Gospodnetić
6910641266 reword PDB usage documentation
Documented that since pytest 2.4.0 you can use the raw pdb.set_trace() call
directly without the pytest.set_trace() wrapper or explicitly disabling pytest's
output capture using 'py.test -s'.

Clearly stated how pytest (since version 2.0.0.) automatically disables its
output capture when entering an interactive PDB debugger. This avoids confusing
new users because their tests display different output when running with or
without entering an interactive debugger (even if user does nothing in that
interactive debugger session other than exit it and continue with the regular
test execution).

--HG--
branch : pdb_doc_update
2014-02-01 10:19:09 +01:00
Jurko Gospodnetić
4b81a07303 make all 'PDB' doc references be recognized as links
--HG--
branch : pdb_doc_update
2014-02-01 10:11:42 +01:00
Jurko Gospodnetić
7eb765578a correct inconsistent comment wording
Once the 'the' article was used before 'first' and once it was not, all within
the same code example.

--HG--
branch : pdb_doc_update
2014-02-01 10:07:54 +01:00
holger krekel
e2cf3e0932 Added tag 2.5.2 for changeset 421d3b4d150d 2014-01-29 14:09:33 +01:00
holger krekel
1830de2c13 make it clear that this xfail is an unimplemented feature, nothing more. 2014-01-29 13:56:24 +01:00
holger krekel
25ab906b8b add release announcement, bump version to 2.5.2,
add links to plugins index, regenerate doc examples.
2014-01-29 13:47:11 +01:00
holger krekel
8a3b4b9c37 require py>=1.2.20 2014-01-29 13:11:40 +01:00
holger krekel
2b8a54d5d9 refine skipif to use direct booleans, to help with flakes 2014-01-29 11:46:36 +01:00
holger krekel
4eabfed651 refactor lsof checking and fix an lsof leak in pypy 2014-01-29 11:18:15 +01:00
holger krekel
505a34bb85 fix flakes failures 2014-01-29 10:20:13 +01:00
holger krekel
2dade6ed00 add changelog entry about issue429, adapt README 2014-01-29 09:00:14 +01:00
Floris Bruynooghe
825ea9bfa1 Fix assertrepr for mojibake
If the compared text was in bytes and not actually valid text
(i.e. could not be encoded to text/unicode using the default encoding)
then the assertrepr would fail with an EncodingError.  This ensures
that the internal string is always valid unicode, converting any bytes
safely to valid unicode.  This is done using repr() which then needs
post-processing to fix the encompassing quotes and un-escape newlines.

This fixes issue 429.
2014-01-29 00:42:58 +00:00
Floris Bruynooghe
cc1186242c Avoid wasted string concatenation and improve english 2014-01-29 00:39:04 +00:00
holger krekel
86284689a3 simplify loop which turns direct funcarg parametrization to indirect 2014-01-27 12:53:44 +01:00
holger krekel
c70d020bf3 allow positional args to tox invocation 2014-01-27 12:42:06 +01:00
holger krekel
4622c28ffd setupstate.addfinalizer(): fix docstring and remove related unit test not covering functional reality 2014-01-26 12:44:21 +01:00
holger krekel
899998cf9c Merged in hpk42/pytest-capsimple/capsimple1 (pull request #115)
some simplifications in capturing code
2014-01-26 12:07:45 +01:00
holger krekel
6f385fb4ea remove "mixed" capturing mode which is not used by pytest
--HG--
branch : capsimple1
2014-01-25 19:56:27 +01:00
holger krekel
18e12cbd67 remove "StdCapture*.call" classmethod because pytest does not use it.
--HG--
branch : capsimple1
2014-01-25 19:43:57 +01:00
holger krekel
3cf4e133cc remove now parameter because pytest only used now==False everywhere
--HG--
branch : capsimple1
2014-01-25 19:42:45 +01:00
holger krekel
d53bfe0aa7 Merged in RonnyPfannschmidt/pytest/multi-usageerror (pull request #113)
Make one usage error for every argument that fails instead of bailing at the first only
2014-01-25 11:04:53 +01:00
Ronny Pfannschmidt
97da43d909 merge from default
--HG--
branch : multi-usageerror
2014-01-25 10:42:21 +01:00
holger krekel
ee080ce8a5 Merged in jurko/pytest/remove_github_references (pull request #112)
remove references to the no longer used github mirror
2014-01-25 10:30:31 +01:00
Jurko Gospodnetić
741a3e8602 remove references to the no longer used github mirror
--HG--
branch : remove_github_references
2014-01-25 09:11:55 +01:00
Ronny Pfannschmidt
177637bfb9 Redo the Capture integration propperly 2014-01-24 21:22:19 +01:00
Piotr Banaszkiewicz
ae64221c34 Contribution guide: added pull request button image 2014-01-24 20:01:04 +01:00
Piotr Banaszkiewicz
22017f11d0 Contribution guide: removed confusion regarding git 2014-01-24 19:37:44 +01:00
Piotr Banaszkiewicz
c1eaad7d57 Contribution guide: added "what is pull request" section 2014-01-24 19:21:21 +01:00
holger krekel
8e6d538a57 address issue416: clarify docs as to conftest.py loading semantics 2014-01-23 15:25:01 +01:00
holger krekel
0836d74ae7 add Jurko to authors/contributors file 2014-01-23 15:08:24 +01:00
holger krekel
a9e5bd52d3 remove github links 2014-01-23 14:50:58 +01:00
Anatoly Bubenkov
b4b5e358c3 merge with mainline 2014-01-23 13:21:00 +01:00
Anatoly Bubenkov
4190809d1a remove the github contribution section 2014-01-23 13:19:49 +01:00
holger krekel
4e2a820c6a add Daniel Greensfeld 3-part blog series about pytest 2014-01-23 13:07:28 +01:00
holger krekel
14a43fffee have travis use the devpi index to get the pylib dependency 2014-01-23 12:18:20 +01:00
holger krekel
245d39f52d Merged in jurko/pytest/document_ExceptionInfo_ref_cycle (pull request #109)
document explicitly clearing local references to pytest.raises() results (redo of pull request #98)
2014-01-23 11:42:51 +01:00
holger krekel
ac0b862f8f speak about "pytest" rather than "py.test". Thanks Jurko. 2014-01-23 11:42:20 +01:00
holger krekel
c41db8ebbb refine contributing text in several places 2014-01-23 11:38:05 +01:00
Jurko Gospodnetić
75c124ea17 reword note on explicitly clearing local references to pytest.raises() results
Made it clearer that clearing such references is not mandatory and is only an
optional step which may help the Python interpreter speed up its garbage
collection.

--HG--
branch : document_ExceptionInfo_ref_cycle
2014-01-23 11:36:04 +01:00
Anatoly Bubenkov
ab13c3f362 add explicit branch creation note 2014-01-23 10:51:45 +01:00
holger krekel
c9af19dae1 rename, refine and link to new contributing doc from several places. 2014-01-23 10:21:06 +01:00
Jurko Gospodnetić
ffffac27f9 document explicitly clearing local references to pytest.raises() results
pytest.raises() returns an ExceptionInfo object which, if a local reference is
made to it, forms a reference cycle:
  ExceptionInfo
  --> exception
  --> stack frame raising the exception
  --> current stack frame
  --> current local variables
  --> Exception Info

Such a reference cycle would then prevent any local variables in the current
stack frame, or any of its child stack frames involved in the same reference
cycle, from being garbage collected until the next reference cycle garbage
collection phase. This unnecessarily increases the program's memory footprint
and potentially slows it down.

This situation is based on a similar one described in the official 'try'
statement Python documentation for locally stored exception references.

--HG--
branch : document_ExceptionInfo_ref_cycle
2014-01-23 09:46:36 +01:00
Anatoly Bubenkov
618bd56acf add Piotr Banaszkiewicz 2014-01-23 00:54:25 +01:00
Anatoly Bubenkov
402232e60f merge pbanaszkiewicz/contributiondocs 2014-01-23 00:52:49 +01:00
holger krekel
400b51caf6 mark encoding test as xfail also on py2 2014-01-22 22:18:33 +01:00
holger krekel
9aaf0fd340 backing out Ronny's PR because it was merged too early (still has failing tests) 2014-01-22 22:15:40 +01:00
Ronny Pfannschmidt
8976b3ee0e stop exposing capsys/capfd.capture 2014-01-22 21:52:32 +01:00
Ronny Pfannschmidt
ac2f2b1deb add notes on the copied pylib version 2014-01-22 21:50:07 +01:00
Ronny Pfannschmidt
0be961a0f3 capture tests: move imports and declarations to the top 2014-01-22 21:46:35 +01:00
Ronny Pfannschmidt
b4a397d153 kill ancient capture devnullpath, os.devnull exists since py 2.4 2014-01-22 21:37:59 +01:00
Ronny Pfannschmidt
d1a9ab3df0 small cleanp 2014-01-22 21:04:00 +01:00
Ronny Pfannschmidt
0ede968ec0 kill the str magic of Encodedfile 2014-01-22 21:03:49 +01:00
Ronny Pfannschmidt
5f21abc3a3 move imports and declarations to the top 2014-01-22 20:48:17 +01:00
Ronny Pfannschmidt
e2bb81124c simplify StdCaptureFD snapshot reading 2014-01-22 19:48:10 +01:00
Ronny Pfannschmidt
ea18e9656b rewrite all _pytest.capture uses of py.io to _pytest.capture 2014-01-22 19:44:20 +01:00
Ronny Pfannschmidt
3cc58c2f78 rewrite all testing uses of py.io to _pytest.capture 2014-01-22 19:32:23 +01:00
Ronny Pfannschmidt
0ac94134f5 initial code import for capture transfer 2014-01-22 19:04:38 +01:00
Ronny Pfannschmidt
c142f2551d xfailing test for captire encoding issues with binary stdio 2014-01-22 18:07:54 +01:00
holger krekel
cccfaa81fb fix issue413: exceptions with unicode attributes are now printed
correctly also on python2 and with pytest-xdist runs. (the fix
requires py-1.4.20)
2014-01-22 17:48:56 +01:00
Piotr Banaszkiewicz
d960fb78fc Contribution guide: moved tox inst. instructions up
--HG--
branch : contributiondocs
2014-01-22 17:05:11 +01:00
holger krekel
d02d0bb7b7 Merged in pelme/pytest/py2_pkg_skip (pull request #107)
fixed issue428: Skip test for packages without __init__.py on Python 2
2014-01-22 14:46:22 +01:00
Andreas Pelme
fe4cdd8a90 fixed issue428: Skip test for packages without __init__.py on Python 2
--HG--
branch : py2_pkg_skip
2014-01-22 14:32:22 +01:00
Jurko Gospodnetić
54a143e6a8 add test: '--markers' listing info from plugins in current folder
When pytest is called with the '--markers' option, it should collect marker
information from the current folder, and they should get loaded and used
correctly before the '--markers' output is constructed.
2014-01-22 14:16:39 +01:00
holger krekel
3a4f69734a remove superflous line 2014-01-22 13:54:25 +01:00
Piotr Banaszkiewicz
fbdc6e8cc0 Addressed contribution guide issues: virtualenv, links, Github mirror, RST rendering
--HG--
branch : contributiondocs
2014-01-22 12:19:33 +01:00
Piotr Banaszkiewicz
c2c44f0ffc Moved contribution guide to the rootdir/CONTRIBUTING.txt
--HG--
branch : contributiondocs
2014-01-22 11:37:02 +01:00
Floris Bruynooghe
e12fe64b54 Include py version in the terminal output
This can help to reproduce bugs when looking at the output pasted into
bug reports.
2014-01-22 11:27:15 +01:00
Piotr Banaszkiewicz
5240252164 New enthusiastic contribution guide based on Audreyr's cookiecutter-pypackage
Audrey's code is BSD, so there should be no problem with licensing.

I've covered:
* contribution types (with hints)
* steps to start with pytest development
* testing pytest
* basics of hg

--HG--
branch : contributiondocs
2014-01-22 11:24:58 +01:00
holger krekel
1ffc006363 fixed circular imports by reverting a few py.test -> pytest substitions. 2014-01-22 11:17:25 +01:00
holger krekel
836232e544 fix issue425: mention at end of "py.test -h" that --markers
and --fixtures work according to specified test path (or current dir)
2014-01-22 10:24:22 +01:00
holger krekel
2539e5a352 Merged in derdon/pytest/no-p-option (pull request #102)
added docs about the `no:` syntax for the -p option
2014-01-20 13:22:31 +01:00
Jurko Gospodnetić
8e457338ee fix handling MarkDecorators called with a single positional plus keyword args
When a MarkDecorator instance is called it does the following:
  1. If called with a single class as its only positional argument and no
     additional keyword arguments, it attaches itself to the class so it gets
     applied automatically to all test cases found in that class.
  2. If called with a single function as its only positional argument and no
     additional keyword arguments, it attaches a MarkInfo object to the
     function, containing all the arguments already stored internally in the
     MarkDecorator.
  3. When called in any other case, it performs a 'fake construction' call, i.e.
     it returns a new MarkDecorator instance with the original MarkDecorator's
     content updated with the arguments passed to this call.

When Python applies a function decorator it always passes the target class/
function to the decorator as its positional argument with no additional
positional or keyword arguments. However, when MarkDecorator was deciding
whether it was being called to decorate a target function/class (cases 1. & 2.
as documented above) or to return an updated MarkDecorator (case 3. as
documented above), it only checked that it received a single callable positional
argument and did not take into consideration whether additional keyword
arguments were being passed in as well.

With this change, it is now possible to create a pytest mark storing a function/
class parameter passed as its only positional argument and accompanied by one or
more additional keyword arguments. Before, it was only possible to do so if the
function/class parameter argument was accompanied by at least one other
positional argument.

Added a related unit test.

Updated MarkDecorator doc-string.
2014-01-20 01:27:33 +01:00
Simon Liedtke
d92ee8c3c3 added docs about the no: syntax for the -p option
--HG--
branch : no-p-option
2014-01-19 22:05:14 +01:00
Jurko Gospodnetić
492c60c202 fix doc typo 2014-01-19 10:26:55 +01:00
holger krekel
86ef81454f fix name 2014-01-19 09:13:06 +01:00
holger krekel
675669c52e added changelog: fixed docs and code to use "pytest" instead of "py.test"
everywhere.  Thanks Jurko Gspodnetic for the complete PR.
2014-01-18 14:53:04 +01:00
holger krekel
92c5d395a2 Merged in jurko/pytest (pull request #100)
update README.rst docs - pytest is compatible with Python 2.5 instead of 2.4
2014-01-18 14:51:53 +01:00
Jurko Gospodnetić
fa4ea1d9e8 update README.rst docs - pytest is compatible with Python 2.5 instead of 2.4 2014-01-18 13:11:17 +01:00
Jurko Gospodnetić
657a395839 fix comment typos 2014-01-18 12:39:16 +01:00
Jurko Gospodnetić
9fb2079458 replace py.test module references with pytest
The only remaining 'py.test' references are:
 * those referring to the 'py.test' executable
 * those in code explicitly testing py.test/pytest module compatibility
 * those in old CHANGES documentation
 * those in documentation generated based on external data
 * those in seemingly unfinished & unmaintained Japanese documentation

Minor stylistic changes and typo corrections made to documentation next to
several applied py.test --> pytest content changes.
2014-01-18 12:31:33 +01:00
Jurko Gospodnetić
83620ced2e trim trailing spaces 2014-01-18 10:40:20 +01:00
Bruno Oliveira
1fb824cd28 plugins_index: status images now link to actual tox output 2014-01-15 20:48:11 -02:00
Bruno Oliveira
0d35994fb8 Updated plugins_index.txt after changes in plugin_index.py 2014-01-15 20:32:11 -02:00
Bruno Oliveira
3a37f33d99 Improvements in plugins_index.txt
- Removed author and email in favor of repository link.
  Repository link is obtained from the 'home_page' field
  obtained from pypi. For plugins that don't have
  that field set, function obtain_override_repositories
  is used to override it in favor of known repositories url.

- Shortened "Python 2.7" in favor of "py27" to save space;
  Same for "Python 3.3".
2014-01-15 20:26:05 -02:00
Bruno Oliveira
ddfb2d5f3a Removing test_plugins_index
This test seems unnecessary now, since after every change we have
to generate plugins_index.txt and manually check to ensure it is
correct.
2014-01-15 19:20:53 -02:00
holger krekel
d81c0e9a92 remove build status that shows on pypi -- doesn't make sense because it shows the current trunk, not the released version. And start a new doc/en/status.txt 2014-01-11 10:46:07 +01:00
holger krekel
048cb71bf6 Merged in lakka/pytest//minor-doc-fix-in-skippingtxt-also-submi-1387492852421 (pull request #94)
Minor doc fix in skipping.txt.  Also submitted at Github before I realised that this was the master repo.  Will close over there.
2014-01-10 10:44:12 +01:00
Daniel Hahler
903fd144ff doc: fix desc for parametrize
- the parameter is called `expected`, not `output`
 - s/that that/that/
2014-01-09 22:27:23 +01:00
Jurko Gospodnetić
d51e27a5cb correct documentation typo 2013-12-28 17:05:17 +01:00
holger krekel
064290a606 Merge pull request #11 from pmuller/patch-1
Fix minor typo in special.txt
2013-12-20 11:37:39 -08:00
Philippe Muller
e6ae68c0cc Fix minor typo in special.txt 2013-12-20 14:01:17 +01:00
lakka
43f970ab6b Minor doc fix in skipping.txt. Also submitted at Github before I realised that this was the master repo. Will close over there.
--HG--
branch : /minor-doc-fix-in-skippingtxt-also-submi-1387492852421
2013-12-19 22:41:07 +00:00
holger krekel
49b9f9091a Merge pull request #9 from lukaszb/mark-error-message
Updated error message to be more helpful.
2013-12-19 07:13:13 -08:00
Lukasz Balcerzak
99277be25f Updated error message to be more helpful
Also, added misssing test
2013-12-19 14:29:57 +01:00
holger krekel
699892bd03 fix issue409 -- better interoperate with cx_freeze by not
trying to import from collections.abc which causes problems for py27/cx_freeze.
2013-12-18 14:56:45 +01:00
Bruno Oliveira
70c1503afc updated plugins_index for pytest 2.5.1 release 2013-12-17 21:52:26 -02:00
Bruno Oliveira
ee5d2eb696 plugins_index.py and test run under py33
changed a message a bit since issue405 has actually been resolved
2013-12-17 21:42:51 -02:00
Bruno Oliveira
2058f11931 Formatted plugins_index files to use a 80 char width
- Formatted code to follow pep-8 more closely;
- Got rid of header comments to better follow py.test coding style;
2013-12-17 19:34:07 -02:00
Bruno Oliveira
53a9ee21d4 Fixed test_plugins_index to work on python 2.6
- Expected and obtained modules now use .rst to avoid being picked as doctests
- Fixed test_plugins_index.expected to use the real py.test version
2013-12-17 19:14:57 -02:00
holger krekel
04118a5761 just use "sans-serif" as the default font, thankfully recommended by hynek. 2013-12-17 14:59:29 +01:00
holger krekel
c101c30690 change to the non-serif version of "Deja Vu" 2013-12-17 13:48:59 +01:00
holger krekel
0e664d3471 don't use guidea as font as it appears to give troubles to windows/chrome
users, see also here: http://stackoverflow.com/questions/11487427/is-there-any-font-smoothing-in-google-chrome
2013-12-17 13:21:39 +01:00
holger krekel
fcb1749f10 a few minor fixes and removing google+ stuff. 2013-12-17 11:24:58 +01:00
holger krekel
180eb098f1 Added tag 2.5.1 for changeset 039d543d1ca0 2013-12-17 10:52:03 +01:00
holger krekel
cc9b3ec296 fix links and add github link 2013-12-17 08:59:50 +01:00
holger krekel
66bd71a5d7 use gudea/gudea as header/body fonts 2013-12-17 08:56:59 +01:00
holger krekel
3365907989 last change to release announce 2013-12-17 08:43:01 +01:00
holger krekel
6b2040f98d regen docs for 2.5.1, add links for coverage reports 2013-12-17 08:30:35 +01:00
holger krekel
90551c6ce2 adding a release announcement and some doc fixes 2013-12-17 07:58:49 +01:00
holger krekel
d3b8390df3 Merge branch 'doc' of git+ssh://github.com/Turbo87/pytest into Turbo87-doc
Conflicts:
	CHANGELOG
2013-12-17 06:49:12 +01:00
holger krekel
9554fe0bf8 pypy has >21K tests now 2013-12-16 18:25:00 +01:00
holger krekel
5a13f31bce fix issue407: fix addoption docstring to point to argparse instead of
optparse. Thanks Daniel D. Wright.
2013-12-16 18:07:05 +01:00
holger krekel
41bddb48a1 remove unused var (fixes flakes tests) 2013-12-16 12:38:15 +01:00
Floris Bruynooghe
b820cf2e39 Fix docstring
This was copied from another paramterize call and I forgot to change
the parameters referred too.
2013-12-16 10:51:50 +00:00
Floris Bruynooghe
fd8638652d Still print this, but use py2/py3 compat syntax
I realised being able to print is probably an essential part of this
test which I may have inadvertendly disabled, so correct that.
2013-12-16 10:51:04 +00:00
holger krekel
01ae5dbb2e amend CHANGELOG with credits and issue mentioning 2013-12-16 08:04:46 +01:00
holger krekel
b4797d6295 fix issue403 : allow same-name parametrized functions within a collector 2013-12-16 07:47:59 +01:00
holger krekel
c9195a0f45 fix py32 failures and remove random print from commit accident 2013-12-16 07:19:49 +01:00
holger krekel
86c56c829a fix issue405 -- xfail the plugin generation test as it is not supposed to run as part of the pytest core tests and only runs on specific environments. 2013-12-16 07:03:59 +01:00
holger krekel
ef023ebad3 merge 2013-12-16 07:01:58 +01:00
Floris Bruynooghe
0c737e3de0 Allow parameterised fixtures to give paramemter IDs
This is just like the markers etc already can do.
2013-12-15 22:15:15 +00:00
Floris Bruynooghe
1b7c70eab4 Do not use py2-only print, breaks py3 testruns 2013-12-15 22:12:38 +00:00
Tobias Bieniek
6a5456f873 doc: Replaced header font 2013-12-14 15:49:56 +01:00
Tobias Bieniek
28b1079548 doc: Moved G+ button 2013-12-14 15:45:01 +01:00
Tobias Bieniek
fe01d1b0df doc: Fixed small res sidebar font color 2013-12-14 15:43:40 +01:00
Tobias Bieniek
54174c308f doc: Use native scrollbars on webkit 2013-12-14 15:38:11 +01:00
holger krekel
901f764825 merge 2013-12-14 14:00:47 +01:00
holger krekel
c1759fc384 fix py25 mention 2013-12-13 15:50:06 +01:00
Ronny Pfannschmidt
e843b028e6 fix issue404 by more strict junitxml escape 2013-12-13 10:28:23 +01:00
Bruno Oliveira
305cbecb34 Updated plugins_index to use pytest 2.5.0
- Also made test for plugins_index less brittle;
2013-12-12 19:20:13 -02:00
Tobias Bieniek
a986b3fb4a doc: Removed unused template 2013-12-12 19:48:45 +01:00
Tobias Bieniek
fd42133d89 doc: Don't use italic font for internal references 2013-12-12 19:48:36 +01:00
Tobias Bieniek
d6d7f3821f doc: Use green color for links 2013-12-12 19:48:13 +01:00
Tobias Bieniek
e79b43eeb2 doc: Moved link colors into variables 2013-12-12 19:41:29 +01:00
Tobias Bieniek
afba6ce907 doc: Don't show not existing logo 2013-12-12 19:36:07 +01:00
Tobias Bieniek
d5948325d4 doc: Use different font combination 2013-12-12 19:32:38 +01:00
Tobias Bieniek
b9b44bb87c doc: Moved font family attributes into variables 2013-12-12 19:29:28 +01:00
Tobias Bieniek
00b00ff931 doc: Adjusted TOC sidebar section 2013-12-12 19:22:37 +01:00
Tobias Bieniek
6f54a6be1e CHANGELOG: Simplified section headings 2013-12-12 19:10:24 +01:00
Tobias Bieniek
d1faccb061 CHANGELOG: Removed trailing whitespace 2013-12-12 19:08:26 +01:00
Tobias Bieniek
0f6bb3b3ef doc: Adjusted sidebar link 2013-12-12 19:03:25 +01:00
Tobias Bieniek
542b87fed3 doc: Added "Useful Links" section to all sidebars 2013-12-12 18:58:16 +01:00
Tobias Bieniek
33f1df2369 doc: Removed overwritten searchbox template
The original one works quite well...
2013-12-12 18:56:13 +01:00
Tobias Bieniek
041a12fdf2 doc: Moved PDF documentation link into links.html 2013-12-12 18:55:09 +01:00
Tobias Bieniek
555999397b doc: Moved searchbox into searchbox.html file 2013-12-12 18:49:44 +01:00
Tobias Bieniek
25a45f6bf7 doc: Moved links section to its own file 2013-12-12 18:48:10 +01:00
Tobias Bieniek
82f017edeb doc: Removed unused themes 2013-12-12 18:48:10 +01:00
Tobias Bieniek
b4842b20f6 doc: Added proper sidebar to index page 2013-12-12 18:48:10 +01:00
Tobias Bieniek
e14e966da9 doc: Activate "Flask" theme 2013-12-12 18:48:09 +01:00
Tobias Bieniek
ebe0c34a02 doc: Imported Flask Sphinx Styles
from https://github.com/mitsuhiko/flask-sphinx-themes
2013-12-12 18:48:09 +01:00
Tobias Bieniek
7d711083ec .gitignore: Removed *.html rule
The Sphinx templates are HTML files and should be included.
2013-12-12 18:48:09 +01:00
holger krekel
0a4d5a423e some doc fixes 2013-12-12 13:06:25 +01:00
holger krekel
b9ccb9d31f Added tag 2.5.0 for changeset a064ad64d167 2013-12-12 13:06:21 +01:00
holger krekel
a056b41070 fix typo 2013-12-12 13:01:57 +01:00
holger krekel
6d26c44895 remove py25 from automated testing 2013-12-12 08:16:16 +01:00
holger krekel
1644cd2da5 don't declare py25 as supported anymore. 2013-12-12 07:30:34 +01:00
holger krekel
98135a3d30 remove unusued import 2013-12-12 06:55:05 +01:00
holger krekel
307a41339c fix expicit assert messages for Python2.6: it turns out python2.6
instantiates the AssertionError differently for tuples.  Test
and fix to neutralize it.
2013-12-12 06:41:48 +01:00
Bruno Oliveira
72ebd74715 Updated plugins_index.txt with latest plugins 2013-12-11 17:28:08 -02:00
holger krekel
bfa53811d3 regen docs and bump version to 2.5.0 2013-12-11 12:20:19 +01:00
holger krekel
0fa77d58c4 preparing 2.5.0 release announcement 2013-12-11 12:12:01 +01:00
holger krekel
fa80b8ad17 add changelog: 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.
2013-12-11 11:28:06 +01:00
holger krekel
9cdb6fc724 Merged in paylogic/pytest/override-fixture-via-parametrization (pull request #92)
Paratrization overrides existing fixtures.
2013-12-10 14:59:10 +01:00
holger krekel
cd8e69e33c close issue240 - rework "good practises" document and discuss
discuss the two common test directory layouts in more detail, including
an explicit note on how it interacts with PEP420-namespace packages.
2013-12-10 14:54:13 +01:00
Anatoly Bubenkov
7b87f7b6b5 Paratrization overrides existing fixtures.
--HG--
branch : override-fixture-via-parametrization
2013-12-10 14:27:29 +01:00
holger krekel
dd0da4643a clarify that pytest.mark.parametrize() takes a list of argvalues and not just
arbitrary iterators.  Addresses issue122.
2013-12-10 10:16:27 +01:00
holger krekel
7766526992 address issue122 -- explode "params" into a list in fixture function decorators 2013-12-09 10:48:15 +01:00
holger krekel
5c3d692008 some minor internal cleanup 2013-12-09 10:40:39 +01:00
holger krekel
bdf9147ad4 fix changelog 2013-12-09 10:38:40 +01:00
holger krekel
ad2ac256de speed up reorder for large higher-than-function-scoped parametrizations 2013-12-09 10:05:44 +01:00
holger krekel
a4466342ae make bench.py accept an optional script name and add a slow "manyparam" test 2013-12-09 08:14:58 +01:00
holger krekel
0d7af592c0 speed up a test 2013-12-09 08:14:39 +01:00
holger krekel
66ffc5e0f8 backout allowing @pytest.fixture in front of pytest_funcarg__NAME functions.
It was introduced because of pylint warnings and it's probably better to
go for a pylint-pytest plugin that avoids also other warnings/issues.
2013-12-09 07:07:47 +01:00
holger krekel
320137a4aa Merged in msabramo/pytest/color_option (pull request #91)
Remove u'' literal in test_color_{yes,no} for Python 3.2 compat
2013-12-08 20:56:21 +01:00
Marc Abramowitz
0278dc9b6f Remove u'' literal in test_color_{yes,no} for Python 3.2 compat
--HG--
branch : color_option
2013-12-08 11:39:55 -08:00
holger krekel
7d9297e929 add changelog entry: PR90: add --color=yes|no|auto option to force terminal coloring
mode ("auto" is default).  Thanks Marc Abramowitz.
2013-12-08 20:25:36 +01:00
holger krekel
9e03ea8215 Merged in msabramo/pytest/color_option (pull request #90)
Add option: --color=(yes/no/auto)
2013-12-08 20:19:37 +01:00
Marc Abramowitz
60f5b15f20 Remove superfluous monkeypatch arg to test_color_yes
--HG--
branch : color_option
2013-12-07 12:04:23 -08:00
holger krekel
e67047d629 remove unused cache argument for re-ordering items. 2013-12-07 21:00:33 +01:00
holger krekel
10edfa65dc fix issue396 -- properly sort tests using class-scoped parametrization
also refix issue323 in a better way to avoid recursion for the fixture-grouping
algorithm alltogether.
2013-12-07 20:55:17 +01:00
holger krekel
daec4c70b8 refactor sorting wrt class-scopes. This fixes issue396 and also simplifies
the internal sorting algorithm a bit.
2013-12-07 19:31:27 +01:00
holger krekel
dbfbc2b222 add a skip benchmark file (from issue400). 2013-12-07 19:11:37 +01:00
holger krekel
426907eafb radically simplify eq/neq with nodes by just using Pythons builtin "is" relationship.
The need for comparing two separately instantiated nodes seems to be historic
(related to an already-gone mode of pytest-xdist which would re-collect nodes)
and not actually needed anymore.
2013-12-07 16:39:53 +01:00
holger krekel
4f0879ff9b refactor internal finalization mechanics such that all fixture arguments
in a test invocation will have a corresponding FixtureDef instance.
also fixes issue246 (again).

simplify parametrized fixture teardown by making it work lazy:
during the setup of a parametrized fixture instance any previously
setup instance which was setup with a different param is torn down
before setting up the new one.
2013-12-07 16:37:46 +01:00
Marc Abramowitz
bec6ee5c29 Assert 'test session starts' in output for test_color_{yes,no}
--HG--
branch : color_option
2013-12-06 11:58:04 -08:00
Marc Abramowitz
23fa4cec61 Add option: --color=(yes/no/auto)
--HG--
branch : color_option
2013-12-06 11:49:48 -08:00
holger krekel
4b9dbd3920 remove unused line 2013-12-05 14:40:50 +01:00
holger krekel
98c6ced46e refactor and document parametrized sorting code. 2013-12-05 06:09:29 +01:00
holger krekel
cb485e5af4 reopen #246 -- it turns out parametrized finalization ordering is not fully fixed -- i modified the test and marked it xfail for now. 2013-12-04 16:09:37 +01:00
holger krekel
817b175870 allow to use pytest.fixture decorator on old-style pytest_funcarg__NAME definitions. 2013-12-04 07:16:34 +01:00
holger krekel
bd320951e6 Merged in paylogic/pytest/parametrize-hashable (pull request #89)
implement index-based mechanizm for collection of parametrized tests
2013-12-03 21:07:15 +01:00
Anatoly Bubenkov
0cfd873abe implement index-based mechanizm for collection of parametrized tests
--HG--
branch : parametrize-hashable
2013-12-03 21:05:19 +01:00
holger krekel
d30ad3f5ce fix reporting for @mock'd test functions 2013-12-03 11:23:22 +01:00
holger krekel
5dbf4fc0c2 fix importorskip test 2013-12-03 09:40:40 +01:00
Floris Bruynooghe
e3a945a0b5 Add test for unicode assertion descriptions
Also clean up a few debugging leftovers.
2013-11-29 00:29:14 +00:00
Floris Bruynooghe
a5c075c4e2 Respect unicode in AssertionError argument
This is related to issue319
2013-11-24 17:45:48 +00:00
holger krekel
c0dd7c5975 fix issue275 - allow usefixtures and autouse fixtures
for running doctest text files.
2013-11-22 15:35:20 +01:00
holger krekel
4031588811 add a note to the documentation that pytest does not mimick nose try to perform "import isolation". Addresses issue268. 2013-11-22 15:12:12 +01:00
holger krekel
1dc2a45cb2 fix issue377 by clarifying in the nose-compat docs that pytest
does not duplicate the unittest-API into the "plain" namespace.
2013-11-22 14:07:56 +01:00
holger krekel
40b172ca5a python2.4 is not really tested or supported anymore 2013-11-22 13:57:15 +01:00
holger krekel
94031f9cef apply doc changes from just backed out changeset 2013-11-22 13:53:43 +01:00
holger krekel
a6783cd6f3 Backed out changeset 73b1eed8ce09 2013-11-22 13:52:53 +01:00
holger krekel
438d85b5ad clarify that python_functions does not apply to unittest.TestCase
classes and their methods.  Addresses issue284.
2013-11-22 13:44:56 +01:00
Floris Bruynooghe
90b6ccd321 Ensure the long descriptions and formatting preserve unicode correctly
This is the first stage towards fixing issue319, at least
py.io.saferepr and py.code.ExceptionInfo need to be addressed as well.
2013-11-22 12:28:59 +00:00
Floris Bruynooghe
db778fd456 Correct comment 2013-11-22 12:27:34 +00:00
holger krekel
08f3a0791d 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.

Also add a note to the docs about what is allowed.
2013-11-21 15:25:16 +01:00
holger krekel
663f824fc4 simplify basedir isolation 2013-11-21 14:54:46 +01:00
holger krekel
2700a94d49 remove an old duplicate marker and use recent pytest mechanism for parametrization 2013-11-21 14:40:14 +01:00
holger krekel
e31f40c2d0 fix ordering of finalizers of parametrized interdependent fixtures.
This fixes issue246 as reported.  Thanks Ralph Schmitt for the
precise failure example.
2013-11-21 14:16:44 +01:00
holger krekel
fc073cb81c fixed version comparison in pytest.importskip(modname, minverstring) 2013-11-21 13:53:04 +01:00
holger krekel
2e90aaf7af remove _fixturestack attribute now that we have a proper request->subrequest->subrequest chain. 2013-11-21 13:15:32 +01:00
holger krekel
238b890d9b avoid maintaining a fixturestack 2013-11-21 12:42:22 +01:00
holger krekel
49119e31bf fix py25 compat 2013-11-21 12:31:22 +01:00
holger krekel
bb5f1e8173 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.
2013-11-21 12:21:52 +01:00
holger krekel
05fbd490da addresses issue246: add a test for module/function scope that shows that
finalizer ordering is wrong.
2013-11-21 09:42:24 +01:00
holger krekel
5322f057a0 move two fixture test modules into bigger testing/python/fixture.py 2013-11-21 09:26:45 +01:00
holger krekel
086cc03f05 some amendments/fixes to changelog 2013-11-21 07:46:53 +01:00
Floris Bruynooghe
d67514b657 Fixup changelog
This seems to have gone wrong in the merge.
2013-11-21 01:37:48 +00:00
Floris Bruynooghe
a467fbea0d Merge 2013-11-21 01:16:49 +00:00
Floris Bruynooghe
6686c67a41 Re-raise the first exception instead of the last
This will make more sense if multiple fixtures depend on each other.
It would be better if all exceptions could be shown however.

Also depend on python 2.5+ exception hierarchy and use sys module
directly.
2013-11-21 01:15:24 +00:00
holger krekel
73f36fc8b7 fix issue221 - handle importing of namespace-package with no
__init__.py properly. (This is a commit after the fix -- the
original issue steps for failure cannot be reproduced anymore).
2013-11-20 21:04:19 +01:00
holger krekel
bd8a2cc18c removing pexpect from general dependencies because
it doesn't install on windows anymore.  Instead
to specific configurations for pexpect on py27 and py33
which only call the tests that need it.
2013-11-20 20:00:59 +01:00
holger krekel
6d1b7e94d1 add py33-xdist to tox testing 2013-11-20 16:03:55 +01:00
holger krekel
9eff939b02 remove testing of xdist+genscript -- doesn't really make sense
because for installing pytest-xdist you need pytest installed
which defeats the purpose of genscript.
2013-11-20 15:46:23 +01:00
holger krekel
0a8b27ff49 fix ordering when mock.patch or other standard decorator-wrappings
are used with test methods.  This fixues issue346.  Thanks to
Ronny Pfannschmidt and Donald Stufft for helping to isolate it.
2013-11-19 23:22:27 +01:00
Floris Bruynooghe
72752165df Ensure all finalizations are run when one fails
Fixes issue287.
2013-11-19 17:26:18 +00:00
holger krekel
9b21d3f206 internally make varnames() deal with classes's __init__,
although it's not needed by pytest itself atm.  Also
fix caching.  Fixes issue376.
2013-11-19 15:33:52 +01:00
holger krekel
dde0a81677 don't hide an ImportError when importing a plugin produces one.
fixes issue375.
2013-11-19 14:45:51 +01:00
holger krekel
31576fac61 fix issue380 by making --resultlog only rely on longrepr instead
of the "reprcrash" attribute which only exists sometimes.
2013-11-19 14:19:29 +01:00
Ronny Pfannschmidt
82846777a7 add missing importorskip 2013-11-19 12:21:47 +01:00
holger krekel
7f49e0fddc xfail a test on pypy that checks wrong encoding/ascii (pypy does
not error out). fixes issue385.

also re-enable pypy tests in tox.
2013-11-19 11:18:51 +01:00
Ronny Pfannschmidt
eda8b02a8d fix issue384 by removing the trial support code 2013-11-19 10:58:24 +01:00
holger krekel
1fd1617427 fix pexpect-3.0 compatibility for pytest's own tests.
(fixes issue386)
2013-11-19 10:10:27 +01:00
holger krekel
97252a8b66 fix issues link 2013-11-19 09:20:50 +01:00
holger krekel
4a1cc792c9 a script to read bitbucket pytest issues 2013-11-18 21:31:32 +01:00
holger krekel
581b3a110c Merged in hsoft/pytest (pull request #81)
Fix TypeError crash on failed imports under py3.3.
2013-11-15 21:02:30 +01:00
Virgil Dupras
e118682db1 Added test for previous crash on failed import fix
Also, rewrote the fix a bit.
ref #383.
2013-11-15 14:03:57 -05:00
holger krekel
4eeb1c4f31 Merged in paylogic/pytest/fix-fixturedef-merge (pull request #86)
correctly check for fixturedef when  merging
2013-11-14 05:58:50 +01:00
Anatoly Bubenkov
e2c4730e17 correctly check for fixturedef when merging
--HG--
branch : fix-fixturedef-merge
2013-11-13 18:25:55 +01:00
holger krekel
c3e844e561 Merged in nicoddemus/pytest/plugins-index-status-images (pull request #85)
Adding status images in plugins_index
2013-11-13 07:45:40 +01:00
holger krekel
fde947e1a8 Merged in paylogic/pytest/ignore-autocomplete-on-darwin (pull request #84)
ignore argcomplete on darwin
2013-11-13 07:44:24 +01:00
holger krekel
ce0af892aa Merged in paylogic/pytest/multi-level-fixture-deps-override (pull request #83)
When overridden, fixture's dependencies are called from all levels of folder structure
2013-11-13 07:43:59 +01:00
holger krekel
3f389238f8 Merged in paylogic/pytest/python32-test-fix (pull request #82)
support python32 fix
2013-11-13 07:43:35 +01:00
Bruno Oliveira
1faf95273c Adding status images in plugins_index
--HG--
branch : plugins-index-status-images
2013-11-12 23:54:13 -02:00
Anatoly Bubenkov
ba5d4ae42f ignore argcomplete on darwin
--HG--
branch : ignore-autocomplete-on-darwin
2013-11-12 13:52:16 +01:00
Anatoly Bubenkov
d18124f5ed support python32
--HG--
branch : python32-test-fix
2013-11-12 13:48:17 +01:00
Anatoly Bubenkov
846cf781a1 use deepest fixturedef for fixture closure
--HG--
branch : multi-level-fixture-deps-override
2013-11-12 13:45:36 +01:00
Anatoly Bubenkov
85dd51ccc8 initial
--HG--
branch : multi-level-fixture-deps-override
2013-11-12 13:35:32 +01:00
Virgil Dupras
ded88700a3 Fix TypeError crash on failed imports under py3.3.
Starting with Python 3.3, NamespacePath passed to importlib hooks
seem to have lost the ability to be accessed by index.

We wrap the index access in a try..except and wrap the path in a
list if it happens.

Fixes #383.
2013-11-08 16:59:13 -05:00
holger krekel
a9d1f40c29 merge, add changelog entry 2013-11-02 07:04:26 +01:00
holger krekel
e2d19aab39 Merged in jameslan/pytest/multi-marks (pull request #79)
Support multiple marks for individual parametrized argument set
2013-11-02 07:02:28 +01:00
James Lan
7210e443ee Support multiple marks for individual parametrized argument set
--HG--
branch : multi-marks
2013-11-01 21:10:13 -07:00
holger krekel
f674c57d1a add german pytest talk (pyconde2013) 2013-10-25 16:50:05 +02:00
holger krekel
9dec27371d change metadata 2013-10-24 15:08:50 +02:00
holger krekel
75328b66e6 fix tests on py32/py33 2013-10-22 11:26:29 +02:00
holger krekel
cf9d345382 fix unicode handling with junitxml, fixes issue368. 2013-10-21 16:54:25 +02:00
holger krekel
0d8392bc45 fix unicode handling with new monkeypatch.setattr(import_path, value)
API.  Thanks Rob Dennis.  Fixes issue371.
2013-10-21 14:01:02 +02:00
holger krekel
47d2d20d81 fix typo, thank avanderneuth 2013-10-21 13:36:22 +02:00
holger krekel
b0a5740898 fix changelog 2013-10-21 13:34:24 +02:00
holger krekel
bc8c4b3ebd pytestconfig is now session-config as it is the same object during the
whole test run.  Fixes issue370
2013-10-21 13:33:36 +02:00
holger krekel
2eebe6c677 Merged in nicoddemus/pytest/plugins-index-adjustments (pull request #77)
Adjustments to the plugins index page
2013-10-20 07:53:36 +02:00
Floris Bruynooghe
8c326c5e66 Correct hyperlink and target 2013-10-15 12:45:55 +01:00
Bruno Oliveira
8e9034f074 adding column for download counts
--HG--
branch : plugins-index-adjustments
2013-10-14 19:14:05 -03:00
Bruno Oliveira
612fb96d02 using a single column for name and version
--HG--
branch : plugins-index-adjustments
2013-10-14 18:33:41 -03:00
Bruno Oliveira
49d067d72e moved test_plugins_index.py
--HG--
branch : plugins-index-adjustments
2013-10-14 18:22:41 -03:00
Bruno Oliveira
8e1301b6d7 moved plugins_index to its own directory
--HG--
branch : plugins-index-adjustments
2013-10-14 18:14:35 -03:00
holger krekel
8ac5af2896 fix flakes issues and make --flakes run part of tox runs 2013-10-12 15:39:22 +02:00
holger krekel
8550ea0728 Merged in nicoddemus/pytest/plugins-index (pull request #76)
Script to generate docs with a list of pytest plugins from PyPI
2013-10-12 14:27:43 +02:00
Bruno Oliveira
6e619e0a70 fixed 'PyPI' spelling
--HG--
branch : plugins-index
2013-10-11 20:57:35 -03:00
Bruno Oliveira
5b2b71bfd4 included test for plugins_index and added command line options
--HG--
branch : plugins-index
2013-10-11 20:53:03 -03:00
Bruno Oliveira
d92322a574 added plugins_index documentation and generated plugins_index file
--HG--
branch : plugins-index
2013-10-11 19:47:40 -03:00
Bruno Oliveira
7e793b9419 adding first version of plugins_index script
--HG--
branch : plugins-index
2013-10-11 19:14:22 -03:00
holger krekel
d81b703f10 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.
2013-10-11 14:36:54 +02:00
holger krekel
1265cb9952 add changelog entry: 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.
2013-10-11 09:29:28 +02:00
holger krekel
124e58e42d merge 2013-10-11 09:30:08 +02:00
Jason R. Coombs
2697b63bcd Fix bytes/string mismatch in test on Python 3 2013-10-10 18:01:56 -04:00
Jason R. Coombs
ee5b836e27 Implement suggestions by HPK 2013-10-10 17:39:37 -04:00
Jason R. Coombs
a4c17dfb19 Register the AssertionRewritingHook loader with pkg_resources; fixes #366. 2013-10-10 11:56:12 -04:00
Jason R. Coombs
00c0d62c9b Adding test capturing #366 where an error occurs when package resources are loaded from the test package. 2013-10-10 11:40:31 -04:00
holger krekel
a5d4c20905 make "--runxfail" turn imperative pytest.xfail calls into no ops
(it already did neutralize pytest.mark.xfail markers)
2013-10-09 22:55:20 +02:00
holger krekel
0335c6d750 bump version to 2.3.3.dev1 2013-10-05 21:39:16 +02:00
Benjamin Peterson
8b6e42317b add test for detecting coding cookie with CRLF newlines 2013-10-05 15:20:32 -04:00
Benjamin Peterson
56e6ae567c fix detection of the coding cookie when it is on the second line of the file (fixes #330) 2013-10-05 15:16:08 -04:00
Benjamin Peterson
33b663e03d fix coding cookie detection logic 2013-10-05 15:03:04 -04:00
holger krekel
4bfbe7ec22 Added tag 2.4.2 for changeset 8d051f89184b 2013-10-04 14:33:12 +02:00
holger krekel
4b395d56cc bump version of docs 2013-10-04 13:59:44 +02:00
holger krekel
018860d626 finalize release announcement, changelog 2013-10-04 12:34:47 +02:00
holger krekel
19a76337a4 add pluginmanager.do_configure(config) as a link to
config.do_configure() for plugin-compatibility
add some more plugins to plugin-test.sh
2013-10-04 11:36:45 +02:00
holger krekel
0780f2573f bump version to 2.4.2, regen docs 2013-10-03 19:09:18 +02:00
holger krekel
cec7d47c1f remove fd-fixing attempt at startup of pytest. It's
not clear it's actually needed and it's not nice
to still do FD-dupping when "-s" is specified.
2013-10-03 18:53:40 +02:00
holger krekel
3d00cd35fc fix python2.5 issues 2013-10-03 18:25:03 +02:00
holger krekel
5aa5b9748d fix argcomplete-test to use sys.argv[0] if it looks like a py.test executable 2013-10-03 18:02:54 +02:00
holger krekel
cb65c56037 fix issue365 and depend on a newer py versions which uses colorama
for coloring instead of its own ctypes hacks.
2013-10-03 17:46:36 +02:00
holger krekel
ae090740c5 always dupfile if os.dup is available 2013-10-03 16:47:55 +02:00
holger krekel
2248a31a44 more fixes regarding marking, in particular plugins should use add_marker/get_marker now. 2013-10-03 15:43:56 +02:00
holger krekel
9fdfa155fb fix issue354: avoid tmpdir fixture to create too long filenames especially
when parametrization is used
2013-10-03 14:22:54 +02:00
holger krekel
e49eca8d59 simplify the implementation of NodeKeywords getting rid of __ descriptors appearing there. 2013-10-03 13:53:22 +02:00
holger krekel
263b0e7d99 add setup.cfg for building sphinx_docs 2013-10-03 12:35:13 +02:00
Andreas Zeidler
42b1033385 allow test items to not be associated with a test function
this is needed for plugins like `pytest-pep8` or `pytest-flakes`
2013-10-02 15:55:28 +02:00
holger krekel
05f6422392 remove unused imports (using "importchecker" project) 2013-10-02 14:32:40 +02:00
holger krekel
f83a65c8ae Added tag 2.4.1 for changeset 8828c924acae 2013-10-02 12:41:03 +02:00
holger krekel
071960250f avoid "IOError: Bad Filedescriptor" on pytest shutdown by not closing
the internal dupped stdout (fix is slightly hand-wavy but work).
2013-10-02 12:39:01 +02:00
holger krekel
16d98541f2 reference CHANGELOG 2013-10-02 12:09:19 +02:00
holger krekel
2b8f4214c3 2.4.1 release preps 2013-10-02 09:16:51 +02:00
holger krekel
d3c9927fee fix regression reported by dstufft: regression when a 1-tuple ("arg",) is used
for specifying parametrization (the values of the parametrization were passed
nested in a tuple).
2013-10-02 08:08:26 +02:00
holger krekel
acc5679bc8 adapt changelog 2013-10-02 07:56:30 +02:00
holger krekel
2ba77cb1f4 merge 2013-10-02 07:49:11 +02:00
holger krekel
8f65418d34 Merged in dirn/pytest/dirn/adjust-syntax-for-parametrize-documentat-1380671670976 (pull request #72)
Adjust syntax for parametrize documentation
2013-10-02 07:48:41 +02:00
Andy Dirnberger
8ae79e09c0 Adjust syntax for parametrize documentation
Without the double colon, reStructuredText won't display treat the block that
follows as pre-formatted text. Also, with this change comes the need to change a
tab to spaces to align it with the adjacent lines.

--HG--
branch : dirn/adjust-syntax-for-parametrize-documentat-1380671670976
2013-10-01 23:54:34 +00:00
holger krekel
c62bfaefd6 add to CHANGELOG 2013-10-01 22:39:23 +02:00
Anthon van der Neut
236fff00ad complete_dotted: fix for #361, filecompleter on dot files had differing behaviour from bash
Now if the prefix to expands ends in the directory seperator, then
'..../.*' is globbed as well.
2013-10-01 16:33:15 +02:00
holger krekel
9b9355b8da fix typos (thanks @faassen) 2013-10-01 14:30:53 +02:00
holger krekel
446bcf44fb strike wrong yield_fixture paragraph 2013-10-01 14:25:59 +02:00
Floris Bruynooghe
1db6fc87c7 Allow unicode strings in parser.add_argument()
This fixes issue360 by also converting unicode strings to the argparse
syntax instead of just native strings.
2013-10-01 13:20:20 +01:00
holger krekel
895d52471b bump version to dev again, new CHANGELOG section for 2.4.1.dev. 2013-10-01 12:51:52 +02:00
holger krekel
d226b2faf4 release announcement, bump version numbers, some test adapatations because of random win32 test failures. 2013-10-01 12:37:11 +02:00
holger krekel
74ea94625a Added tag 2.4.0 for changeset af860de70cc3 2013-10-01 10:43:40 +02:00
holger krekel
f9927e457b bump version to 2.4.0 2013-10-01 10:43:36 +02:00
holger krekel
a71fdd26b3 fix usage docs for "-k" (addresses issue357) 2013-09-30 21:39:32 +02:00
holger krekel
2c7d00579b bump version, some windows test fixes, prevent logging from raising exceptions at the end (finally), add py25 to tox.ini. 2013-09-30 16:09:26 +02:00
holger krekel
de35b077a2 disallow yield in non-yield-fixtures for now. This is an incompataibility but we want to prepare for possibly merging fixture and yield_fixture some day. 2013-09-30 13:56:54 +02:00
holger krekel
086d4e4ced strike keyword argument in favour of new pytest.yield_fixture decorator 2013-09-30 13:42:39 +02:00
holger krekel
431ce79d94 add missing entry to CHANGELOG 2013-09-30 13:23:32 +02:00
holger krekel
db6f347db6 fix issue358 -- introduce new pytest_load_initial_conftests hook and make capturing initialization use it, relying on a new (somewhat internal) parser.parse_known_args() method.
This also addresses issue359 -- plugins like pytest-django could implement a pytest_load_initial_conftests hook like the capture plugin.
2013-09-30 13:14:16 +02:00
holger krekel
4b709037ab some more separation of core pluginmanager from pytest specific functionality.
Idea is to have the PluginManager be re-useable from other projects at some point.
2013-09-30 13:14:14 +02:00
holger krekel
d946299b0a shift pytest_configure/unconfigure/addoption/namespace hook calling to config object.
The _pytest.config module itself is no longer a plugin but the actual
config instance is plugin-registered as ``pytestconfig``.
This allows to put most pytest specific logic to _pytest.config instead
of in the core pluginmanager.
2013-09-30 13:14:14 +02:00
holger krekel
694c6fd0e7 localize some argcomplete-related functionality 2013-09-30 10:19:06 +02:00
holger krekel
8b1e53f6d3 avoid creation of file in os.getcwd() cc avanderneut 2013-09-30 08:36:31 +02:00
holger krekel
a930f44e60 introduce pluginmanager.ensure_teardown() which allows 2013-09-28 22:23:00 +02:00
holger krekel
ac19212b2d remove very likely unused pytest_plugin_unregister hook (pytest itself and all plugins i know don't use it) 2013-09-28 22:22:57 +02:00
holger krekel
03c314e3be refine fromdictargs to avoid an uncessary re-setup of the pluginmanager 2013-09-28 22:22:55 +02:00
holger krekel
fad7bd4393 simplify Config constructor 2013-09-28 22:22:53 +02:00
holger krekel
b80e875525 move FILE_OR_DIR constant out 2013-09-28 09:52:41 +02:00
holger krekel
1fc466e8ac add terminalreporter.section|line methods to print extra information. 2013-09-27 15:48:03 +02:00
holger krekel
209a0cd5b2 is actually a new feature, the syntax: pytest.mark.parametrize("arg1,arg2", ...) 2013-09-27 14:15:53 +02:00
holger krekel
9ddfd62848 re-order CHANGELOG and group it into "features" and "bugs" and "known incompatibilities" 2013-09-27 12:58:26 +02:00
holger krekel
48838727ae bump version 2013-09-27 12:43:49 +02:00
holger krekel
39503932a4 merge monkeypatch.replace into monkeypatch.setattr, also support monkeypatch.delattr. 2013-09-27 12:33:06 +02:00
holger krekel
da7133d201 fix some tests wrt to expecting output now that pytest does no
introduce unwanted "buffering" on "-s" calls.
2013-09-27 12:28:34 +02:00
holger krekel
684d7f8668 remove gittip mention for now. 2013-09-27 10:58:04 +02:00
holger krekel
1327eb7cef rework docs to demonstrate and discuss current yield syntax in more depth. 2013-09-27 10:21:23 +02:00
holger krekel
030c337c68 don't manipulate FDs at all if output capturing is turned off. 2013-09-27 09:49:39 +02:00
holger krekel
3ab9b48782 introduce yieldctx=True in the @pytest.fixture decorator. Refactor tests and docs. 2013-09-26 12:57:21 +02:00
holger krekel
2bdd034242 fix issue355: junitxml generates name="pytest" tag. 2013-09-26 08:45:50 +02:00
Anthon van der Neut
b5a83a6af1 argcomplete_win: skip testing of argcomplete on windows 2013-09-09 12:41:29 +02:00
holger krekel
d565df90ad fix issue333: fix a case of bad unittest/pytest hook interaction. 2013-09-09 09:56:53 +02:00
holger krekel
88dc5f8204 Merge pull request #6 from bubenkoff/fix-failing-travis
only force tox to upgrade
2013-09-08 23:12:07 -07:00
Ronny Pfannschmidt
cf37c477bb output errors for all failures of specific collection
when issueing a command with many specific items to collect,
print all collect failures instead of just the first one

--HG--
branch : multi-usageerror
2013-09-08 22:26:51 +02:00
Anatoly Bubenkov
fb6282caaa only force tox to upgrade 2013-09-07 20:23:44 +02:00
holger krekel
f7f569f730 Merged in paylogic/pytest/parametrize-fails-when-values-are (pull request #68)
parametrize fails when values are unhashable - add test
2013-09-07 09:16:35 +02:00
Anatoly Bubenkov
63a924b922 parametrize fails when values are unhashable - tests
--HG--
branch : parametrize-fails-when-values-are
2013-09-07 02:30:09 +02:00
Anatoly Bubenkov
f5897498f3 initial
--HG--
branch : parametrize-fails-when-values-are
2013-09-06 22:42:54 +02:00
holger krekel
c478027805 make "import pdb ; pdb.set_trace()" work natively wrt capturing (no "-s" needed
anymore), turning ``pytest.set_trace()`` into a mere shortcut.
2013-09-06 15:29:00 +02:00
holger krekel
109e2f215f add nose.SkipTest for python2.6 -- which apparently is a subclass from python2.7 on.
addresses issue236
2013-09-06 12:48:54 +02:00
holger krekel
41df742faf fix <py27 tests with nose 2013-09-06 12:32:55 +02:00
holger krekel
86f70f5201 fix issue352: fix reference to py.path.local description in tmpdir documentation
(generally to be found at http://pytest.org/latest/tmpdir.html )
2013-09-06 12:16:05 +02:00
holger krekel
94ee37cdb3 - fix issue181: --pdb now also works on collect errors. This was
implemented by a slight internal refactoring and the introduction
  of a new hook ``pytest_exception_interact`` hook.

- fix issue341: introduce new experimental hook for IDEs/terminals to
  intercept debugging: ``pytest_exception_interact(node, call, report)``.
2013-09-06 11:56:04 +02:00
holger krekel
8360c1e687 xfail some tests for doctest support if pdbpp is installed 2013-09-06 10:07:06 +02:00
holger krekel
ca5d02df06 another way how bash reacts when no argcomplete is there? 2013-09-05 22:32:35 +02:00
holger krekel
c3fcf4d928 show more info if the test fails 2013-09-05 22:22:14 +02:00
holger krekel
517d498285 fix issue169: respect --tb=style with setup/teardown errors as well. 2013-09-05 15:43:19 +02:00
holger krekel
9686a4129c Merged in mcmtroffaes/pytest/fix-nose-docs (pull request #67)
Fix instructions for nose users.
2013-09-05 12:10:25 +02:00
Matthias C. M. Troffaes
b7d31952eb Fix instructions for nose users.
--HG--
branch : fix-nose-docs
2013-08-23 11:59:57 +01:00
holger krekel
b879074a64 refs issue290 -- move and refactor the test the string/int-id parametrization test (Which xfails) 2013-08-16 11:41:31 +02:00
holger krekel
4800aeaef7 Merged in markon/pytest (pull request #66)
Fix @parametrize.
2013-08-16 11:38:00 +02:00
holger krekel
ca7c1f5d8e merge pull request #27: correctly handle nose.SkipTest during collection. Thanks
Antonio Cuni, Ronny Pfannschmidt.  I did a few tweaks to the test and the
activation (depending on if unittest is imported at all).
2013-08-16 11:33:58 +02:00
Marco Buccini
f5a6a84314 test marked as 2013-08-16 09:55:25 +02:00
holger krekel
2888988eb6 fix manifest 2013-08-15 13:05:01 +02:00
holger krekel
e27dbdd071 Merged in bubenkoff/pytest/fix-broken-tests (pull request #65)
Fix broken python3 and python2.5 tests
2013-08-15 13:03:20 +02:00
Marco Buccini
6c54ee03de Fix @parametrize when using an integer and strings as parameters in a test accepting a parameter and a fixture as arguments. 2013-08-15 12:52:34 +02:00
Anatoly Bubenkov
0cd7effe35 fix broken python3 and python2.5 tests
--HG--
branch : fix-broken-tests
2013-08-15 11:52:55 +02:00
Anatoly Bubenkov
5851a99b82 initial
--HG--
branch : fix-broken-tests
2013-08-15 09:25:00 +02:00
holger krekel
863a206727 Merged in bubenkoff/pytest/overriden-fixture-finalizer (pull request #64)
overriden fixture finalizer tests
2013-08-15 07:06:25 +02:00
Anatoly Bubenkov
722b35b0a6 tests for fixture finalizers
--HG--
branch : overriden-fixture-finalizer
2013-08-14 13:58:59 +02:00
Anatoly Bubenkov
51dd63d3e1 ignores
--HG--
branch : overriden-fixture-finalizer
2013-08-14 10:09:02 +02:00
holger krekel
57f997b0b4 strike distribute dep 2013-08-11 18:19:58 +02:00
holger krekel
654212d93b add a note about how a lightweight but more powerful function-mocker could be done
(compared to standard mock).
2013-08-09 10:22:49 +02:00
holger krekel
88aa8f5435 mention pytest_collection_modifyitems in plugin page 2013-08-08 23:32:14 +02:00
holger krekel
0755d0605f remove automatic tox-testing of py25 2013-08-08 13:18:46 +02:00
holger krekel
4b88d6d2d7 monkeypatch.replace() now only accepts a string. Improved error handling and
docs thanks to suggestions from flub, pelme, schmir, ronny.
2013-08-07 16:49:29 +02:00
holger krekel
407283ef81 a new monkeypatch.replace(target, value) call which derives the
monkeypatch location from target (can be class/module/function or
string which is taken as importable python path)
examples:

    monkeypatch.replace(os.path.abspath, lambda x: "")
    monkeypatch.replace("requests.get", ...)
2013-08-07 15:35:27 +02:00
holger krekel
3fddf99661 Merged in anthon_van_der_neut/pytest_argcomplete (pull request #63)
argcomplete: FastFileCompleter that doesn't call bash in subprocess, strip prefix dir
2013-08-06 15:41:54 +02:00
holger krekel
21f72b7163 Merged in pelme/pytest/quiet-color-summary (pull request #61)
Added color to the quite mode summary
2013-08-06 15:38:43 +02:00
Anthon van der Neut
719e89fc1a argcomplete: FastFileCompleter that doesn't call bash in subprocess, strip prefix dir
```
timeit result for 10000 iterations of expanding '/d' (lowered the count in the code afterwards)
#                      2.7.5     3.3.2
# FilesCompleter       75.1109   69.2116
# FastFilesCompleter    0.7383    1.0760
```
- does not display prefix dir (like bash, not like compgen), py.test /usr/<TAB> does not show /usr/bin/ but bin/
2013-08-06 15:33:27 +02:00
Andreas Pelme
afa88a479b Added color to the quite mode summary. Also changed the output format
slightly to match the output of the standard summary.

--HG--
branch : quiet-color-summary
2013-08-05 09:45:10 +02:00
holger krekel
7d86827b5e ref #322 cleanup all teardown calling to only happen when setup succeeded.
don't use autouse fixtures for now because it would cause a proliferation
and overhead for the execution of every test.  Rather introduce a
node.addfinalizer(fin) to attach a finalizer to the respective node
and call it from node.setup() functions if the setup phase succeeded
(i.e. there is no setup function or it finished successfully)
2013-08-02 09:52:40 +02:00
holger krekel
b2ebb80878 fix issue322: tearDownClass is not run if setUpClass failed. Thanks
Mathieu Agopian for fixing.  The patch moves handling setUpClass
into a new autofixture. (XXX impl-decide if rather adding addfinalizer()
API to node's would have a similar effect)
2013-08-02 00:02:28 +02:00
Mathieu Agopian
7fc0d45a4c refs #322: setUpClass and tearDownClass as autouse fixture and finalizer 2013-08-01 23:48:40 +02:00
Ronny Pfannschmidt
3b85a56db2 merge 2013-08-01 22:55:16 +02:00
Ronny Pfannschmidt
743711cd1f fix issue317: assertion rewriter support for the is_package method 2013-08-01 22:11:18 +02:00
Floris Bruynooghe
cfe1d4f7c9 mention fix for issue 336 in changelog 2013-08-01 19:03:53 +01:00
Floris Bruynooghe
2cdb54225c Fix issue 336: autouse fixtures in plugins work again
When an autouse fixture in a plugin was encountered None was stored as nodeid
where it used to be ''.  This broke the lookup of autouse fixtures later on.

This also adds another test for the normal fixture ordering which was slightly
wrong: a fixture without location was always added at the front of the fixture
list rather then at the end of the fixtures without location but before the
fixtures with location.
2013-08-01 18:58:28 +01:00
holger krekel
8f24e10571 add changelog entry for anthon's hynek-fication of options,
and change the docs and tests to use the new style.
2013-08-01 17:32:19 +02:00
holger krekel
3ac36f6572 Merged in anthon_van_der_neut/pytest/opt-drop-non-hyphened-long-options (pull request #57)
changes to addoption() for hyphenated long-options
2013-08-01 17:04:18 +02:00
Anthon van der Neut
e96da76c3b changes to addoption() for hyphenated long-options
--HG--
branch : opt-drop-non-hyphened-long-options
2013-08-01 16:49:26 +02:00
holger krekel
ca6f3d24c3 Merged in anthon_van_der_neut/pytest/opt-drop-non-hyphened-long-options (pull request #56)
drop help for long options if longer versions with hyphens are available
2013-08-01 16:33:50 +02:00
Anthon van der Neut
e24b56af6c removed two superfluous parser arguments
--HG--
branch : opt-drop-non-hyphened-long-options
2013-08-01 16:27:06 +02:00
Anthon van der Neut
007a77c2ba drop help for long options if longer versions with hyphens are available
--HG--
branch : opt-drop-non-hyphened-long-options
2013-08-01 16:21:33 +02:00
Floris Bruynooghe
18fa7d866d Close issue 279: improved assertrepr_compare 2013-08-01 15:02:58 +01:00
holger krekel
9ccd52d538 fix issue305 - ignore any problems in writing a pyc file, but print out a trace. 2013-08-01 15:43:42 +02:00
holger krekel
cbbbfcd101 fix collection imports for python2.5 2013-08-01 15:38:03 +02:00
Mathieu Agopian
72a48d69cd refs #279: sequence assertions can also deal with (Mutable)Sequence instances 2013-08-01 14:48:34 +02:00
holger krekel
7e4b21e9a7 merge 2013-08-01 14:45:24 +02:00
holger krekel
b90d82c17f fix some py33 issues introduced with rev 2985
--HG--
branch : argcomplete
2013-08-01 14:24:25 +02:00
holger krekel
b60a8c12d5 fix Mathieu's name. 2013-08-01 12:12:09 +02:00
holger krekel
a24c7b42f1 add changelog entry for fixed issue 335. 2013-08-01 11:36:05 +02:00
Mathieu Agopian
0350a1929d merge 2013-08-01 11:20:30 +02:00
Mathieu Agopian
99783b6fba refs #335: clarify that the exception info returned by pytest.raises is a py.code.ExceptionInfo() 2013-08-01 11:19:47 +02:00
Mathieu Agopian
0e3abdc1af Merged hpk42/pytest into default 2013-08-01 11:12:59 +02:00
Mathieu Agopian
905c648b99 fixes #335: document ExceptionInfo returned by pytest.raises 2013-08-01 11:12:02 +02:00
holger krekel
b81c257360 small mod to test BND 2013-08-01 10:59:45 +02:00
holger krekel
64e9956770 plugin versions are displayed now. 2013-08-01 10:57:36 +02:00
holger krekel
2385553790 no funcargs for setup functions, rather use autouse fixtures. 2013-08-01 10:43:02 +02:00
holger krekel
4c6a11b8e1 remove an old issue. 2013-08-01 10:40:55 +02:00
holger krekel
1111d5b26b remove an entry 2013-08-01 10:37:45 +02:00
holger krekel
44d5524be2 Merged in anthon_van_der_neut/pytest/argcomplete (pull request #51)
fix for tests running subprocesses of py.test after test_argcomplete
2013-08-01 10:30:24 +02:00
holger krekel
1023390f53 fix issue334: don't recommend distribute but setuptools everywhere, also remove implicit distribute_setup support from setup.py. 2013-08-01 09:42:44 +02:00
holger krekel
02199c218d add license note to README 2013-08-01 09:31:34 +02:00
holger krekel
46901fb813 fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho.
(this is just changing the CHANGELOG entry because the bug was already fixed earlier)
2013-08-01 07:43:00 +02:00
Anthon van der Neut
ef2ddb6f16 monkeypatch for os.environment changes
--HG--
branch : argcomplete
2013-07-31 21:33:13 +02:00
Anthon van der Neut
e3a2e1bbf8 fix for tests running subprocesses of py.test after test_argcomplete
(which all still ran with argcompletion enabled) -> fail

--HG--
branch : argcomplete
2013-07-31 16:03:53 +02:00
holger krekel
8a0a880294 Merged in anthon_van_der_neut/pytest/argcomplete (pull request #50)
Fixes for argcomplete
2013-07-31 07:51:07 +02:00
Anthon van der Neut
6817a56270 minor adjustment, added test for positional argument completion
--HG--
branch : argcomplete
2013-07-30 12:33:38 +02:00
Anthon van der Neut
87860600fb Fixes for argcomplete
- separate out most argcomplete related stuff in new file _argcomplete.py
  (could probably be in the py library)
- allow positional arguments to be interspaced with optional arguments
  ( + test in test_parseopt.py )
- removed double argument in tox.ini
- add documentation on installing argcomplete (>=0.5.7 as needed for
  Python 3), might need improving/incorporation in index.

This does not work on 2.5 yet. I have patches for argcomplete
(with/print()/"".format) but I am not sure they will be accepted.
Agreed with hpk not to push for that.

Removing argcomplete and leaving completion code active now works by early
exit, so <TAB> no longer re-runs the programs without parameters
(which took long for py.test)

test calls bash with a script that redirects filedescriptor 8 (as used by
argcomplete), so the result can be tested.

--HG--
branch : argcomplete
2013-07-30 11:26:15 +02:00
holger krekel
377f63085a be more liberal with respect to lsof checks because jenkins keeps some files open 2013-07-29 15:39:24 +02:00
holger krekel
2a7c79dbf5 make genscript provide information as to compatibility
(now that argparse is a dependency on python2.6)
2013-07-26 08:59:31 +02:00
holger krekel
7a8134660f merge doc changes 2013-07-26 08:59:29 +02:00
holger krekel
863a255c9d Merged in anthon_van_der_neut/pytest/tox_reference (pull request #47)
update for links to tox
2013-07-26 08:59:12 +02:00
Anthon van der Neut
9b51105afa also update testrun.org in 日本語
--HG--
branch : tox_reference
2013-07-26 08:20:26 +02:00
Anthon van der Neut
4b56b075c1 updated tox to live on testrun.org (the old links are still
working on codespeak.net, but those docs are outdated)

--HG--
branch : tox_reference
2013-07-26 08:14:49 +02:00
holger krekel
788303523e add changelog: integrate option tab-completion when argcomplete is used. Thanks
Anthon van der Neut for the PR.  This also lets pytest use argparse
instead of optparse.
2013-07-26 07:51:33 +02:00
holger krekel
4b87810fc2 Merged in anthon_van_der_neut/pytest/argparse (pull request #46)
argparse / argcomplete
2013-07-26 07:41:43 +02:00
Anthon van der Neut
ad72e7f29d auto change %default -> %(default)s in help parameter string (on retrieval)
added code for warnings on optparse arguments (type, help),
which can be easily switched on with TYPE_WARN = True in config.py


installed and tested ( py.test --help )
pytest-quickcheck-0.7
pytest-gae-0.2.2
pytest-growl-0.1
pytest-bdd-0.4.7
pytest-bdd-splinter-0.4.4
pytest-cache-1.0
pytest-capturelog-0.7
pytest-codecheckers-0.2
pytest-contextfixture-0.1.1
pytest-cov-1.6
pytest-flakes-0.1
pytest-incremental-0.3.0
pytest-xdist-1.8
pytest-localserver-0.1.5
pytest-monkeyplus-1.1.0
pytest-oerp-0.2.0
pytest-pep8-1.0.4
pytest-pydev-0.1
pytest-rage-0.1
pytest-runfailed-0.3
pytest-timeout-0.3
pytest-xprocess-0.7
pytest-browsermob-proxy-0.1
pytest-mozwebqa-1.1.1
pytest-random-0.02
pytest-rerunfailures-0.03
pytest-zap-0.1
pytest-blockage-0.1
pytest-django-2.3.0
pytest-figleaf-1.0
pytest-greendots-0.1
pytest-instafail-0.1.0
pytest-konira-0.2
pytest-marker-bugzilla-0.06
pytest-marks-0.4
pytest-poo-0.2
pytest-twisted-1.4
pytest-yamlwsgi-0.6

--HG--
branch : argparse
2013-07-25 17:26:48 +02:00
Anthon van der Neut
15ec5a898c moving from optparse to argparse. Major difficulty is
that argparse does not have Option objects -> added class Argument
Needed explicit call of MyOptionParser.format_epilog as argparse
does not have that. The parse_arg epilog argument wraps the text,
which is not the same (could be handled with a special formatter).

- parser.parse() now returns single argument (with positional args in
  .file_or_dir)
- "file_or_dir" made a class variable Config._file_or_dir and used in help and tests
- added code for argcomplete (because of which this all started!)

addoption:
- if option type is a string ('int' or 'string', this converted to
  int resp. str
- if option type is 'count' this is changed to the type of choices[0]

testing:
- added tests for Argument
- test_mark.test_keyword_extra split as ['-k', '-mykeyword'] generates argparse
  error test split in two and one marked as fail
- testing hints, multiline and more strickt (for if someone moves format_epilog
  to epilog argument of parse_args without Formatter)
- test for destination derived from long option with internal dash
- renamed second test_parseopt.test_parse() to test_parse2 as it was
  not tested at all (the first was tested.)

--HG--
branch : argparse
2013-07-25 15:33:43 +02:00
holger krekel
9d9dd381bc mention github and bitbucket 2013-07-24 12:14:53 +02:00
holger krekel
997df928b7 stick to virtualenv<1.10 for now because it breaks python2.5 2013-07-24 12:08:20 +02:00
holger krekel
6d145ac93a bump version 2013-07-24 11:16:19 +02:00
holger krekel
1280add047 SO-17664702: call fixture finalizers even if the fixture function
partially failed (finalizers would not always be called before)
2013-07-17 10:29:11 +02:00
holger krekel
c53556b88d paint last line red if "failures" or "errors" occured, attribute theuni 2013-07-17 09:31:55 +02:00
holger krekel
60a53c75a6 some python2.5/3.3 fixes of Brianna's parametrize improvements 2013-07-16 15:43:20 +02:00
holger krekel
ca8281f229 merge better parametrize error messages, thanks Brianna Laugher 2013-07-16 15:32:05 +02:00
holger krekel
af7db5195b Merged in pfctdayelise/pytest (pull request #38)
A couple of improvements to parametrize
2013-07-16 15:30:48 +02:00
holger krekel
c2138e9733 add python testing training 2013-07-16 11:30:21 +02:00
holger krekel
31c1c69901 fix link to kotti 2013-07-11 16:07:58 +02:00
holger krekel
b7054495a7 send IRC notifications to pytest-dev 2013-07-11 12:20:38 +02:00
holger krekel
fc03c35bbd Merge pull request #3 from bubenkoff/travis-status-icon
correct travis build status image url
2013-07-11 03:08:27 -07:00
Anatoly Bubenkov
8320232f38 correct travis build status image url 2013-07-11 12:06:13 +02:00
holger krekel
52838a7834 Merge pull request #2 from bubenkoff/py25-test_skipping_faild
fixes for py25 in test_skipping
2013-07-11 02:30:01 -07:00
Anatoly Bubenkov
87eae6213e fixes for py25 in test_skipping 2013-07-11 11:15:31 +02:00
holger krekel
5d8b950b7f change copyright years 2013-07-11 10:50:59 +02:00
Anatoly Bubenkov
7b54476d71 Update README.rst
change the travis link and image to be correct
2013-07-10 13:51:43 +02:00
holger krekel
13ddce2381 fix issue320 - fix class scope for fixtures when mixed with
module-level functions.  Thanks Anatloy Bubenkoff.
2013-07-08 15:54:38 +02:00
holger krekel
be30eb22a6 fix docs wrt norecursedirs, thanks @mgax 2013-07-08 15:39:14 +02:00
Anatoly Bubenkov
589138ea71 re #320 fallback to test scope if the class-scoped fixture is used in non-class-based test function
--HG--
branch : 320-class-scoped-fixture-caching-is-broken-if
2013-07-06 21:30:24 +02:00
holger krekel
f7a9beaefb Merged in bubenkoff/pytest/329-skipif-requires-expression-as-a-string (pull request #43)
re #329 add test for skipif failure when you pass boolean without the reason. add emphasize to the docs.
2013-07-06 20:13:27 +02:00
Anatoly Bubenkov
214793f697 re #329 add test for skipif failure when you pass boolean without the reason. add emphasize to the docs.
--HG--
branch : 329-skipif-requires-expression-as-a-string
2013-07-06 18:54:24 +02:00
Floris Bruynooghe
c36186ce65 Always check for both ENOENT and ENOTDIR
This fixes issue 326.
2013-07-06 18:53:26 +02:00
Floris Bruynooghe
e6a063ee47 Solve fixture ordering when loading plugins from conftest
Conftests are plugins with a location attached to them while other
plugins do not have a location.  When ordering fixturedefs those from
plugins without a location need to be listed first.
2013-07-06 17:56:54 +02:00
holger krekel
723e414814 add KAsia to authors 2013-07-06 17:17:03 +02:00
holger krekel
a00b516f9a add kasia to changelog 2013-07-06 17:06:51 +02:00
holger krekel
31421cb6d7 merge 2013-07-06 16:03:48 +02:00
holger krekel
a6f2af23fb Merged in katarzynaanna/pytest (pull request #42)
Improved reporting
2013-07-06 16:03:27 +02:00
Katarzyna Jachim
ffa1bf726d merge 2013-07-06 15:54:33 +02:00
holger krekel
199f0314b9 Merged in bubenkoff/pytest/travis-integration (pull request #41)
add travis integration, fixes for py25 and py27 no pyc tox env
2013-07-06 15:51:14 +02:00
Katarzyna Jachim
87df85f12d improved reporting
added intermediate level of quiet reporting:
 * -q now shows short summary (# passed/failed tests + time)
 * the former -q is now -qq
2013-07-06 15:43:59 +02:00
holger krekel
ae327ef435 move to development doc target 2013-07-06 15:38:40 +02:00
Anatoly Bubenkov
1736242bd7 add travis integration, fixes for py25 and py27 no pyc tox env
--HG--
branch : travis-integration
2013-07-06 14:23:02 +02:00
Floris Bruynooghe
1a319056fc Mention issue 300 in changelog 2013-07-06 11:00:29 +02:00
Anatoly Bubenkov
ea7a997afc remove unnecessary print 2013-07-06 10:26:14 +02:00
Anatoly Bubenkov
2c7613c15c merge with upstream 2013-07-06 10:06:12 +02:00
Christian Theune
ab637e028b Merged in ctheune/pytest-greenbar-1/ctheune/typo-1372873724648 (pull request #1)
Typo
2013-07-03 19:49:28 +02:00
Christian Theune
1934f515ef Typo
--HG--
branch : ctheune/typo-1372873724648
2013-07-03 17:48:57 +00:00
Christian Theune
d9f0a28da2 Compatibility with my spinal cord reflexes: colorize last summary line.
Provide a red bar if there are any 'failures'. Otherwise make it green.
2013-07-03 19:43:18 +02:00
Christian Theune
ca88c02507 Support working in a local virtualenv. 2013-07-03 19:41:05 +02:00
holger krekel
ea4a3adfd6 - add my ep2013 talk to talks page
- add "talks/blogs" to the navigation side bar
2013-07-03 11:47:18 +02:00
holger krekel
c4c966683c fix issue323 - parametrize() of many module-scoped params 2013-06-28 12:57:10 +02:00
holger krekel
469830fffa some internal renaming to make more sense of the sorting algo,
no semantical changes.
2013-06-28 12:54:10 +02:00
holger krekel
f9720a38fe mention added support for setUpModule/tearDownModule detection, thanks Brian Okken. 2013-06-23 09:24:48 +02:00
Brian Okken
28b2859718 change how the test is called 2013-06-22 09:42:31 -07:00
Brian Okken
5e77eb23eb add test_unittest_style_setup_teardown()
to test setUpModule() and tearDownModule()
2013-06-22 09:35:10 -07:00
variedthoughts
3bcd3317ad support unittest setUpModule/tearDownModule 2013-06-20 14:43:42 +00:00
holger krekel
4af052b098 added some endorsements, not quite properly layouted 2013-06-20 14:05:16 +02:00
holger krekel
ac3d8800fd make sessionfinish hooks execute with the same cwd-context as at
session start (helps fix plugin behaviour which write output files
with relative path such as pytest-cov)
2013-06-10 10:09:28 +02:00
holger krekel
2951c3ace9 Merged in embray/pytest (pull request #37)
Adds a test for and fixes #112
2013-06-09 15:07:44 +02:00
Erik Bray
17e1106584 reindent a few of the blockquotes in these tests 2013-06-07 17:30:10 -04:00
holger krekel
7e2d4daa68 Merge pull request #1 from alfredodeza/297
add ref targets on recwarn
2013-06-03 07:13:04 -07:00
Alfredo Deza
0cfc4a49ea adding ref targets on recwarn 2013-06-03 10:07:14 -04:00
holger krekel
da1996b5f5 fix issue316 - properly reference collection hooks in docs 2013-06-03 10:04:50 +02:00
Brianna Laugher
345b8391c4 A couple of improvements to parametrize
- When not specifying ids, let None and bools use their native string form (like str, int, float) rather than obfuscated form used for objects
- When specifying ids, explicitly raise a ValueError if a different number of ids are specified compared to the test cases
- Add tests for both these items.
2013-05-29 12:59:47 +10:00
Erik Bray
b1595d3f61 Adds a test for and fixes #112. If attempting to write to the __pycache__ directory raises a permission error _write_pyc() should just return False to prevent any further write attempts. 2013-05-28 18:11:12 -04:00
holger krekel
c294a417bd allow to specify parametrize inputs as a comma-separated string
add Wouter to changelog and to authors
2013-05-28 10:32:54 +02:00
Benjamin Peterson
bc5a5a63f2 use __dict__ not func_dict for Python 3 compatibility 2013-05-27 14:04:53 -07:00
holger krekel
655afba17d Merged in w00t0r/pytest-fixes (pull request #35)
Fixed issue #306: Keywords and markers are now matched in a defined way. Also applied some pep8 formatting while fixing.
2013-05-27 21:40:41 +02:00
Wouter van Ackooy
212f4b4d64 Issue 306: Used a set for the extra_keywords, and used listchain for parent iteration. 2013-05-27 18:14:35 +02:00
Wouter van Ackooy
60906f7a46 Issue 306: Use the names of all the parents in the chain for matching, except the Instance objects. 2013-05-27 17:58:39 +02:00
Wouter van Ackooy
72afbbbd71 Added new test to check on matching markers to full test names, which was possible before. Also adjusted check on number of deselected tests. 2013-05-23 12:21:40 +02:00
Wouter van Ackooy
583c736f0c Added a test to check there is no matching on magic values. 2013-05-23 09:12:50 +02:00
holger krekel
8a0a18e9b3 - add Brianna (@pfctdayelise ) to changelog and contributors
- fix some broken tests on py32/py33 (related to issue308 merge)
- re-format docstrings
-
2013-05-22 15:24:58 +02:00
holger krekel
bbc61c85ac Merged in pfctdayelise/pytest (pull request #36)
issue 308
2013-05-22 13:36:39 +02:00
Wouter van Ackooy
02511d1564 Added lost space. 2013-05-22 07:41:46 +02:00
holger krekel
f78408df77 add holger's gittip account, would also like to add ronny's 2013-05-21 16:05:32 +02:00
Brianna Laugher
f2175146a9 Merged hpk42/pytest into default 2013-05-21 11:18:37 +10:00
Brianna Laugher
d8bc40271a issue #308
+ docs
2013-05-21 11:12:45 +10:00
Wouter van Ackooy
fe27f3cc7d Fixed issue #306: Keywords and markers are now matched in a defined way. Also applied some pep8 formatting while fixing. 2013-05-20 14:37:58 +02:00
Brianna Laugher
3aa0e4a526 ? pull/merge 2013-05-20 12:56:30 +10:00
Brianna Laugher
ee65ca10f4 issue #308
address some comments by @hpk42 on 0b9d82e :

- move tests into their own class, rename
- add test showing metafunc.parametrize called in pytest_generate_tests rather than as decorator
- add test and fix single-argname case
- convert two loops into one in parametrize()

also
- renamed 'input' to 'n', since 'input' is a built-in
2013-05-20 12:52:20 +10:00
holger krekel
afbeb056f0 added changelog for improved doctest counting 2013-05-17 20:48:51 +02:00
Danilo de Jesus da Silva Bellini
242b67de17 zero to many doctests from module instead of one 2013-05-17 12:18:22 -03:00
holger krekel
ed1095565b Merged hpk42/pytest into default 2013-05-17 11:32:52 +02:00
Brianna Laugher
5373a63008 issue #308
first attempt, mark individual parametrize test instances with other marks (like xfail)
2013-05-17 18:46:36 +10:00
holger krekel
e6e86fa462 fix issue307 - use yaml.safe_load instead of yaml.load, thanks Mark Eichin. 2013-05-16 09:59:48 +02:00
holger krekel
5a1ce3c45c add Jaap Broekhuizen for junitxml gen 2013-05-10 08:14:39 +02:00
holger krekel
67279418ff fix junitxml generation when test output contains control characters,
addressing issue267
2013-05-10 08:13:35 +02:00
holger krekel
1f1c24fe15 Merged in jaapz/pytest-xml-escape-control-chars (pull request #32)
Fix junitxml generation when using special characters in parametrized tests.
2013-05-10 08:06:31 +02:00
Jaap Broekhuizen
7803bca335 Implemented a test for xml control character fail. 2013-05-09 21:16:57 +02:00
holger krekel
c610c903f6 mention --tb style change in changelog 2013-05-09 15:50:28 +02:00
holger krekel
36e7cc1b9c honor --tb style for setup/teardown errors as well. 2013-05-09 15:50:09 +02:00
holger krekel
d69c9da656 add maho as contributor 2013-05-09 15:37:51 +02:00
holger krekel
a113c4c6d3 Merged in maho/pytest (pull request #31)
#299
2013-05-09 15:32:29 +02:00
maho
9e3cd03721 #299 - polishing 2013-05-08 17:01:20 +02:00
Jaap Broekhuizen
0e5f2847f1 Fix pytest.py permissions. 2013-05-08 16:11:55 +02:00
Jaap Broekhuizen
963b944e79 Fix junitxml generation when using special characters in parametrized tests. 2013-05-08 15:15:43 +02:00
holger krekel
55cd3d8bf3 bump version 2013-05-07 21:39:30 +02:00
holger krekel
150ad0172f document context fixtures, also improve plugin docs 2013-05-07 21:37:08 +02:00
holger krekel
9d8645b45d enhance index page, fix announcement index 2013-05-07 21:34:59 +02:00
holger krekel
bbd265184d support boolean condition expressions in skipif/xfail
change documentation to prefer it over string expressions
2013-05-07 18:40:26 +02:00
holger krekel
3279cfa28b don't use indexservers anymore 2013-05-07 16:26:56 +02:00
holger krekel
5fb4a100c9 Removed tag 1.4.14 2013-05-07 10:55:41 +02:00
holger krekel
71b4908233 Removed tag 1.4.14 2013-05-07 10:54:46 +02:00
holger krekel
77d2f6adde fix issue245 by depending on py-1.4.14 which fixes py.io.dupfile
to not assume file.mode is present.
2013-05-07 10:54:05 +02:00
holger krekel
51688270ac implemented as context managers. Thanks Andreas Pelme,
ladimir Keleshev.
fix issue245 by depending on the released py-1.4.14
which fixes py.io.dupfile to work with files with no
mode. Thanks Jason R. Coombs.
2013-05-07 10:53:31 +02:00
holger krekel
19f3e06ab0 Added tag 1.4.14 for changeset b93ac0cdae02 2013-05-07 10:48:13 +02:00
hg
d2dc797779 #299 2013-05-05 22:15:06 +02:00
holger krekel
56aa9962fc allow fixture functions to be implemented as context managers:
@pytest.fixture
def myfix():
    # setup
    yield 1
    # teardown
2013-05-05 14:48:37 +02:00
holger krekel
8e41ef5776 bump version 2013-05-05 14:48:17 +02:00
holger krekel
331bd84ef4 change version 2013-05-05 14:23:47 +02:00
holger krekel
4ac3445056 Added tag 2.3.5 for changeset fc3a793e87ec 2013-04-30 16:41:01 +02:00
Floris Bruynooghe
c93fbb0e57 Load conftest files in the correct order initially
When the conftest.py files are looked for intially they got loaded
starting from the subdir ending at the parent dir(s).  Later on during
collection any conftest.py files are loaded starting from the parent
dir ending at the subdir.  Due to how extending fixtures works the
latter is correct as otherwise the wrong fixture will be available.
So this changes the initial conftest loading to start at the root and
go towards the subdir.

This does also affect the order of other hooks, hence the order of the
reporting being different in testing/test_terminal.py.
2013-04-18 12:24:53 +01:00
Antonio Cuni
ba0100e057 (antocuni, ronny around): import directly from _pytest.runner to avoid the usage of @property 2013-03-14 16:53:57 +01:00
Antonio Cuni
37c47155e0 correctly handle nose.SkipTest during collection 2013-03-14 16:10:33 +01:00
358 changed files with 23214 additions and 18308 deletions

7
.coveragerc Normal file
View File

@@ -0,0 +1,7 @@
[run]
omit =
# standlonetemplate is read dynamically and tested by test_genscript
*standalonetemplate.py
# oldinterpret could be removed, as it is no longer used in py26+
*oldinterpret.py
vendored_packages

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
CHANGELOG merge=union

View File

@@ -1,28 +1,34 @@
# Automatically generated by `hgimportsvn`
syntax:glob
.svn
.hgsvn
# Ignore local virtualenvs
lib/
bin/
include/
.Python/
# These lines are suggested according to the svn:ignore property
# Feel free to enable them by uncommenting them
syntax:glob
*.pyc
*.pyo
*.swp
*.html
*.class
*.orig
*~
.eggs/
doc/*/_build
build/
dist/
*.egg-info
issue/
env/
.env/
3rdparty/
.tox
.cache
.coverage
.ropeproject
.idea

56
.hgtags
View File

@@ -1,56 +0,0 @@
52c6d9e78777a5a34e813123997dfc614a1a4767 1.0.0b3
1c7aaa8c61f3b0945921a9acc7beb184201aed4b 1.0.0b4
1c7aaa8c61f3b0945921a9acc7beb184201aed4b 1.0.0b4
0000000000000000000000000000000000000000 1.0.0b4
0000000000000000000000000000000000000000 1.0.0b4
8cd6eb91eba313b012d6e568f37d844dc0751f2e 1.0.0b4
8cd6eb91eba313b012d6e568f37d844dc0751f2e 1.0.0b4
0000000000000000000000000000000000000000 1.0.0b4
2cc0507f117ffe721dff7ee026648cfce00ec92f 1.0.0b6
86f1e1b6e49bf5882a809f11edd1dbb08162cdad 1.0.0b8
86f1e1b6e49bf5882a809f11edd1dbb08162cdad 1.0.0b8
c63f35c266cbb26dad6b87b5e115d65685adf448 1.0.0b8
c63f35c266cbb26dad6b87b5e115d65685adf448 1.0.0b8
0eaa0fdf2ba0163cf534dc2eff4ba2e5fc66c261 1.0.0b8
e2a60653cb490aeed81bbbd83c070b99401c211c 1.0.0b9
5ea0cdf7854c3d4278d36eda94a2b68483a0e211 1.0.0
5ea0cdf7854c3d4278d36eda94a2b68483a0e211 1.0.0
7acde360d94b6a2690ce3d03ff39301da84c0a2b 1.0.0
6bd221981ac99103002c1cb94fede400d23a96a1 1.0.1
4816e8b80602a3fd3a0a120333ad85fbe7d8bab4 1.0.2
60c44bdbf093285dc69d5462d4dbb4acad325ca6 1.1.0
319187fcda66714c5eb1353492babeec3d3c826f 1.1.1
4fc5212f7626a56b9eb6437b5c673f56dd7eb942 1.2.0
c143a8c8840a1c68570890c8ac6165bbf92fd3c6 1.2.1
eafd3c256e8732dfb0a4d49d051b5b4339858926 1.3.0
d5eacf390af74553227122b85e20345d47b2f9e6 1.3.1
d5eacf390af74553227122b85e20345d47b2f9e6 1.3.1
8b8e7c25a13cf863f01b2dd955978285ae9daf6a 1.3.1
3bff44b188a7ec1af328d977b9d39b6757bb38df 1.3.2
c59d3fa8681a5b5966b8375b16fccd64a3a8dbeb 1.3.3
79ef6377705184c55633d456832eea318fedcf61 1.3.4
79ef6377705184c55633d456832eea318fedcf61 1.3.4
90fffd35373e9f125af233f78b19416f0938d841 1.3.4
e9e127acd6f0497324ef7f40cfb997cad4c4cd17 2.0.0
e4497c2aed358c1988cf7be83ca9394c3c707fa2 2.0.1
84e5c54b72448194a0f6f815da7e048ac8019d50 2.0.2
2ef82d82daacb72733a3a532a95c5a37164e5819 2.0.3
2ef82d82daacb72733a3a532a95c5a37164e5819 2.0.3
c777dcad166548b7499564cb49ae5c8b4b07f935 2.0.3
c777dcad166548b7499564cb49ae5c8b4b07f935 2.0.3
49f11dbff725acdcc5fe3657cbcdf9ae04e25bbc 2.0.3
49f11dbff725acdcc5fe3657cbcdf9ae04e25bbc 2.0.3
363e5a5a59c803e6bc176a6f9cc4bf1a1ca2dab0 2.0.3
e5e1746a197f0398356a43fbe2eebac9690f795d 2.1.0
5864412c6f3c903384243bd315639d101d7ebc67 2.1.2
12a05d59249f80276e25fd8b96e8e545b1332b7a 2.1.3
1522710369337d96bf9568569d5f0ca9b38a74e0 2.2.0
3da8cec6c5326ed27c144c9b6d7a64a648370005 2.2.1
92b916483c1e65a80dc80e3f7816b39e84b36a4d 2.2.2
3c11c5c9776f3c678719161e96cc0a08169c1cb8 2.2.3
ad9fe504a371ad8eb613052d58f229aa66f53527 2.2.4
c27a60097767c16a54ae56d9669a77925b213b9b 2.3.0
acf0e1477fb19a1d35a4e40242b77fa6af32eb17 2.3.1
8738b828dec53937765db71951ef955cca4c51f6 2.3.2
7fe44182c434f8ac89149a3c340479872a5d5ccb 2.3.3
ef299e57f24218dbdd949498d7e660723636bcc3 2.3.4

40
.travis.yml Normal file
View File

@@ -0,0 +1,40 @@
sudo: false
language: python
python:
- '3.5'
# command to install dependencies
install: "pip install -U tox"
# # command to run tests
env:
matrix:
- TESTENV=coveralls
- TESTENV=doctesting
- TESTENV=flakes
- TESTENV=py26
- TESTENV=py27
- TESTENV=py27-cxfreeze
- TESTENV=py27-nobyte
- TESTENV=py27-pexpect
- TESTENV=py27-subprocess
- TESTENV=py27-trial
- TESTENV=py27-xdist
- TESTENV=py33
- TESTENV=py33
- TESTENV=py34
- TESTENV=py35-pexpect
- TESTENV=py35-trial
- TESTENV=py35-xdist
- TESTENV=py35
- TESTENV=pypy
script: tox --recreate -e $TESTENV
notifications:
irc:
channels:
- "chat.freenode.net#pytest"
on_success: change
on_failure: change
skip_join: true
email:
- pytest-commit@python.org

87
AUTHORS
View File

@@ -1,27 +1,70 @@
Holger Krekel, holger at merlinux eu
merlinux GmbH, Germany, office at merlinux eu
Contributors include::
Contributors include::
Ronny Pfannschmidt
Benjamin Peterson
Floris Bruynooghe
Samuele Pedroni
Carl Friedrich Bolz
Armin Rigo
Maciek Fijalkowski
Guido Wesdorp
Brian Dorsey
Ross Lawley
Ralf Schmitt
Chris Lamb
Harald Armin Massa
Martijn Faassen
Ian Bicking
Jan Balster
Grig Gheorghiu
Bob Ippolito
Christian Tismer
Daniel Nuri
Graham Horler
Abhijeet Kasurde
Anatoly Bubenkoff
Andreas Zeidler
Andy Freeland
Anthon van der Neut
Armin Rigo
Aron Curzon
Benjamin Peterson
Bob Ippolito
Brian Dorsey
Brian Okken
Brianna Laugher
Bruno Oliveira
Carl Friedrich Bolz
Charles Cloud
Chris Lamb
Christian Theunert
Christian Tismer
Christopher Gilling
Daniel Grana
Daniel Nuri
Dave Hunt
David Mohr
Edison Gustavo Muenz
Eduardo Schettino
Elizaveta Shashkova
Eric Hunsberger
Eric Siegerman
Florian Bruhin
Floris Bruynooghe
Graham Horler
Grig Gheorghiu
Guido Wesdorp
Harald Armin Massa
Ian Bicking
Jaap Broekhuizen
Jan Balster
Janne Vanhala
Jason R. Coombs
Jurko Gospodnetić
Katarzyna Jachim
Kevin Cox
Maciek Fijalkowski
Maho
Marc Schlaich
Mark Abramowitz
Markus Unterwaditzer
Martijn Faassen
Michael Droettboom
Nicolas Delaby
Pieter Mulder
Piotr Banaszkiewicz
Punyashloka Biswal
Ralf Schmitt
Ronny Pfannschmidt
Ross Lawley
Samuele Pedroni
Tom Viner
Trevor Bekolay
Wouter van Ackooy
David Díaz-Barquero
Eric Hunsberger
Simon Gomizelj
Russel Winder
Ben Webb

1182
CHANGELOG

File diff suppressed because it is too large Load Diff

221
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,221 @@
============================
Contribution getting started
============================
Contributions are highly welcomed and appreciated. Every little help counts,
so do not hesitate!
.. contents:: Contribution links
:depth: 2
.. _submitplugin:
Submit a plugin, co-develop pytest
----------------------------------
Pytest development of the core, some plugins and support code happens
in repositories living under:
- `the pytest-dev github organisation <https://github.com/pytest-dev>`_
- `the pytest-dev bitbucket team <https://bitbucket.org/pytest-dev>`_
All pytest-dev Contributors team members have write access to all contained
repositories. pytest core and plugins are generally developed
using `pull requests`_ to respective repositories.
You can submit your plugin by subscribing to the `pytest-dev mail list
<https://mail.python.org/mailman/listinfo/pytest-dev>`_ and writing a
mail pointing to your existing pytest plugin repository which must have
the following:
- PyPI presence with a ``setup.py`` that contains a license, ``pytest-``
prefixed, version number, authors, short and long description.
- a ``tox.ini`` for running tests using `tox <http://tox.testrun.org>`_.
- a ``README.txt`` describing how to use the plugin and on which
platforms it runs.
- a ``LICENSE.txt`` file or equivalent containing the licensing
information, with matching info in ``setup.py``.
- an issue tracker unless you rather want to use the core ``pytest``
issue tracker.
If no contributor strongly objects and two agree, the repo will be
transferred to the ``pytest-dev`` organisation and you'll become a
member of the ``pytest-dev Contributors`` team, with commit rights
to all projects. We recommend that each plugin has at least three
people who have the right to release to pypi.
.. _reportbugs:
Report bugs
-----------
Report bugs for pytest at https://github.com/pytest-dev/pytest/issues
If you are reporting a bug, please include:
* Your operating system name and version.
* Any details about your local setup that might be helpful in troubleshooting,
specifically Python interpreter version,
installed libraries and pytest version.
* Detailed steps to reproduce the bug.
If you can write a demonstration test that currently fails but should pass (xfail),
that is a very useful commit to make as well, even if you can't find how
to fix the bug yet.
.. _submitfeedback:
Submit feedback for developers
------------------------------
Do you like pytest? Share some love on Twitter or in your blog posts!
We'd also like to hear about your propositions and suggestions. Feel free to
`submit them as issues <https://github.com/pytest-dev/pytest/issues>`__ and:
* Set the "kind" to "enhancement" or "proposal" so that we can quickly find
about them.
* Explain in detail how they should work.
* Keep the scope as narrow as possible. This will make it easier to implement.
* If you have required skills and/or knowledge, we are very happy for
:ref:`pull requests <pull-requests>`.
.. _fixbugs:
Fix bugs
--------
Look through the GitHub issues for bugs. Here is sample filter you can use:
https://github.com/pytest-dev/pytest/labels/bug
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs.
Don't forget to check the issue trackers of your favourite plugins, too!
.. _writeplugins:
Implement features
------------------
Look through the GitHub issues for enhancements. Here is sample filter you
can use:
https://github.com/pytest-dev/pytest/labels/enhancement
:ref:`Talk <contact>` to developers to find out how you can implement specific
features.
Write documentation
-------------------
pytest could always use more documentation. What exactly is needed?
* More complementary documentation. Have you perhaps found something unclear?
* Documentation translations. We currently have only English.
* Docstrings. There's never too much of them.
* Blog posts, articles and such -- they're all very appreciated.
You can also edit documentation files directly in the Github web interface
without needing to make a fork and local copy. This can be convenient for
small fixes.
.. _`pull requests`:
.. _pull-requests:
Preparing Pull Requests on GitHub
---------------------------------
.. note::
What is a "pull request"? It informs project's core developers about the
changes you want to review and merge. Pull requests are stored on
`GitHub servers <https://github.com/pytest-dev/pytest/pulls>`_.
Once you send pull request, we can discuss it's potential modifications and
even add more commits to it later on.
There's an excellent tutorial on how Pull Requests work in the
`GitHub Help Center <https://help.github.com/articles/using-pull-requests/>`_,
but here is a simple overview:
#. Fork the
`pytest GitHub repository <https://github.com/pytest-dev/pytest>`__. It's
fine to use ``pytest`` as your fork repository name because it will live
under your user.
#. Clone your fork locally using `git <https://git-scm.com/>`_ and create a branch::
$ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git
$ cd pytest
# now, to fix a bug create your own branch off "master":
$ git checkout -b your-bugfix-branch-name master
# or to instead add a feature create your own branch off "features":
$ git checkout -b your-feature-branch-name features
Given we have "major.minor.micro" version numbers, bugfixes will usually
be released in micro releases whereas features will be released in
minor releases and incompatible changes in major releases.
If you need some help with Git, follow this quick start
guide: https://git.wiki.kernel.org/index.php/QuickStart
#. Install tox
Tox is used to run all the tests and will automatically setup virtualenvs
to run the tests in.
(will implicitly use http://www.virtualenv.org/en/latest/)::
$ pip install tox
#. Run all the tests
You need to have Python 2.7 and 3.5 available in your system. Now
running tests is as simple as issuing this command::
$ python runtox.py -e py27,py35,flakes
This command will run tests via the "tox" tool against Python 2.7 and 3.5
and also perform "flakes" coding-style checks. ``runtox.py`` is
a thin wrapper around ``tox`` which installs from a development package
index where newer (not yet released to pypi) versions of dependencies
(especially ``py``) might be present.
#. You can now edit your local working copy.
You can now make the changes you want and run the tests again as necessary.
To run tests on py27 and pass options to pytest (e.g. enter pdb on failure)
to pytest you can do::
$ python runtox.py -e py27 -- --pdb
or to only run tests in a particular test module on py35::
$ python runtox.py -e py35 -- testing/test_config.py
#. Commit and push once your tests pass and you are happy with your change(s)::
$ git commit -a -m "<commit message>"
$ git push -u
Make sure you add a CHANGELOG message, and add yourself to AUTHORS. If you
are unsure about either of these steps, submit your pull request and we'll
help you fix it up.
#. Finally, submit a pull request through the GitHub website using this data::
head-fork: YOUR_GITHUB_USERNAME/pytest
compare: your-branch-name
base-fork: pytest-dev/pytest
base: master # if it's a bugfix
base: feature # if it's a feature

88
HOWTORELEASE.rst Normal file
View File

@@ -0,0 +1,88 @@
How to release pytest
--------------------------------------------
Note: this assumes you have already registered on pypi.
1. Bump version numbers in _pytest/__init__.py (setup.py reads it)
2. Check and finalize CHANGELOG
3. Write doc/en/announce/release-VERSION.txt and include
it in doc/en/announce/index.txt
4. Use devpi for uploading a release tarball to a staging area::
devpi use https://devpi.net/USER/dev
devpi upload --formats sdist,bdist_wheel
5. Run from multiple machines::
devpi use https://devpi.net/USER/dev
devpi test pytest==VERSION
6. Check that tests pass for relevant combinations with::
devpi list pytest
or look at failures with "devpi list -f pytest".
There will be some failed environments like e.g. the py33-trial
or py27-pexpect tox environments on Win32 platforms
which is ok (tox does not support skipping on
per-platform basis yet).
7. Regenerate the docs examples using tox, and check for regressions::
tox -e regen
git diff
8. Build the docs, you need a virtualenv with py and sphinx
installed::
cd doc/en
python plugins_index/plugins_index.py
make html
Commit any changes before tagging the release.
9. Tag the release::
git tag VERSION
git push
10. Upload the docs using doc/en/Makefile::
cd doc/en
make install # or "installall" if you have LaTeX installed for PDF
This requires ssh-login permission on pytest.org because it uses
rsync.
Note that the ``install`` target of ``doc/en/Makefile`` defines where the
rsync goes to, typically to the "latest" section of pytest.org.
If you are making a minor release (e.g. 5.4), you also need to manually
create a symlink for "latest"::
ssh pytest-dev@pytest.org
ln -s 5.4 latest
Browse to pytest.org to verify.
11. Publish to pypi::
devpi push pytest-VERSION pypi:NAME
where NAME is the name of pypi.python.org as configured in your ``~/.pypirc``
file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_.
12. Send release announcement to mailing lists:
- pytest-dev
- testing-in-python
- python-announce-list@python.org
13. **after the release** Bump the version number in ``_pytest/__init__.py``,
to the next Minor release version (i.e. if you released ``pytest-2.8.0``,
set it to ``pytest-2.9.0.dev1``).

View File

@@ -1,10 +1,22 @@
improve / add to dependency/test resource injection
recorder = monkeypatch.function(".......")
-------------------------------------------------------------
tags: wish feature docs
tags: nice feature
write up better examples showing the connection between
the two.
Like monkeypatch.replace but sets a mock-like call recorder:
recorder = monkeypatch.function("os.path.abspath")
recorder.set_return("/hello")
os.path.abspath("hello")
call, = recorder.calls
assert call.args.path == "hello"
assert call.returned == "/hello"
...
Unlike mock, "args.path" acts on the parsed auto-spec'ed ``os.path.abspath``
so it's independent from if the client side called "os.path.abspath(path=...)"
or "os.path.abspath('positional')".
refine parametrize API
-------------------------------------------------------------
@@ -37,7 +49,7 @@ probably makes sense in order to keep the declarative nature. This mirrors
the marker-mechanism with respect to a test module but puts it to a directory
scale.
When doing larger scoped parametrization it probably becomes neccessary
When doing larger scoped parametrization it probably becomes necessary
to allow parametrization to be ignored if the according parameter is not
used (currently any parametrized argument that is not present in a function will cause a ValueError). Example:
@@ -65,16 +77,7 @@ this would run the test_hello() function three times with three
different values for self.db. This could also work with unittest/nose
style tests, i.e. it leverages existing test suites without needing
to rewrite them. Together with the previously mentioned setup_test()
maybe the setupfunc could be ommitted?
checks / deprecations for next release
---------------------------------------------------------------
tags: bug 2.4 core xdist
* check oejskit plugin compatibility
* move pytest_nose out of pylib because it implicitely extends
the protocol now - setup/teardown is called at module level.
consider making calling of setup/teardown configurable
maybe the setupfunc could be omitted?
optimizations
---------------------------------------------------------------
@@ -94,20 +97,6 @@ appropriately to avoid this issue. Moreover/Alternatively, we could
record which implementations of a hook succeeded and only call their
teardown.
consider and document __init__ file usage in test directories
---------------------------------------------------------------
tags: bug core
Currently, a test module is imported with its fully qualified
package path, determined by checking __init__ files upwards.
This has the side effect that a source package at the root
of the test dir could be imported as well. This is somewhat
convenient but complicates the picture for running tests against
different versions of a package. Also, implicit sys.path
manipulations are problematic per-se. Maybe factorting out
a pytest_addsyspath hook which can be disabled from the command line
makes sense. In any case documentation/recommendations for
certain scenarios makes sense.
relax requirement to have tests/testing contain an __init__
----------------------------------------------------------------
@@ -124,8 +113,8 @@ customize test function collection
-------------------------------------------------------
tags: feature
- introduce py.test.mark.nocollect for not considering a function for
test collection at all. maybe also introduce a py.test.mark.test to
- introduce pytest.mark.nocollect for not considering a function for
test collection at all. maybe also introduce a pytest.mark.test to
explicitely mark a function to become a tested one. Lookup JUnit ways
of tagging tests.
@@ -137,18 +126,18 @@ in addition to the imperative pytest.importorskip also introduce
a pytest.mark.importorskip so that the test count is more correct.
introduce py.test.mark.platform
introduce pytest.mark.platform
-------------------------------------------------------
tags: feature
Introduce nice-to-spell platform-skipping, examples:
@py.test.mark.platform("python3")
@py.test.mark.platform("not python3")
@py.test.mark.platform("win32 and not python3")
@py.test.mark.platform("darwin")
@py.test.mark.platform("not (jython and win32)")
@py.test.mark.platform("not (jython and win32)", xfail=True)
@pytest.mark.platform("python3")
@pytest.mark.platform("not python3")
@pytest.mark.platform("win32 and not python3")
@pytest.mark.platform("darwin")
@pytest.mark.platform("not (jython and win32)")
@pytest.mark.platform("not (jython and win32)", xfail=True)
etc. Idea is to allow Python expressions which can operate
on common spellings for operating systems and python
@@ -183,8 +172,8 @@ tags: feature
allow to name conftest.py files (in sub directories) that should
be imported early, as to include command line options.
improve central py.test ini file
----------------------------------
improve central pytest ini file
-------------------------------
tags: feature
introduce more declarative configuration options:
@@ -198,7 +187,7 @@ new documentation
----------------------------------
tags: feature
- logo py.test
- logo pytest
- examples for unittest or functional testing
- resource management for functional testing
- patterns: page object
@@ -207,47 +196,25 @@ have imported module mismatch honour relative paths
--------------------------------------------------------
tags: bug
With 1.1.1 py.test fails at least on windows if an import
With 1.1.1 pytest fails at least on windows if an import
is relative and compared against an absolute conftest.py
path. Normalize.
consider globals: py.test.ensuretemp and config
consider globals: pytest.ensuretemp and config
--------------------------------------------------------------
tags: experimental-wish
consider deprecating py.test.ensuretemp and py.test.config
to further reduce py.test globality. Also consider
having py.test.config and ensuretemp coming from
consider deprecating pytest.ensuretemp and pytest.config
to further reduce pytest globality. Also consider
having pytest.config and ensuretemp coming from
a plugin rather than being there from the start.
consider allowing funcargs for setup methods
--------------------------------------------------------------
tags: experimental-wish
Users have expressed the wish to have funcargs available to setup
functions. Experiment with allowing funcargs there - it might
also help to make the py.test.ensuretemp and config deprecation.
For filling funcargs for setup methods, we could call funcarg
factories with a request object that not have a cls/function
attributes. However, how to handle parametrized test functions
and funcargs?
maybe introduce a setup method like:
setup_invocation(self, request)
which has full access to the test invocation through "request"
through which you can get funcargvalues, use cached_setup etc.
Therefore, the access to funcargs would be indirect but it
could be consistently implemented. setup_invocation() would
be a "glue" function for bringing together the xUnit and funcargs
world.
consider pytest_addsyspath hook
-----------------------------------------
tags:
tags: wish
py.test could call a new pytest_addsyspath() in order to systematically
pytest could call a new pytest_addsyspath() in order to systematically
allow manipulation of sys.path and to inhibit it via --no-addsyspath
in order to more easily run against installed packages.
@@ -255,21 +222,14 @@ Alternatively it could also be done via the config object
and pytest_configure.
show plugin information in test header
deprecate global pytest.config usage
----------------------------------------------------------------
tags: feature
Now that external plugins are becoming more numerous
it would be useful to have external plugins along with
their versions displayed as a header line.
deprecate global py.test.config usage
----------------------------------------------------------------
tags: feature
py.test.ensuretemp and py.test.config are probably the last
pytest.ensuretemp and pytest.config are probably the last
objects containing global state. Often using them is not
neccessary. This is about trying to get rid of them, i.e.
necessary. This is about trying to get rid of them, i.e.
deprecating them and checking with PyPy's usages as well
as others.
@@ -338,7 +298,7 @@ tags: feature
The idea is that you can e.g. import modules in a test and afterwards
sys.modules, sys.meta_path etc would be reverted. It can go further
then just importing however, e.g. current working direcroty, file
then just importing however, e.g. current working directory, file
descriptors, ...
This would probably be done by marking::
@@ -397,7 +357,7 @@ a few use-cases come to mind:
id, call = prepare_check(check)
# bubble should only prevent exception propagation after a failure
# the whole test should still fail
# there might be need for a loer level api and taking custom markers into account
# there might be need for a lower level api and taking custom markers into account
with pytest.section(id, bubble=False):
call()

View File

@@ -1,7 +1,6 @@
include CHANGELOG
include README.rst
include setup.py
include distribute_setup.py
include tox.ini
include LICENSE
graft doc

View File

@@ -1,6 +1,27 @@
======
pytest
======
The ``py.test`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing. It provides
The ``pytest`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing.
.. image:: http://img.shields.io/pypi/v/pytest.svg
:target: https://pypi.python.org/pypi/pytest
.. image:: http://img.shields.io/coveralls/pytest-dev/pytest/master.svg
:target: https://coveralls.io/r/pytest-dev/pytest
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
:target: https://travis-ci.org/pytest-dev/pytest
.. image:: https://ci.appveyor.com/api/projects/status/mrgbjaua7t33pg6b?svg=true
:target: https://ci.appveyor.com/project/pytestbot/pytest
Documentation: http://pytest.org/latest/
Changelog: http://pytest.org/latest/changelog.html
Issues: https://github.com/pytest-dev/pytest/issues
Features
--------
- `auto-discovery
<http://pytest.org/latest/goodpractises.html#python-test-discovery>`_
@@ -8,15 +29,18 @@ scales to support complex functional testing. It provides
- detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names)
- `modular fixtures <http://pytest.org/latest/fixture.html>`_ for
managing small or parametrized long-lived test resources.
- multi-paradigm support: you can use ``py.test`` to run test suites based
- multi-paradigm support: you can use ``pytest`` to run test suites based
on `unittest <http://pytest.org/latest/unittest.html>`_ (or trial),
`nose <http://pytest.org/latest/nose.html>`_
- single-source compatibility to Python2.4 all the way up to Python3.3,
PyPy-1.9 and Jython-2.5.1.
- single-source compatibility from Python2.6 all the way up to
Python3.5, PyPy-2.3, (jython-2.5 untested)
- many `external plugins <http://pytest.org/latest/plugins.html#installing-external-plugins-searching>`_.
A simple example for a test::
A simple example for a test:
.. code-block:: python
# content of test_module.py
def test_function():
@@ -31,6 +55,12 @@ For much more info, including PDF docs, see
and report bugs at:
http://bitbucket.org/hpk42/pytest/issues/
https://github.com/pytest-dev/pytest/issues
Copyright Holger Krekel and others, 2004-2012
and checkout or fork repo at:
https://github.com/pytest-dev/pytest
Copyright Holger Krekel and others, 2004-2015
Licensed under the MIT license.

View File

@@ -1,2 +1,2 @@
#
__version__ = '2.3.5'
__version__ = '2.8.2'

104
_pytest/_argcomplete.py Normal file
View File

@@ -0,0 +1,104 @@
"""allow bash-completion for argparse with argcomplete if installed
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
to find the magic string, so _ARGCOMPLETE env. var is never set, and
this does not need special code.
argcomplete does not support python 2.5 (although the changes for that
are minor).
Function try_argcomplete(parser) should be called directly before
the call to ArgumentParser.parse_args().
The filescompleter is what you normally would use on the positional
arguments specification, in order to get "dirname/" after "dirn<TAB>"
instead of the default "dirname ":
optparser.add_argument(Config._file_or_dir, nargs='*'
).completer=filescompleter
Other, application specific, completers should go in the file
doing the add_argument calls as they need to be specified as .completer
attributes as well. (If argcomplete is not installed, the function the
attribute points to will not be used).
SPEEDUP
=======
The generic argcomplete script for bash-completion
(/etc/bash_completion.d/python-argcomplete.sh )
uses a python program to determine startup script generated by pip.
You can speed up completion somewhat by changing this script to include
# PYTHON_ARGCOMPLETE_OK
so the the python-argcomplete-check-easy-install-script does not
need to be called to find the entry point of the code and see if that is
marked with PYTHON_ARGCOMPLETE_OK
INSTALL/DEBUGGING
=================
To include this support in another application that has setup.py generated
scripts:
- add the line:
# PYTHON_ARGCOMPLETE_OK
near the top of the main python entry point
- include in the file calling parse_args():
from _argcomplete import try_argcomplete, filescompleter
, call try_argcomplete just before parse_args(), and optionally add
filescompleter to the positional arguments' add_argument()
If things do not work right away:
- switch on argcomplete debugging with (also helpful when doing custom
completers):
export _ARC_DEBUG=1
- run:
python-argcomplete-check-easy-install-script $(which appname)
echo $?
will echo 0 if the magic line has been found, 1 if not
- sometimes it helps to find early on errors using:
_ARGCOMPLETE=1 _ARC_DEBUG=1 appname
which should throw a KeyError: 'COMPLINE' (which is properly set by the
global argcomplete script).
"""
import sys
import os
from glob import glob
class FastFilesCompleter:
'Fast file completer class'
def __init__(self, directories=True):
self.directories = directories
def __call__(self, prefix, **kwargs):
"""only called on non option completions"""
if os.path.sep in prefix[1:]: #
prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
else:
prefix_dir = 0
completion = []
globbed = []
if '*' not in prefix and '?' not in prefix:
if prefix[-1] == os.path.sep: # we are on unix, otherwise no bash
globbed.extend(glob(prefix + '.*'))
prefix += '*'
globbed.extend(glob(prefix))
for x in sorted(globbed):
if os.path.isdir(x):
x += '/'
# append stripping the prefix (like bash, not like compgen)
completion.append(x[prefix_dir:])
return completion
if os.environ.get('_ARGCOMPLETE'):
# argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
if sys.version_info[:2] < (2, 6):
sys.exit(1)
try:
import argcomplete.completers
except ImportError:
sys.exit(-1)
filescompleter = FastFilesCompleter()
def try_argcomplete(parser):
argcomplete.autocomplete(parser)
else:
def try_argcomplete(parser): pass
filescompleter = None

11
_pytest/_pluggy.py Normal file
View File

@@ -0,0 +1,11 @@
"""
imports symbols from vendored "pluggy" if available, otherwise
falls back to importing "pluggy" from the default namespace.
"""
try:
from _pytest.vendored_packages.pluggy import * # noqa
from _pytest.vendored_packages.pluggy import __version__ # noqa
except ImportError:
from pluggy import * # noqa
from pluggy import __version__ # noqa

View File

@@ -3,24 +3,35 @@ support for presenting detailed information in failing assertions.
"""
import py
import sys
import pytest
from _pytest.monkeypatch import monkeypatch
from _pytest.assertion import util
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption('--assert', action="store", dest="assertmode",
group.addoption('--assert',
action="store",
dest="assertmode",
choices=("rewrite", "reinterp", "plain",),
default="rewrite", metavar="MODE",
help="""control assertion debugging tools.
'plain' performs no assertion debugging.
'reinterp' reinterprets assert statements after they failed to provide assertion expression information.
'rewrite' (the default) rewrites assert statements in test modules on import
to provide assert expression information. """)
group.addoption('--no-assert', action="store_true", default=False,
dest="noassert", help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', action="store_true", default=False,
dest="nomagic", help="DEPRECATED equivalent to --assert=plain")
default="rewrite",
metavar="MODE",
help="""control assertion debugging tools. 'plain'
performs no assertion debugging. 'reinterp'
reinterprets assert statements after they failed
to provide assertion expression information.
'rewrite' (the default) rewrites assert
statements in test modules on import to
provide assert expression information. """)
group.addoption('--no-assert',
action="store_true",
default=False,
dest="noassert",
help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', '--no-magic',
action="store_true",
default=False,
help="DEPRECATED equivalent to --assert=plain")
class AssertionState:
"""State for the assertion plugin."""
@@ -29,40 +40,42 @@ class AssertionState:
self.mode = mode
self.trace = config.trace.root.get("assertion")
def pytest_configure(config):
mode = config.getvalue("assertmode")
if config.getvalue("noassert") or config.getvalue("nomagic"):
mode = "plain"
if mode == "rewrite":
try:
import ast
import ast # noqa
except ImportError:
mode = "reinterp"
else:
# Both Jython and CPython 2.6.0 have AST bugs that make the
# assertion rewriting hook malfunction.
if (sys.platform.startswith('java') or
sys.version_info[:3] == (2, 6, 0)):
sys.version_info[:3] == (2, 6, 0)):
mode = "reinterp"
if mode != "plain":
_load_modules(mode)
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)
config._assertstate.hook = hook
config._assertstate.trace("configured with mode set to %r" % (mode,))
def undo():
hook = config._assertstate.hook
if hook is not None and hook in sys.meta_path:
sys.meta_path.remove(hook)
config.add_cleanup(undo)
def pytest_unconfigure(config):
hook = config._assertstate.hook
if hook is not None:
sys.meta_path.remove(hook)
def pytest_collection(session):
# this hook is only called when test modules are collected
@@ -72,39 +85,65 @@ def pytest_collection(session):
if hook is not None:
hook.set_session(session)
def pytest_runtest_setup(item):
"""Setup the pytest_assertrepr_compare hook
The newinterpret and rewrite modules will use util._reprcompare if
it exists to use custom reporting via the
pytest_assertrepr_compare hook. This sets up this custom
comparison for the test.
"""
def callbinrepr(op, left, right):
"""Call the pytest_assertrepr_compare hook and prepare the result
This uses the first result from the hook and then ensures the
following:
* Overly verbose explanations are dropped unles -vv was used.
* Embedded newlines are escaped to help util.format_explanation()
later.
* If the rewrite mode is used embedded %-characters are replaced
to protect later % formatting.
The result can be formatted by util.format_explanation() for
pretty printing.
"""
hook_result = item.ihook.pytest_assertrepr_compare(
config=item.config, op=op, left=left, right=right)
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)
if (sum(len(p) for p in new_expl[1:]) > 80*8
and item.config.option.verbose < 2):
show_max = 10
truncated_lines = len(new_expl) - show_max
new_expl[show_max:] = [py.builtin._totext(
'Detailed information truncated (%d more lines)'
', use "-vv" to show' % truncated_lines)]
new_expl = [line.replace("\n", "\\n") for line in new_expl]
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
# '%'s in the string. Escape them here.
res = res.replace("%", "%%")
return res
util._reprcompare = callbinrepr
def pytest_runtest_teardown(item):
util._reprcompare = None
def pytest_sessionfinish(session):
hook = session.config._assertstate.hook
if hook is not None:
hook.session = None
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:
@@ -119,8 +158,10 @@ def warn_about_missing_assertion(mode):
specifically = "failing tests may report as passing"
sys.stderr.write("WARNING: " + specifically +
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
# Expose this plugin's implementation for the pytest_assertrepr_compare hook
pytest_assertrepr_compare = util.assertrepr_compare

View File

@@ -33,6 +33,12 @@ else:
def _is_ast_stmt(node):
return isinstance(node, ast.stmt)
try:
_Starred = ast.Starred
except AttributeError:
# Python 2. Define a dummy class so isinstance() will always be False.
class _Starred(object): pass
class Failure(Exception):
"""Error found while interpreting AST."""
@@ -232,24 +238,38 @@ class DebugInterpreter(ast.NodeVisitor):
arguments = []
for arg in call.args:
arg_explanation, arg_result = self.visit(arg)
arg_name = "__exprinfo_%s" % (len(ns),)
ns[arg_name] = arg_result
arguments.append(arg_name)
arg_explanations.append(arg_explanation)
if isinstance(arg, _Starred):
arg_name = "__exprinfo_star"
ns[arg_name] = arg_result
arguments.append("*%s" % (arg_name,))
arg_explanations.append("*%s" % (arg_explanation,))
else:
arg_name = "__exprinfo_%s" % (len(ns),)
ns[arg_name] = arg_result
arguments.append(arg_name)
arg_explanations.append(arg_explanation)
for keyword in call.keywords:
arg_explanation, arg_result = self.visit(keyword.value)
arg_name = "__exprinfo_%s" % (len(ns),)
if keyword.arg:
arg_name = "__exprinfo_%s" % (len(ns),)
keyword_source = "%s=%%s" % (keyword.arg)
arguments.append(keyword_source % (arg_name,))
arg_explanations.append(keyword_source % (arg_explanation,))
else:
arg_name = "__exprinfo_kwds"
arguments.append("**%s" % (arg_name,))
arg_explanations.append("**%s" % (arg_explanation,))
ns[arg_name] = arg_result
keyword_source = "%s=%%s" % (keyword.arg)
arguments.append(keyword_source % (arg_name,))
arg_explanations.append(keyword_source % (arg_explanation,))
if call.starargs:
if getattr(call, 'starargs', None):
arg_explanation, arg_result = self.visit(call.starargs)
arg_name = "__exprinfo_star"
ns[arg_name] = arg_result
arguments.append("*%s" % (arg_name,))
arg_explanations.append("*%s" % (arg_explanation,))
if call.kwargs:
if getattr(call, 'kwargs', None):
arg_explanation, arg_result = self.visit(call.kwargs)
arg_name = "__exprinfo_kwds"
ns[arg_name] = arg_result
@@ -286,7 +306,19 @@ class DebugInterpreter(ast.NodeVisitor):
source = "__exprinfo_expr.%s" % (attr.attr,)
co = self._compile(source)
try:
result = self.frame.eval(co, __exprinfo_expr=source_result)
try:
result = self.frame.eval(co, __exprinfo_expr=source_result)
except AttributeError:
# Maybe the attribute name needs to be mangled?
if not attr.attr.startswith("__") or attr.attr.endswith("__"):
raise
source = "getattr(__exprinfo_expr.__class__, '__name__', '')"
co = self._compile(source)
class_name = self.frame.eval(co, __exprinfo_expr=source_result)
mangled_attr = "_" + class_name + attr.attr
source = "__exprinfo_expr.%s" % (mangled_attr,)
co = self._compile(source)
result = self.frame.eval(co, __exprinfo_expr=source_result)
except Exception:
raise Failure(explanation)
explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),

View File

@@ -1,3 +1,5 @@
import traceback
import types
import py
import sys, inspect
from compiler import parse, ast, pycodegen
@@ -55,7 +57,7 @@ class View(object):
def __getattr__(self, attr):
# attributes not found in the normal hierarchy rooted on View
# are looked up in the object's real class
return getattr(self.__obj__, attr)
return getattr(object.__getattribute__(self, '__obj__'), attr)
def __viewkey__(self):
return self.__obj__.__class__
@@ -355,7 +357,18 @@ class Getattr(Interpretable):
expr.eval(frame)
source = '__exprinfo_expr.%s' % self.attrname
try:
self.result = frame.eval(source, __exprinfo_expr=expr.result)
try:
self.result = frame.eval(source, __exprinfo_expr=expr.result)
except AttributeError:
# Maybe the attribute name needs to be mangled?
if (not self.attrname.startswith("__") or
self.attrname.endswith("__")):
raise
source = "getattr(__exprinfo_expr.__class__, '__name__', '')"
class_name = frame.eval(source, __exprinfo_expr=expr.result)
mangled_attr = "_" + class_name + self.attrname
source = "__exprinfo_expr.%s" % (mangled_attr,)
self.result = frame.eval(source, __exprinfo_expr=expr.result)
except passthroughex:
raise
except:
@@ -466,7 +479,7 @@ def check(s, frame=None):
def interpret(source, frame, should_fail=False):
module = Interpretable(parse(source, 'exec').node)
#print "got module", module
if isinstance(frame, py.std.types.FrameType):
if isinstance(frame, types.FrameType):
frame = py.code.Frame(frame)
try:
module.run(frame)
@@ -476,7 +489,6 @@ def interpret(source, frame, should_fail=False):
except passthroughex:
raise
except:
import traceback
traceback.print_exc()
if should_fail:
return ("(assertion failed, but when it was re-run for "

View File

@@ -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:
@@ -37,10 +45,8 @@ class AssertionError(BuiltinAssertionError):
if sys.version_info > (3, 0):
AssertionError.__module__ = "builtins"
reinterpret_old = "old reinterpretation not available for py3"
else:
from _pytest.assertion.oldinterpret import interpret as reinterpret_old
if sys.version_info >= (2, 6) or (sys.platform.startswith("java")):
if sys.version_info >= (2, 6) or sys.platform.startswith("java"):
from _pytest.assertion.newinterpret import interpret as reinterpret
else:
reinterpret = reinterpret_old
from _pytest.assertion.oldinterpret import interpret as reinterpret

View File

@@ -15,13 +15,7 @@ import py
from _pytest.assertion import util
# Windows gives ENOENT in places *nix gives ENOTDIR.
if sys.platform.startswith("win"):
PATH_COMPONENT_NOT_DIR = errno.ENOENT
else:
PATH_COMPONENT_NOT_DIR = errno.ENOTDIR
# py.test caches rewritten pycs in __pycache__.
# pytest caches rewritten pycs in __pycache__.
if hasattr(imp, "get_tag"):
PYTEST_TAG = imp.get_tag() + "-PYTEST"
else:
@@ -41,12 +35,19 @@ PYC_TAIL = "." + PYTEST_TAG + PYC_EXT
REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2)
ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3
if sys.version_info >= (3,5):
ast_Call = ast.Call
else:
ast_Call = lambda a,b,c: ast.Call(a, b, c, None, None)
class AssertionRewritingHook(object):
"""PEP302 Import hook which rewrites asserts."""
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")
@@ -61,8 +62,12 @@ class AssertionRewritingHook(object):
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)
@@ -103,7 +108,7 @@ class AssertionRewritingHook(object):
# the most magical part of the process: load the source, rewrite the
# asserts, and load the rewritten source. We also cache the rewritten
# module code in a special pyc. We must be aware of the possibility of
# concurrent py.test processes rewriting and loading pycs. To avoid
# concurrent pytest processes rewriting and loading pycs. To avoid
# tricky race conditions, we maintain the following invariant: The
# cached pyc is always a complete, valid pyc. Operations on it must be
# atomic. POSIX's atomic rename comes in handy.
@@ -119,11 +124,11 @@ class AssertionRewritingHook(object):
# common case) or it's blocked by a non-dir node. In the
# latter case, we'll ignore it in _write_pyc.
pass
elif e == PATH_COMPONENT_NOT_DIR:
elif e in [errno.ENOENT, errno.ENOTDIR]:
# One of the path components was not a directory, likely
# because we're in a zip file.
write = False
elif e == errno.EACCES:
elif e in [errno.EACCES, errno.EROFS]:
state.trace("read only directory: %r" % fn_pypath.dirname)
write = False
else:
@@ -132,21 +137,27 @@ class AssertionRewritingHook(object):
pyc = os.path.join(cache_dir, cache_name)
# Notice that even if we're in a read-only directory, I'm going
# to check for a cached pyc. This may not be optimal...
co = _read_pyc(fn_pypath, pyc)
co = _read_pyc(fn_pypath, pyc, state.trace)
if co is None:
state.trace("rewriting %r" % (fn,))
co = _rewrite_test(state, fn_pypath)
source_stat, co = _rewrite_test(state, fn_pypath)
if co is None:
# Probably a SyntaxError in the test.
return None
if write:
_make_rewritten_pyc(state, fn_pypath, pyc, co)
_make_rewritten_pyc(state, source_stat, pyc, co)
else:
state.trace("found cached rewritten pyc for %r" % (fn,))
self.modules[name] = co, pyc
return self
def load_module(self, name):
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
# the reload() builtin will not work correctly.)
if name in sys.modules:
return sys.modules[name]
co, pyc = self.modules.pop(name)
# I wish I could just call imp.load_compiled here, but __file__ has to
# be set properly. In Python 3.2+, this all would be handled correctly
@@ -156,31 +167,69 @@ class AssertionRewritingHook(object):
mod.__file__ = co.co_filename
# Normally, this attribute is 3.2+.
mod.__cached__ = pyc
mod.__loader__ = self
py.builtin.exec_(co, mod.__dict__)
except:
del sys.modules[name]
raise
return sys.modules[name]
def _write_pyc(co, source_path, pyc):
def is_package(self, name):
try:
fd, fn, desc = imp.find_module(name)
except ImportError:
return False
if fd is not None:
fd.close()
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 get_data(self, pathname):
"""Optional PEP302 get_data API.
"""
with open(pathname, 'rb') as f:
return f.read()
def _write_pyc(state, co, source_stat, pyc):
# Technically, we don't have to have the same pyc format as
# (C)Python, since these "pycs" should never be seen by builtin
# import. However, there's little reason deviate, and I hope
# sometime to be able to use imp.load_compiled to load them. (See
# the comment in load_module above.)
mtime = int(source_path.mtime())
try:
fp = open(pyc, "wb")
except IOError:
err = sys.exc_info()[1].errno
if err == PATH_COMPONENT_NOT_DIR:
# This happens when we get a EEXIST in find_module creating the
# __pycache__ directory and __pycache__ is by some non-dir node.
return False
raise
state.trace("error writing pyc file at %s: errno=%s" %(pyc, err))
# we ignore any failure to write the cache file
# there are many reasons, permission-denied, __pycache__ being a
# file etc.
return False
try:
fp.write(imp.get_magic())
fp.write(struct.pack("<l", mtime))
mtime = int(source_stat.mtime)
size = source_stat.size & 0xFFFFFFFF
fp.write(struct.pack("<ll", mtime, size))
marshal.dump(co, fp)
finally:
fp.close()
@@ -189,15 +238,16 @@ def _write_pyc(co, source_path, pyc):
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):
"""Try to read and rewrite *fn* and return the code object."""
try:
stat = fn.stat()
source = fn.read("rb")
except EnvironmentError:
return None
return None, None
if ASCII_IS_DEFAULT_ENCODING:
# ASCII is the default encoding in Python 2. Without a coding
# declaration, Python 2 will complain about any bytes in the file
@@ -213,17 +263,18 @@ def _rewrite_test(state, fn):
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
# encodings imported us again, so don't rewrite.
return None, None
state._indecode = True
try:
try:
source.decode("ascii")
except UnicodeDecodeError:
# Let it fail in real import.
return None
return None, None
finally:
del state._indecode
# On Python versions which are not 2.7 and less than or equal to 3.1, the
@@ -235,7 +286,7 @@ def _rewrite_test(state, fn):
except SyntaxError:
# Let this pop up again in the real import.
state.trace("failed to parse: %r" % (fn,))
return None
return None, None
rewrite_asserts(tree)
try:
co = compile(tree, fn.strpath, "exec")
@@ -243,24 +294,24 @@ def _rewrite_test(state, fn):
# It's possible that this error is from some bug in the
# assertion rewriting, but I don't know of a fast way to tell.
state.trace("failed to compile: %r" % (fn,))
return None
return co
return None, None
return stat, co
def _make_rewritten_pyc(state, fn, pyc, co):
def _make_rewritten_pyc(state, source_stat, pyc, co):
"""Try to dump rewritten code to *pyc*."""
if sys.platform.startswith("win"):
# Windows grants exclusive access to open files and doesn't have atomic
# rename, so just write into the final file.
_write_pyc(co, fn, pyc)
_write_pyc(state, co, source_stat, pyc)
else:
# When not on windows, assume rename is atomic. Dump the code object
# into a file specific to this process and atomically replace it.
proc_pyc = pyc + "." + str(os.getpid())
if _write_pyc(co, fn, proc_pyc):
if _write_pyc(state, co, source_stat, proc_pyc):
os.rename(proc_pyc, pyc)
def _read_pyc(source, pyc):
"""Possibly read a py.test pyc containing rewritten code.
def _read_pyc(source, pyc, trace=lambda x: None):
"""Possibly read a pytest pyc containing rewritten code.
Return rewritten code if successful or None if not.
"""
@@ -268,23 +319,28 @@ def _read_pyc(source, pyc):
fp = open(pyc, "rb")
except IOError:
return None
try:
with fp:
try:
mtime = int(source.mtime())
data = fp.read(8)
except EnvironmentError:
size = source.size()
data = fp.read(12)
except EnvironmentError as e:
trace('_read_pyc(%s): EnvironmentError %s' % (source, e))
return None
# Check for invalid or out of date pyc file.
if (len(data) != 8 or data[:4] != imp.get_magic() or
struct.unpack("<l", data[4:])[0] != mtime):
if (len(data) != 12 or data[:4] != imp.get_magic() or
struct.unpack("<ll", data[4:]) != (mtime, size)):
trace('_read_pyc(%s): invalid or out of date pyc' % source)
return None
try:
co = marshal.load(fp)
except Exception as e:
trace('_read_pyc(%s): marshal.load error %s' % (source, e))
return None
co = marshal.load(fp)
if not isinstance(co, types.CodeType):
# That's interesting....
trace('_read_pyc(%s): not a code object' % source)
return None
return co
finally:
fp.close()
def rewrite_asserts(mod):
@@ -292,14 +348,64 @@ def rewrite_asserts(mod):
AssertionRewriter().run(mod)
_saferepr = py.io.saferepr
from _pytest.assertion.util import format_explanation as _format_explanation
def _saferepr(obj):
"""Get a safe repr of an object for assertion error messages.
The assertion formatting (util.format_explanation()) requires
newlines to be escaped since they are a special character for it.
Normally assertion.util.format_explanation() does this but for a
custom repr it is possible to contain one of the special escape
sequences, especially '\n{' and '\n}' are likely to be present in
JSON reprs.
"""
repr = py.io.saferepr(obj)
if py.builtin._istext(repr):
t = py.builtin.text
else:
t = py.builtin.bytes
return repr.replace(t("\n"), t("\\n"))
from _pytest.assertion.util import format_explanation as _format_explanation # noqa
def _format_assertmsg(obj):
"""Format the custom assertion message given.
For strings this simply replaces newlines with '\n~' so that
util.format_explanation() will preserve them instead of escaping
newlines. For other objects py.io.saferepr() is used first.
"""
# reprlib appears to have a bug which means that if a string
# contains a newline it gets escaped, however if an object has a
# .__repr__() which contains newlines it does not get escaped.
# However in either case we want to preserve the newline.
if py.builtin._istext(obj) or py.builtin._isbytes(obj):
s = obj
is_repr = False
else:
s = py.io.saferepr(obj)
is_repr = True
if py.builtin._istext(s):
t = py.builtin.text
else:
t = py.builtin.bytes
s = s.replace(t("\n"), t("\n~")).replace(t("%"), t("%%"))
if is_repr:
s = s.replace(t("\\n"), t("\n~"))
return s
def _should_repr_global_name(obj):
return not hasattr(obj, "__name__") and not py.builtin.callable(obj)
def _format_boolop(explanations, is_or):
return "(" + (is_or and " or " or " and ").join(explanations) + ")"
explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")"
if py.builtin._istext(explanation):
t = py.builtin.text
else:
t = py.builtin.bytes
return explanation.replace(t('%'), t('%%'))
def _call_reprcompare(ops, results, expls, each_obj):
for i, res, expl in zip(range(len(ops)), results, expls):
@@ -348,6 +454,13 @@ binop_map = {
ast.NotIn: "not in"
}
# Python 3.4+ compatibility
if hasattr(ast, "NameConstant"):
_NameConstant = ast.NameConstant
else:
def _NameConstant(c):
return ast.Name(str(c), ast.Load())
def set_location(node, lineno, col_offset):
"""Set node location information recursively."""
@@ -363,6 +476,56 @@ def set_location(node, lineno, col_offset):
class AssertionRewriter(ast.NodeVisitor):
"""Assertion rewriting implementation.
The main entrypoint is to call .run() with an ast.Module instance,
this will then find all the assert statements and re-write them to
provide intermediate values and a detailed assertion error. See
http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html
for an overview of how this works.
The entry point here is .run() which will iterate over all the
statements in an ast.Module and for each ast.Assert statement it
finds call .visit() with it. Then .visit_Assert() takes over and
is responsible for creating new ast statements to replace the
original assert statement: it re-writes the test of an assertion
to provide intermediate values and replace it with an if statement
which raises an assertion error with a detailed explanation in
case the expression is false.
For this .visit_Assert() uses the visitor pattern to visit all the
AST nodes of the ast.Assert.test field, each visit call returning
an AST node and the corresponding explanation string. During this
state is kept in several instance attributes:
:statements: All the AST statements which will replace the assert
statement.
:variables: This is populated by .variable() with each variable
used by the statements so that they can all be set to None at
the end of the statements.
:variable_counter: Counter to create new unique variables needed
by statements. Variables are created using .variable() and
have the form of "@py_assert0".
:on_failure: The AST statements which will be executed if the
assertion test fails. This is the code which will construct
the failure message and raises the AssertionError.
:explanation_specifiers: A dict filled by .explanation_param()
with %-formatting placeholders and their corresponding
expressions to use in the building of an assertion message.
This is used by .pop_format_context() to build a message.
:stack: A stack of the explanation_specifiers dicts maintained by
.push_format_context() and .pop_format_context() which allows
to build another %-formatted string while already building one.
This state is reset on every new assert statement visited and used
by the other visitors.
"""
def run(self, mod):
"""Find all assert statements in *mod* and rewrite them."""
@@ -436,7 +599,7 @@ class AssertionRewriter(ast.NodeVisitor):
"""Call a helper in this module."""
py_name = ast.Name("@pytest_ar", ast.Load())
attr = ast.Attribute(py_name, "_" + name, ast.Load())
return ast.Call(attr, list(args), [], None, None)
return ast_Call(attr, list(args), [])
def builtin(self, name):
"""Return the builtin called *name*."""
@@ -444,15 +607,41 @@ class AssertionRewriter(ast.NodeVisitor):
return ast.Attribute(builtin_name, name, ast.Load())
def explanation_param(self, expr):
"""Return a new named %-formatting placeholder for expr.
This creates a %-formatting placeholder for expr in the
current formatting context, e.g. ``%(py0)s``. The placeholder
and expr are placed in the current format context so that it
can be used on the next call to .pop_format_context().
"""
specifier = "py" + str(next(self.variable_counter))
self.explanation_specifiers[specifier] = expr
return "%(" + specifier + ")s"
def push_format_context(self):
"""Create a new formatting context.
The format context is used for when an explanation wants to
have a variable value formatted in the assertion message. In
this case the value required can be added using
.explanation_param(). Finally .pop_format_context() is used
to format a string of %-formatted values as added by
.explanation_param().
"""
self.explanation_specifiers = {}
self.stack.append(self.explanation_specifiers)
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
@@ -470,11 +659,15 @@ class AssertionRewriter(ast.NodeVisitor):
return res, self.explanation_param(self.display(res))
def visit_Assert(self, assert_):
if assert_.msg:
# There's already a message. Don't mess with it.
return [assert_]
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
self.statements = []
self.cond_chain = ()
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
@@ -486,12 +679,17 @@ class AssertionRewriter(ast.NodeVisitor):
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
explanation = "assert " + explanation
template = ast.Str(explanation)
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast.Call(err_name, [fmt], [], None, None)
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
@@ -501,7 +699,7 @@ class AssertionRewriter(ast.NodeVisitor):
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, ast.Name("None", ast.Load()))
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
@@ -511,7 +709,7 @@ class AssertionRewriter(ast.NodeVisitor):
def visit_Name(self, name):
# Display the repr of the name if it's a local variable or
# _should_repr_global_name() thinks it's acceptable.
locs = ast.Call(self.builtin("locals"), [], [], None, None)
locs = ast_Call(self.builtin("locals"), [], [])
inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs])
dorepr = self.helper("should_repr_global_name", name)
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
@@ -531,13 +729,14 @@ class AssertionRewriter(ast.NodeVisitor):
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)
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
expl_format = self.pop_format_context(ast.Str(expl))
call = ast.Call(app, [expl_format], [], None, None)
call = ast_Call(app, [expl_format], [])
self.on_failure.append(ast.Expr(call))
if i < levels:
cond = res
@@ -566,7 +765,42 @@ class AssertionRewriter(ast.NodeVisitor):
res = self.assign(ast.BinOp(left_expr, binop.op, right_expr))
return res, explanation
def visit_Call(self, call):
def visit_Call_35(self, call):
"""
visit `ast.Call` nodes on Python3.5 and after
"""
new_func, func_expl = self.visit(call.func)
arg_expls = []
new_args = []
new_kwargs = []
for arg in call.args:
res, expl = self.visit(arg)
arg_expls.append(expl)
new_args.append(res)
for keyword in call.keywords:
res, expl = self.visit(keyword.value)
new_kwargs.append(ast.keyword(keyword.arg, res))
if keyword.arg:
arg_expls.append(keyword.arg + "=" + expl)
else: ## **args have `arg` keywords with an .arg of None
arg_expls.append("**" + expl)
expl = "%s(%s)" % (func_expl, ', '.join(arg_expls))
new_call = ast.Call(new_func, new_args, new_kwargs)
res = self.assign(new_call)
res_expl = self.explanation_param(self.display(res))
outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl)
return res, outer_expl
def visit_Starred(self, starred):
# From Python 3.5, a Starred node can appear in a function call
res, expl = self.visit(starred.value)
return starred, '*' + expl
def visit_Call_legacy(self, call):
"""
visit `ast.Call nodes on 3.4 and below`
"""
new_func, func_expl = self.visit(call.func)
arg_expls = []
new_args = []
@@ -594,6 +828,15 @@ class AssertionRewriter(ast.NodeVisitor):
outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl)
return res, outer_expl
# ast.Call signature changed on 3.5,
# conditionally change which methods is named
# visit_Call depending on Python version
if sys.version_info >= (3, 5):
visit_Call = visit_Call_35
else:
visit_Call = visit_Call_legacy
def visit_Attribute(self, attr):
if not isinstance(attr.ctx, ast.Load):
return self.generic_visit(attr)
@@ -624,7 +867,7 @@ class AssertionRewriter(ast.NodeVisitor):
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()),

View File

@@ -1,8 +1,14 @@
"""Utilities for assertion debugging"""
import pprint
import py
try:
from collections import Sequence
except ImportError:
Sequence = list
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
@@ -21,20 +27,33 @@ def format_explanation(explanation):
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)
if where == -1:
break
level = 0
prev_c = explanation[start]
for i, c in enumerate(explanation[start:]):
if c == "{":
if prev_c + c == "\n{":
level += 1
elif c == "}":
elif prev_c + c == "\n}":
level -= 1
if not level:
break
prev_c = c
else:
raise AssertionError("unbalanced braces: %r" % (explanation,))
end = start + i
@@ -43,38 +62,59 @@ def format_explanation(explanation):
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('~'):
if l and l[0] in ['{', '}', '~', '>']:
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()
stackcnt.pop()
result[stack[-1]] += line[1:]
else:
assert line.startswith('~')
result.append(' '*len(stack) + line[1:])
assert line[0] in ['~', '>']
stack[-1] += 1
indent = len(stack) if line.startswith('~') else len(stack) - 1
result.append(u(' ')*indent + line[1:])
assert len(stack) == 1
return '\n'.join(result)
return result
# Provide basestring in python3
@@ -89,35 +129,57 @@ def assertrepr_compare(config, op, left, right):
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)
issequence = lambda x: isinstance(x, (list, tuple))
# the re-encoding is needed for python2 repr
# with non-ascii characters (see issue 877)
def ecu(s):
try:
return u(s, 'utf-8', 'replace')
except TypeError:
return s
summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
issequence = lambda x: (isinstance(x, (list, tuple, Sequence))
and not isinstance(x, basestring))
istext = lambda x: isinstance(x, basestring)
isdict = lambda x: isinstance(x, dict)
isset = lambda x: isinstance(x, (set, frozenset))
def isiterable(obj):
try:
iter(obj)
return not istext(obj)
except TypeError:
return False
verbose = config.getoption('verbose')
explanation = None
try:
if op == '==':
if istext(left) and istext(right):
explanation = _diff_text(left, right, verbose)
elif issequence(left) and issequence(right):
explanation = _compare_eq_sequence(left, right, verbose)
elif isset(left) and isset(right):
explanation = _compare_eq_set(left, right, verbose)
elif isdict(left) and isdict(right):
explanation = _compare_eq_dict(left, right, verbose)
else:
if issequence(left) and issequence(right):
explanation = _compare_eq_sequence(left, right, verbose)
elif isset(left) and isset(right):
explanation = _compare_eq_set(left, right, verbose)
elif isdict(left) and isdict(right):
explanation = _compare_eq_dict(left, right, verbose)
if isiterable(left) and isiterable(right):
expl = _compare_eq_iterable(left, right, verbose)
if explanation is not None:
explanation.extend(expl)
else:
explanation = expl
elif op == 'not in':
if istext(left) and istext(right):
explanation = _notin_text(left, right, verbose)
except py.builtin._sysex:
raise
except:
excinfo = py.code.ExceptionInfo()
except Exception:
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(py.code.ExceptionInfo())]
if not explanation:
return None
@@ -126,12 +188,19 @@ def assertrepr_compare(config, op, left, right):
def _diff_text(left, right, verbose=False):
"""Return the explanation for the diff between text
"""Return the explanation for the diff between text or bytes
Unless --verbose is used this will skip leading and trailing
characters which are identical to keep the diff minimal.
If the input are bytes they will be safely converted to text.
"""
from difflib import ndiff
explanation = []
if isinstance(left, py.builtin.bytes):
left = u(repr(left)[1:-1]).replace(r'\n', '\n')
if isinstance(right, py.builtin.bytes):
right = u(repr(right)[1:-1]).replace(r'\n', '\n')
if not verbose:
i = 0 # just in case left or right has zero length
for i in range(min(len(left), len(right))):
@@ -139,8 +208,8 @@ def _diff_text(left, right, verbose=False):
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):
@@ -149,13 +218,34 @@ def _diff_text(left, right, verbose=False):
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')
for line in py.std.difflib.ndiff(left.splitlines(),
right.splitlines())]
for line in ndiff(left.splitlines(),
right.splitlines())]
return explanation
def _compare_eq_iterable(left, right, verbose=False):
if not verbose:
return [u('Use -v to get the full diff')]
# dynamic import to speedup pytest
import difflib
try:
left_formatting = pprint.pformat(left).splitlines()
right_formatting = pprint.pformat(right).splitlines()
explanation = [u('Full diff:')]
except Exception:
# hack: PrettyPrinter.pformat() in python 2 fails when formatting items that can't be sorted(), ie, calling
# sorted() on a list would raise. See issue #718.
# As a workaround, the full diff is generated by using the repr() string of each item of each container.
left_formatting = sorted(repr(x) for x in left)
right_formatting = sorted(repr(x) for x in right)
explanation = [u('Full diff (fallback to calling repr on each item):')]
explanation.extend(line.strip() for line in difflib.ndiff(left_formatting, right_formatting))
return explanation
@@ -163,19 +253,18 @@ def _compare_eq_sequence(left, right, verbose=False):
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))
return explanation # + _diff_text(pprint.pformat(left),
# pprint.pformat(right))
def _compare_eq_set(left, right, verbose=False):
@@ -183,11 +272,11 @@ def _compare_eq_set(left, right, verbose=False):
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
@@ -198,26 +287,26 @@ def _compare_eq_dict(left, right, verbose=False):
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 += ['Hiding %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 += py.std.pprint.pformat(same).splitlines()
explanation += [u('Common items:')]
explanation += 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.extend(py.std.pprint.pformat(
explanation.append(u('Left contains more items:'))
explanation.extend(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.extend(py.std.pprint.pformat(
explanation.append(u('Right contains more items:'))
explanation.extend(pprint.pformat(
dict((k, right[k]) for k in extra_right)).splitlines())
return explanation
@@ -228,14 +317,14 @@ def _notin_text(term, text, verbose=False):
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

243
_pytest/cacheprovider.py Executable file
View File

@@ -0,0 +1,243 @@
"""
merged implementation of the cache provider
the name cache was not choosen to ensure pluggy automatically
ignores the external pytest-cache
"""
import py
import pytest
import json
from os.path import sep as _sep, altsep as _altsep
class Cache(object):
def __init__(self, config):
self.config = config
self._cachedir = config.rootdir.join(".cache")
self.trace = config.trace.root.get("cache")
if config.getvalue("cacheclear"):
self.trace("clearing cachedir")
if self._cachedir.check():
self._cachedir.remove()
self._cachedir.mkdir()
def makedir(self, name):
""" return a directory path object with the given name. If the
directory does not yet exist, it will be created. You can use it
to manage files likes e. g. store/retrieve database
dumps across test sessions.
:param name: must be a string not containing a ``/`` separator.
Make sure the name contains your plugin or application
identifiers to prevent clashes with other cache users.
"""
if _sep in name or _altsep is not None and _altsep in name:
raise ValueError("name is not allowed to contain path separators")
return self._cachedir.ensure_dir("d", name)
def _getvaluepath(self, key):
return self._cachedir.join('v', *key.split('/'))
def get(self, key, default):
""" return cached value for the given key. If no value
was yet cached or the value cannot be read, the specified
default is returned.
:param key: must be a ``/`` separated value. Usually the first
name is the name of your plugin or your application.
:param default: must be provided in case of a cache-miss or
invalid cache values.
"""
path = self._getvaluepath(key)
if path.check():
try:
with path.open("r") as f:
return json.load(f)
except ValueError:
self.trace("cache-invalid at %s" % (path,))
return default
def set(self, key, value):
""" save value for the given key.
:param key: must be a ``/`` separated value. Usually the first
name is the name of your plugin or your application.
:param value: must be of any combination of basic
python types, including nested types
like e. g. lists of dictionaries.
"""
path = self._getvaluepath(key)
try:
path.dirpath().ensure_dir()
except (py.error.EEXIST, py.error.EACCES):
self.config.warn(
code='I9', message='could not create cache path %s' % (path,)
)
return
try:
f = path.open('w')
except py.error.ENOTDIR:
self.config.warn(
code='I9', message='cache could not write path %s' % (path,))
else:
with f:
self.trace("cache-write %s: %r" % (key, value,))
json.dump(value, f, indent=2, sort_keys=True)
class LFPlugin:
""" Plugin which implements the --lf (run last-failing) option """
def __init__(self, config):
self.config = config
active_keys = 'lf', 'failedfirst'
self.active = any(config.getvalue(key) for key in active_keys)
if self.active:
self.lastfailed = config.cache.get("cache/lastfailed", {})
else:
self.lastfailed = {}
def pytest_report_header(self):
if self.active:
if not self.lastfailed:
mode = "run all (no recorded failures)"
else:
mode = "rerun last %d failures%s" % (
len(self.lastfailed),
" first" if self.config.getvalue("failedfirst") else "")
return "run-last-failure: %s" % mode
def pytest_runtest_logreport(self, report):
if report.failed and "xfail" not in report.keywords:
self.lastfailed[report.nodeid] = True
elif not report.failed:
if report.when == "call":
self.lastfailed.pop(report.nodeid, None)
def pytest_collectreport(self, report):
passed = report.outcome in ('passed', 'skipped')
if passed:
if report.nodeid in self.lastfailed:
self.lastfailed.pop(report.nodeid)
self.lastfailed.update(
(item.nodeid, True)
for item in report.result)
else:
self.lastfailed[report.nodeid] = True
def pytest_collection_modifyitems(self, session, config, items):
if self.active and self.lastfailed:
previously_failed = []
previously_passed = []
for item in items:
if item.nodeid in self.lastfailed:
previously_failed.append(item)
else:
previously_passed.append(item)
if not previously_failed and previously_passed:
# running a subset of all tests with recorded failures outside
# of the set of tests currently executing
pass
elif self.config.getvalue("failedfirst"):
items[:] = previously_failed + previously_passed
else:
items[:] = previously_failed
config.hook.pytest_deselected(items=previously_passed)
def pytest_sessionfinish(self, session):
config = self.config
if config.getvalue("cacheshow") or hasattr(config, "slaveinput"):
return
config.cache.set("cache/lastfailed", self.lastfailed)
def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption(
'--lf', action='store_true', dest="lf",
help="rerun only the tests that failed "
"at the last run (or all if none failed)")
group.addoption(
'--ff', action='store_true', dest="failedfirst",
help="run all tests but run the last failures first. "
"This may re-order tests and thus lead to "
"repeated fixture setup/teardown")
group.addoption(
'--cache-show', action='store_true', dest="cacheshow",
help="show cache contents, don't perform collection or tests")
group.addoption(
'--cache-clear', action='store_true', dest="cacheclear",
help="remove all cache contents at start of test run.")
def pytest_cmdline_main(config):
if config.option.cacheshow:
from _pytest.main import wrap_session
return wrap_session(config, cacheshow)
@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
config.cache = Cache(config)
config.pluginmanager.register(LFPlugin(config), "lfplugin")
@pytest.fixture
def cache(request):
"""
Return a cache object that can persist state between testing sessions.
cache.get(key, default)
cache.set(key, value)
Keys must be a ``/`` separated value, where the first part is usually the
name of your plugin or application to avoid clashes with other cache users.
Values can be any object handled by the json stdlib module.
"""
return request.config.cache
def pytest_report_header(config):
if config.option.verbose:
relpath = py.path.local().bestrelpath(config.cache._cachedir)
return "cachedir: %s" % relpath
def cacheshow(config, session):
from pprint import pprint
tw = py.io.TerminalWriter()
tw.line("cachedir: " + str(config.cache._cachedir))
if not config.cache._cachedir.check():
tw.line("cache is empty")
return 0
dummy = object()
basedir = config.cache._cachedir
vdir = basedir.join("v")
tw.sep("-", "cache values")
for valpath in vdir.visit(lambda x: x.isfile()):
key = valpath.relto(vdir).replace(valpath.sep, "/")
val = config.cache.get(key, dummy)
if val is dummy:
tw.line("%s contains unreadable content, "
"will be ignored" % key)
else:
tw.line("%s contains:" % key)
stream = py.io.TextIO()
pprint(val, stream=stream)
for line in stream.getvalue().splitlines():
tw.line(" " + line)
ddir = basedir.join("d")
if ddir.isdir() and ddir.listdir():
tw.sep("-", "cache directories")
for p in basedir.join("d").visit():
#if p.check(dir=1):
# print("%s/" % p.relto(basedir))
if p.isfile():
key = p.relto(basedir)
tw.line("%s is a file of length %d" % (
key, p.size()))
return 0

View File

@@ -1,224 +1,444 @@
""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """
"""
per-test stdout/stderr capturing mechanism.
import pytest, py
"""
from __future__ import with_statement
import sys
import os
from tempfile import TemporaryFile
import py
import pytest
from py.io import TextIO
unicode = py.builtin.text
patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--capture', action="store", default=None,
metavar="method", type="choice", choices=['fd', 'sys', 'no'],
help="per-test capturing method: one of fd (default)|sys|no.")
group._addoption('-s', action="store_const", const="no", dest="capture",
group._addoption(
'--capture', action="store",
default="fd" if hasattr(os, "dup") else "sys",
metavar="method", choices=['fd', 'sys', 'no'],
help="per-test capturing method: one of fd|sys|no.")
group._addoption(
'-s', action="store_const", const="no", dest="capture",
help="shortcut for --capture=no.")
@pytest.mark.tryfirst
def pytest_cmdline_parse(pluginmanager, args):
# we want to perform capturing already for plugin/conftest loading
if '-s' in args or "--capture=no" in args:
method = "no"
elif hasattr(os, 'dup') and '--capture=sys' not in args:
method = "fd"
else:
method = "sys"
capman = CaptureManager(method)
@pytest.hookimpl(hookwrapper=True)
def pytest_load_initial_conftests(early_config, parser, args):
ns = early_config.known_args_namespace
pluginmanager = early_config.pluginmanager
capman = CaptureManager(ns.capture)
pluginmanager.register(capman, "capturemanager")
def addouterr(rep, outerr):
for secname, content in zip(["out", "err"], outerr):
if content:
rep.sections.append(("Captured std%s" % secname, content))
# make sure that capturemanager is properly reset at final shutdown
early_config.add_cleanup(capman.reset_capturings)
# make sure logging does not raise exceptions at the end
def silence_logging_at_shutdown():
if "logging" in sys.modules:
sys.modules["logging"].raiseExceptions = False
early_config.add_cleanup(silence_logging_at_shutdown)
# finally trigger conftest loading but while capturing (issue93)
capman.init_capturings()
outcome = yield
out, err = capman.suspendcapture()
if outcome.excinfo is not None:
sys.stdout.write(out)
sys.stderr.write(err)
class NoCapture:
def startall(self):
pass
def resume(self):
pass
def reset(self):
pass
def suspend(self):
return "", ""
class CaptureManager:
def __init__(self, defaultmethod=None):
self._method2capture = {}
self._defaultmethod = defaultmethod
def _maketempfile(self):
f = py.std.tempfile.TemporaryFile()
newf = py.io.dupfile(f, encoding="UTF-8")
f.close()
return newf
def _makestringio(self):
return py.io.TextIO()
def __init__(self, method):
self._method = method
def _getcapture(self, method):
if method == "fd":
return py.io.StdCaptureFD(now=False,
out=self._maketempfile(), err=self._maketempfile()
)
return MultiCapture(out=True, err=True, Capture=FDCapture)
elif method == "sys":
return py.io.StdCapture(now=False,
out=self._makestringio(), err=self._makestringio()
)
return MultiCapture(out=True, err=True, Capture=SysCapture)
elif method == "no":
return NoCapture()
return MultiCapture(out=False, err=False, in_=False)
else:
raise ValueError("unknown capturing method: %r" % method)
def _getmethod(self, config, fspath):
if config.option.capture:
method = config.option.capture
else:
try:
method = config._conftest.rget("option_capture", path=fspath)
except KeyError:
method = "fd"
if method == "fd" and not hasattr(os, 'dup'): # e.g. jython
method = "sys"
return method
def init_capturings(self):
assert not hasattr(self, "_capturing")
self._capturing = self._getcapture(self._method)
self._capturing.start_capturing()
def reset_capturings(self):
for name, cap in self._method2capture.items():
cap.reset()
cap = self.__dict__.pop("_capturing", None)
if cap is not None:
cap.pop_outerr_to_orig()
cap.stop_capturing()
def resumecapture_item(self, item):
method = self._getmethod(item.config, item.fspath)
if not hasattr(item, 'outerr'):
item.outerr = ('', '') # we accumulate outerr on the item
return self.resumecapture(method)
def resumecapture(self):
self._capturing.resume_capturing()
def resumecapture(self, method=None):
if hasattr(self, '_capturing'):
raise ValueError("cannot resume, already capturing with %r" %
(self._capturing,))
if method is None:
method = self._defaultmethod
cap = self._method2capture.get(method)
self._capturing = method
if cap is None:
self._method2capture[method] = cap = self._getcapture(method)
cap.startall()
else:
cap.resume()
def suspendcapture(self, item=None):
def suspendcapture(self, in_=False):
self.deactivate_funcargs()
if hasattr(self, '_capturing'):
method = self._capturing
cap = self._method2capture.get(method)
if cap is not None:
outerr = cap.suspend()
del self._capturing
if item:
outerr = (item.outerr[0] + outerr[0],
item.outerr[1] + outerr[1])
cap = getattr(self, "_capturing", None)
if cap is not None:
try:
outerr = cap.readouterr()
finally:
cap.suspend_capturing(in_=in_)
return outerr
if hasattr(item, 'outerr'):
return item.outerr
return "", ""
def activate_funcargs(self, pyfuncitem):
funcargs = getattr(pyfuncitem, "funcargs", None)
if funcargs is not None:
for name, capfuncarg in funcargs.items():
if name in ('capsys', 'capfd'):
assert not hasattr(self, '_capturing_funcarg')
self._capturing_funcarg = capfuncarg
capfuncarg._start()
capfuncarg = pyfuncitem.__dict__.pop("_capfuncarg", None)
if capfuncarg is not None:
capfuncarg._start()
self._capfuncarg = capfuncarg
def deactivate_funcargs(self):
capturing_funcarg = getattr(self, '_capturing_funcarg', None)
if capturing_funcarg:
outerr = capturing_funcarg._finalize()
del self._capturing_funcarg
return outerr
capfuncarg = self.__dict__.pop("_capfuncarg", None)
if capfuncarg is not None:
capfuncarg.close()
def pytest_make_collect_report(self, __multicall__, collector):
method = self._getmethod(collector.config, collector.fspath)
try:
self.resumecapture(method)
except ValueError:
return # recursive collect, XXX refactor capturing
# to allow for more lightweight recursive capturing
try:
rep = __multicall__.execute()
finally:
outerr = self.suspendcapture()
addouterr(rep, outerr)
return rep
@pytest.hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector):
if isinstance(collector, pytest.File):
self.resumecapture()
outcome = yield
out, err = self.suspendcapture()
rep = outcome.get_result()
if out:
rep.sections.append(("Captured stdout", out))
if err:
rep.sections.append(("Captured stderr", err))
else:
yield
@pytest.mark.tryfirst
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item):
self.resumecapture_item(item)
self.resumecapture()
yield
self.suspendcapture_item(item, "setup")
@pytest.mark.tryfirst
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item):
self.resumecapture_item(item)
self.resumecapture()
self.activate_funcargs(item)
yield
#self.deactivate_funcargs() called from suspendcapture()
self.suspendcapture_item(item, "call")
@pytest.mark.tryfirst
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item):
self.resumecapture_item(item)
self.resumecapture()
yield
self.suspendcapture_item(item, "teardown")
@pytest.hookimpl(tryfirst=True)
def pytest_keyboard_interrupt(self, excinfo):
if hasattr(self, '_capturing'):
self.suspendcapture()
self.reset_capturings()
@pytest.mark.tryfirst
def pytest_runtest_makereport(self, __multicall__, item, call):
funcarg_outerr = self.deactivate_funcargs()
rep = __multicall__.execute()
outerr = self.suspendcapture(item)
if funcarg_outerr is not None:
outerr = (outerr[0] + funcarg_outerr[0],
outerr[1] + funcarg_outerr[1])
addouterr(rep, outerr)
if not rep.passed or rep.when == "teardown":
outerr = ('', '')
item.outerr = outerr
return rep
@pytest.hookimpl(tryfirst=True)
def pytest_internalerror(self, excinfo):
self.reset_capturings()
def suspendcapture_item(self, item, when):
out, err = self.suspendcapture()
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
error_capsysfderror = "cannot use capsys and capfd at the same time"
def pytest_funcarg__capsys(request):
@pytest.fixture
def capsys(request):
"""enables capturing of writes to sys.stdout/sys.stderr and makes
captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple.
"""
if "capfd" in request._funcargs:
raise request.raiseerror(error_capsysfderror)
return CaptureFixture(py.io.StdCapture)
request.node._capfuncarg = c = CaptureFixture(SysCapture)
return c
def pytest_funcarg__capfd(request):
@pytest.fixture
def capfd(request):
"""enables capturing of writes to file descriptors 1 and 2 and makes
captured output available via ``capsys.readouterr()`` method calls
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
"""
if "capsys" in request._funcargs:
request.raiseerror(error_capsysfderror)
if not hasattr(os, 'dup'):
pytest.skip("capfd funcarg needs os.dup")
return CaptureFixture(py.io.StdCaptureFD)
request.node._capfuncarg = c = CaptureFixture(FDCapture)
return c
class CaptureFixture:
def __init__(self, captureclass):
self.capture = captureclass(now=False)
self.captureclass = captureclass
def _start(self):
self.capture.startall()
self._capture = MultiCapture(out=True, err=True, in_=False,
Capture=self.captureclass)
self._capture.start_capturing()
def _finalize(self):
if hasattr(self, 'capture'):
outerr = self._outerr = self.capture.reset()
del self.capture
return outerr
def close(self):
cap = self.__dict__.pop("_capture", None)
if cap is not None:
self._outerr = cap.pop_outerr_to_orig()
cap.stop_capturing()
def readouterr(self):
try:
return self.capture.readouterr()
return self._capture.readouterr()
except AttributeError:
return self._outerr
def safe_text_dupfile(f, mode, default_encoding="UTF8"):
""" return a open text file object that's a duplicate of f on the
FD-level if possible.
"""
encoding = getattr(f, "encoding", None)
try:
fd = f.fileno()
except Exception:
if "b" not in getattr(f, "mode", "") and hasattr(f, "encoding"):
# we seem to have a text stream, let's just use it
return f
else:
newfd = os.dup(fd)
if "b" not in mode:
mode += "b"
f = os.fdopen(newfd, mode, 0) # no buffering
return EncodedFile(f, encoding or default_encoding)
class EncodedFile(object):
errors = "strict" # possibly needed by py3 code (issue555)
def __init__(self, buffer, encoding):
self.buffer = buffer
self.encoding = encoding
def write(self, obj):
if isinstance(obj, unicode):
obj = obj.encode(self.encoding, "replace")
self.buffer.write(obj)
def writelines(self, linelist):
data = ''.join(linelist)
self.write(data)
def __getattr__(self, name):
return getattr(object.__getattribute__(self, "buffer"), name)
class MultiCapture(object):
out = err = in_ = None
def __init__(self, out=True, err=True, in_=True, Capture=None):
if in_:
self.in_ = Capture(0)
if out:
self.out = Capture(1)
if err:
self.err = Capture(2)
def start_capturing(self):
if self.in_:
self.in_.start()
if self.out:
self.out.start()
if self.err:
self.err.start()
def pop_outerr_to_orig(self):
""" pop current snapshot out/err capture and flush to orig streams. """
out, err = self.readouterr()
if out:
self.out.writeorg(out)
if err:
self.err.writeorg(err)
return out, err
def suspend_capturing(self, in_=False):
if self.out:
self.out.suspend()
if self.err:
self.err.suspend()
if in_ and self.in_:
self.in_.suspend()
self._in_suspended = True
def resume_capturing(self):
if self.out:
self.out.resume()
if self.err:
self.err.resume()
if hasattr(self, "_in_suspended"):
self.in_.resume()
del self._in_suspended
def stop_capturing(self):
""" stop capturing and reset capturing streams """
if hasattr(self, '_reset'):
raise ValueError("was already stopped")
self._reset = True
if self.out:
self.out.done()
if self.err:
self.err.done()
if self.in_:
self.in_.done()
def readouterr(self):
""" return snapshot unicode value of stdout/stderr capturings. """
return (self.out.snap() if self.out is not None else "",
self.err.snap() if self.err is not None else "")
class NoCapture:
__init__ = start = done = suspend = resume = lambda *args: None
class FDCapture:
""" Capture IO to/from a given os-level filedescriptor. """
def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd
try:
self.targetfd_save = os.dup(self.targetfd)
except OSError:
self.start = lambda: None
self.done = lambda: None
else:
if targetfd == 0:
assert not tmpfile, "cannot set tmpfile with stdin"
tmpfile = open(os.devnull, "r")
self.syscapture = SysCapture(targetfd)
else:
if tmpfile is None:
f = TemporaryFile()
with f:
tmpfile = safe_text_dupfile(f, mode="wb+")
if targetfd in patchsysdict:
self.syscapture = SysCapture(targetfd, tmpfile)
else:
self.syscapture = NoCapture()
self.tmpfile = tmpfile
self.tmpfile_fd = tmpfile.fileno()
def __repr__(self):
return "<FDCapture %s oldfd=%s>" % (self.targetfd, self.targetfd_save)
def start(self):
""" Start capturing on targetfd using memorized tmpfile. """
try:
os.fstat(self.targetfd_save)
except (AttributeError, OSError):
raise ValueError("saved filedescriptor not valid anymore")
os.dup2(self.tmpfile_fd, self.targetfd)
self.syscapture.start()
def snap(self):
f = self.tmpfile
f.seek(0)
res = f.read()
if res:
enc = getattr(f, "encoding", None)
if enc and isinstance(res, bytes):
res = py.builtin._totext(res, enc, "replace")
f.truncate(0)
f.seek(0)
return res
return ''
def done(self):
""" stop capturing, restore streams, return original capture file,
seeked to position zero. """
targetfd_save = self.__dict__.pop("targetfd_save")
os.dup2(targetfd_save, self.targetfd)
os.close(targetfd_save)
self.syscapture.done()
self.tmpfile.close()
def suspend(self):
self.syscapture.suspend()
os.dup2(self.targetfd_save, self.targetfd)
def resume(self):
self.syscapture.resume()
os.dup2(self.tmpfile_fd, self.targetfd)
def writeorg(self, data):
""" write to original file descriptor. """
if py.builtin._istext(data):
data = data.encode("utf8") # XXX use encoding of original stream
os.write(self.targetfd_save, data)
class SysCapture:
def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd]
self._old = getattr(sys, name)
self.name = name
if tmpfile is None:
if name == "stdin":
tmpfile = DontReadFromInput()
else:
tmpfile = TextIO()
self.tmpfile = tmpfile
def start(self):
setattr(sys, self.name, self.tmpfile)
def snap(self):
f = self.tmpfile
res = f.getvalue()
f.truncate(0)
f.seek(0)
return res
def done(self):
setattr(sys, self.name, self._old)
del self._old
self.tmpfile.close()
def suspend(self):
setattr(sys, self.name, self._old)
def resume(self):
setattr(sys, self.name, self.tmpfile)
def writeorg(self, data):
self._old.write(data)
self._old.flush()
class DontReadFromInput:
"""Temporary stub class. Ideally when stdin is accessed, the
capturing should be turned off, with possibly all data captured
so far sent to the screen. This should be configurable, though,
because in automated test runs it is better to crash than
hang indefinitely.
"""
encoding = None
def read(self, *args):
raise IOError("reading from stdin while output is captured")
readline = read
readlines = read
__iter__ = read
def fileno(self):
raise ValueError("redirected Stdin is pseudofile, has no fileno()")
def isatty(self):
return False
def close(self):
self._finalize()
pass

File diff suppressed because it is too large Load Diff

View File

@@ -1,498 +0,0 @@
"""
pytest PluginManager, basic initialization and tracing.
(c) Holger Krekel 2004-2010
"""
import sys, os
import inspect
import py
from _pytest import hookspec # the extension point definitions
assert py.__version__.split(".")[:2] >= ['1', '4'], ("installation problem: "
"%s is too old, remove or upgrade 'py'" % (py.__version__))
default_plugins = (
"config mark main terminal runner python pdb unittest capture skipping "
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
"junitxml resultlog doctest").split()
class TagTracer:
def __init__(self):
self._tag2proc = {}
self.writer = None
self.indent = 0
def get(self, name):
return TagTracerSub(self, (name,))
def format_message(self, tags, args):
if isinstance(args[-1], dict):
extra = args[-1]
args = args[:-1]
else:
extra = {}
content = " ".join(map(str, args))
indent = " " * self.indent
lines = [
"%s%s [%s]\n" %(indent, content, ":".join(tags))
]
for name, value in extra.items():
lines.append("%s %s: %s\n" % (indent, name, value))
return lines
def processmessage(self, tags, args):
if self.writer is not None and args:
lines = self.format_message(tags, args)
self.writer(''.join(lines))
try:
self._tag2proc[tags](tags, args)
except KeyError:
pass
def setwriter(self, writer):
self.writer = writer
def setprocessor(self, tags, processor):
if isinstance(tags, str):
tags = tuple(tags.split(":"))
else:
assert isinstance(tags, tuple)
self._tag2proc[tags] = processor
class TagTracerSub:
def __init__(self, root, tags):
self.root = root
self.tags = tags
def __call__(self, *args):
self.root.processmessage(self.tags, args)
def setmyprocessor(self, processor):
self.root.setprocessor(self.tags, processor)
def get(self, name):
return self.__class__(self.root, self.tags + (name,))
class PluginManager(object):
def __init__(self, load=False):
self._name2plugin = {}
self._listattrcache = {}
self._plugins = []
self._hints = []
self.trace = TagTracer().get("pluginmanage")
self._plugin_distinfo = []
if os.environ.get('PYTEST_DEBUG'):
err = sys.stderr
encoding = getattr(err, 'encoding', 'utf8')
try:
err = py.io.dupfile(err, encoding=encoding)
except Exception:
pass
self.trace.root.setwriter(err.write)
self.hook = HookRelay([hookspec], pm=self)
self.register(self)
if load:
for spec in default_plugins:
self.import_plugin(spec)
def register(self, plugin, name=None, prepend=False):
if self._name2plugin.get(name, None) == -1:
return
name = name or getattr(plugin, '__name__', str(id(plugin)))
if self.isregistered(plugin, name):
raise ValueError("Plugin already registered: %s=%s" %(name, plugin))
#self.trace("registering", name, plugin)
self._name2plugin[name] = plugin
self.call_plugin(plugin, "pytest_addhooks", {'pluginmanager': self})
self.hook.pytest_plugin_registered(manager=self, plugin=plugin)
if not prepend:
self._plugins.append(plugin)
else:
self._plugins.insert(0, plugin)
return True
def unregister(self, plugin=None, name=None):
if plugin is None:
plugin = self.getplugin(name=name)
self._plugins.remove(plugin)
self.hook.pytest_plugin_unregistered(plugin=plugin)
for name, value in list(self._name2plugin.items()):
if value == plugin:
del self._name2plugin[name]
def isregistered(self, plugin, name=None):
if self.getplugin(name) is not None:
return True
for val in self._name2plugin.values():
if plugin == val:
return True
def addhooks(self, spec):
self.hook._addhooks(spec, prefix="pytest_")
def getplugins(self):
return list(self._plugins)
def skipifmissing(self, name):
if not self.hasplugin(name):
py.test.skip("plugin %r is missing" % name)
def hasplugin(self, name):
return bool(self.getplugin(name))
def getplugin(self, name):
if name is None:
return None
try:
return self._name2plugin[name]
except KeyError:
return self._name2plugin.get("_pytest." + name, None)
# API for bootstrapping
#
def _envlist(self, varname):
val = py.std.os.environ.get(varname, None)
if val is not None:
return val.split(',')
return ()
def consider_env(self):
for spec in self._envlist("PYTEST_PLUGINS"):
self.import_plugin(spec)
def consider_setuptools_entrypoints(self):
try:
from pkg_resources import iter_entry_points, DistributionNotFound
except ImportError:
return # XXX issue a warning
for ep in iter_entry_points('pytest11'):
name = ep.name
if name.startswith("pytest_"):
name = name[7:]
if ep.name in self._name2plugin or name in self._name2plugin:
continue
try:
plugin = ep.load()
except DistributionNotFound:
continue
self._plugin_distinfo.append((ep.dist, plugin))
self.register(plugin, name=name)
def consider_preparse(self, args):
for opt1,opt2 in zip(args, args[1:]):
if opt1 == "-p":
self.consider_pluginarg(opt2)
def consider_pluginarg(self, arg):
if arg.startswith("no:"):
name = arg[3:]
if self.getplugin(name) is not None:
self.unregister(None, name=name)
self._name2plugin[name] = -1
else:
if self.getplugin(arg) is None:
self.import_plugin(arg)
def consider_conftest(self, conftestmodule):
if self.register(conftestmodule, name=conftestmodule.__file__):
self.consider_module(conftestmodule)
def consider_module(self, mod):
attr = getattr(mod, "pytest_plugins", ())
if attr:
if not isinstance(attr, (list, tuple)):
attr = (attr,)
for spec in attr:
self.import_plugin(spec)
def import_plugin(self, modname):
assert isinstance(modname, str)
if self.getplugin(modname) is not None:
return
try:
#self.trace("importing", modname)
mod = importplugin(modname)
except KeyboardInterrupt:
raise
except ImportError:
if modname.startswith("pytest_"):
return self.import_plugin(modname[7:])
raise
except:
e = py.std.sys.exc_info()[1]
if not hasattr(py.test, 'skip'):
raise
elif not isinstance(e, py.test.skip.Exception):
raise
self._hints.append("skipped plugin %r: %s" %((modname, e.msg)))
else:
self.register(mod, modname)
self.consider_module(mod)
def pytest_configure(self, config):
config.addinivalue_line("markers",
"tryfirst: mark a hook implementation function such that the "
"plugin machinery will try to call it first/as early as possible.")
config.addinivalue_line("markers",
"trylast: mark a hook implementation function such that the "
"plugin machinery will try to call it last/as late as possible.")
def pytest_plugin_registered(self, plugin):
import pytest
dic = self.call_plugin(plugin, "pytest_namespace", {}) or {}
if dic:
self._setns(pytest, dic)
if hasattr(self, '_config'):
self.call_plugin(plugin, "pytest_addoption",
{'parser': self._config._parser})
self.call_plugin(plugin, "pytest_configure",
{'config': self._config})
def _setns(self, obj, dic):
import pytest
for name, value in dic.items():
if isinstance(value, dict):
mod = getattr(obj, name, None)
if mod is None:
modname = "pytest.%s" % name
mod = py.std.types.ModuleType(modname)
sys.modules[modname] = mod
mod.__all__ = []
setattr(obj, name, mod)
obj.__all__.append(name)
self._setns(mod, value)
else:
setattr(obj, name, value)
obj.__all__.append(name)
#if obj != pytest:
# pytest.__all__.append(name)
setattr(pytest, name, value)
def pytest_terminal_summary(self, terminalreporter):
tw = terminalreporter._tw
if terminalreporter.config.option.traceconfig:
for hint in self._hints:
tw.line("hint: %s" % hint)
def do_addoption(self, parser):
mname = "pytest_addoption"
methods = reversed(self.listattr(mname))
MultiCall(methods, {'parser': parser}).execute()
def do_configure(self, config):
assert not hasattr(self, '_config')
self._config = config
config.hook.pytest_configure(config=self._config)
def do_unconfigure(self, config):
config = self._config
del self._config
config.hook.pytest_unconfigure(config=config)
config.pluginmanager.unregister(self)
def notify_exception(self, excinfo, option=None):
if option and option.fulltrace:
style = "long"
else:
style = "native"
excrepr = excinfo.getrepr(funcargs=True,
showlocals=getattr(option, 'showlocals', False),
style=style,
)
res = self.hook.pytest_internalerror(excrepr=excrepr)
if not py.builtin.any(res):
for line in str(excrepr).split("\n"):
sys.stderr.write("INTERNALERROR> %s\n" %line)
sys.stderr.flush()
def listattr(self, attrname, plugins=None):
if plugins is None:
plugins = self._plugins
key = (attrname,) + tuple(plugins)
try:
return list(self._listattrcache[key])
except KeyError:
pass
l = []
last = []
for plugin in plugins:
try:
meth = getattr(plugin, attrname)
if hasattr(meth, 'tryfirst'):
last.append(meth)
elif hasattr(meth, 'trylast'):
l.insert(0, meth)
else:
l.append(meth)
except AttributeError:
continue
l.extend(last)
self._listattrcache[key] = list(l)
return l
def call_plugin(self, plugin, methname, kwargs):
return MultiCall(methods=self.listattr(methname, plugins=[plugin]),
kwargs=kwargs, firstresult=True).execute()
def importplugin(importspec):
name = importspec
try:
mod = "_pytest." + name
__import__(mod)
return sys.modules[mod]
except ImportError:
#e = py.std.sys.exc_info()[1]
#if str(e).find(name) == -1:
# raise
pass #
try:
__import__(importspec)
except ImportError:
raise ImportError(importspec)
return sys.modules[importspec]
class MultiCall:
""" execute a call into multiple python functions/methods. """
def __init__(self, methods, kwargs, firstresult=False):
self.methods = list(methods)
self.kwargs = kwargs
self.results = []
self.firstresult = firstresult
def __repr__(self):
status = "%d results, %d meths" % (len(self.results), len(self.methods))
return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs)
def execute(self):
while self.methods:
method = self.methods.pop()
kwargs = self.getkwargs(method)
res = method(**kwargs)
if res is not None:
self.results.append(res)
if self.firstresult:
return res
if not self.firstresult:
return self.results
def getkwargs(self, method):
kwargs = {}
for argname in varnames(method):
try:
kwargs[argname] = self.kwargs[argname]
except KeyError:
if argname == "__multicall__":
kwargs[argname] = self
return kwargs
def varnames(func):
try:
return func._varnames
except AttributeError:
pass
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
return x
class HookRelay:
def __init__(self, hookspecs, pm, prefix="pytest_"):
if not isinstance(hookspecs, list):
hookspecs = [hookspecs]
self._hookspecs = []
self._pm = pm
self.trace = pm.trace.root.get("hook")
for hookspec in hookspecs:
self._addhooks(hookspec, prefix)
def _addhooks(self, hookspecs, prefix):
self._hookspecs.append(hookspecs)
added = False
for name, method in vars(hookspecs).items():
if name.startswith(prefix):
firstresult = getattr(method, 'firstresult', False)
hc = HookCaller(self, name, firstresult=firstresult)
setattr(self, name, hc)
added = True
#print ("setting new hook", name)
if not added:
raise ValueError("did not find new %r hooks in %r" %(
prefix, hookspecs,))
class HookCaller:
def __init__(self, hookrelay, name, firstresult):
self.hookrelay = hookrelay
self.name = name
self.firstresult = firstresult
self.trace = self.hookrelay.trace
def __repr__(self):
return "<HookCaller %r>" %(self.name,)
def __call__(self, **kwargs):
methods = self.hookrelay._pm.listattr(self.name)
return self._docall(methods, kwargs)
def pcall(self, plugins, **kwargs):
methods = self.hookrelay._pm.listattr(self.name, plugins=plugins)
return self._docall(methods, kwargs)
def _docall(self, methods, kwargs):
self.trace(self.name, kwargs)
self.trace.root.indent += 1
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
try:
res = mc.execute()
if res:
self.trace("finish", self.name, "-->", res)
finally:
self.trace.root.indent -= 1
return res
_preinit = []
def _preloadplugins():
_preinit.append(PluginManager(load=True))
def _prepareconfig(args=None, plugins=None):
if args is None:
args = sys.argv[1:]
elif isinstance(args, py.path.local):
args = [str(args)]
elif not isinstance(args, (tuple, list)):
if not isinstance(args, str):
raise ValueError("not a string or argument list: %r" % (args,))
args = py.std.shlex.split(args)
if _preinit:
_pluginmanager = _preinit.pop(0)
else: # subsequent calls to main will create a fresh instance
_pluginmanager = PluginManager(load=True)
hook = _pluginmanager.hook
if plugins:
for plugin in plugins:
_pluginmanager.register(plugin)
return hook.pytest_cmdline_parse(
pluginmanager=_pluginmanager, args=args)
def main(args=None, plugins=None):
""" return exit code, after performing an in-process test run.
:arg args: list of command line arguments.
:arg plugins: list of plugin objects to be auto-registered during
initialization.
"""
config = _prepareconfig(args, plugins)
exitstatus = config.hook.pytest_cmdline_main(config=config)
return exitstatus
class UsageError(Exception):
""" error in py.test usage or invocation"""

View File

@@ -1,10 +1,13 @@
""" discover and run doctests in modules and test files."""
from __future__ import absolute_import
import traceback
import pytest, py
from _pytest.python import FixtureRequest, FuncFixtureInfo
from _pytest.python import FixtureRequest
from py._code.code import TerminalRepr, ReprFileLocation
def pytest_addoption(parser):
parser.addini('doctest_optionflags', 'option flags for doctests',
type="args", default=["ELLIPSIS"])
group = parser.getgroup("collect")
group.addoption("--doctest-modules",
action="store_true", default=False,
@@ -14,6 +17,10 @@ def pytest_addoption(parser):
action="store", default="test*.txt", metavar="pat",
help="doctests file matching pattern, default: test*.txt",
dest="doctestglob")
group.addoption("--doctest-ignore-import-errors",
action="store_true", default=False,
help="ignore doctest ImportErrors",
dest="doctest_ignore_import_errors")
def pytest_collect_file(path, parent):
config = parent.config
@@ -34,8 +41,17 @@ class ReprFailDoctest(TerminalRepr):
self.reprlocation.toterminal(tw)
class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent)
self.runner = runner
self.dtest = dtest
def runtest(self):
_check_all_skipped(self.dtest)
self.runner.run(self.dtest)
def repr_failure(self, excinfo):
doctest = py.std.doctest
import doctest
if excinfo.errisinstance((doctest.DocTestFailure,
doctest.UnexpectedException)):
doctestfailure = excinfo.value
@@ -48,8 +64,8 @@ class DoctestItem(pytest.Item):
lineno = test.lineno + example.lineno + 1
message = excinfo.type.__name__
reprlocation = ReprFileLocation(filename, lineno, message)
checker = py.std.doctest.OutputChecker()
REPORT_UDIFF = py.std.doctest.REPORT_UDIFF
checker = _get_unicode_checker()
REPORT_UDIFF = doctest.REPORT_UDIFF
filelines = py.path.local(filename).readlines(cr=0)
lines = []
if lineno is not None:
@@ -70,39 +86,162 @@ class DoctestItem(pytest.Item):
inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" %
repr(inner_excinfo.value)]
lines += py.std.traceback.format_exception(*excinfo.value.exc_info)
lines += traceback.format_exception(*excinfo.value.exc_info)
return ReprFailDoctest(reprlocation, lines)
else:
return super(DoctestItem, self).repr_failure(excinfo)
def reportinfo(self):
return self.fspath, None, "[doctest]"
return self.fspath, None, "[doctest] %s" % self.name
def _get_flag_lookup():
import doctest
return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE,
NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE,
ELLIPSIS=doctest.ELLIPSIS,
IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL,
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
ALLOW_UNICODE=_get_allow_unicode_flag())
def get_optionflags(parent):
optionflags_str = parent.config.getini("doctest_optionflags")
flag_lookup_table = _get_flag_lookup()
flag_acc = 0
for flag in optionflags_str:
flag_acc |= flag_lookup_table[flag]
return flag_acc
class DoctestTextfile(DoctestItem, pytest.File):
def runtest(self):
doctest = py.std.doctest
# satisfy `FixtureRequest` constructor...
self.funcargs = {}
self._fixtureinfo = FuncFixtureInfo((), [], {})
fixture_request = FixtureRequest(self)
failed, tot = doctest.testfile(
str(self.fspath), module_relative=False,
optionflags=doctest.ELLIPSIS,
extraglobs=dict(getfixture=fixture_request.getfuncargvalue),
raise_on_error=True, verbose=0)
class DoctestModule(DoctestItem, pytest.File):
def runtest(self):
doctest = py.std.doctest
import doctest
fixture_request = _setup_fixtures(self)
# inspired by doctest.testfile; ideally we would use it directly,
# but it doesn't support passing a custom checker
text = self.fspath.read()
filename = str(self.fspath)
name = self.fspath.basename
globs = dict(getfixture=fixture_request.getfuncargvalue)
if '__name__' not in globs:
globs['__name__'] = '__main__'
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_unicode_checker())
parser = doctest.DocTestParser()
test = parser.get_doctest(text, globs, name, filename, 0)
_check_all_skipped(test)
runner.run(test)
def _check_all_skipped(test):
"""raises pytest.skip() if all examples in the given DocTest have the SKIP
option set.
"""
import doctest
all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
if all_skipped:
pytest.skip('all tests skipped by +SKIP option')
class DoctestModule(pytest.File):
def collect(self):
import doctest
if self.fspath.basename == "conftest.py":
module = self.config._conftest.importconftest(self.fspath)
module = self.config.pluginmanager._importconftest(self.fspath)
else:
module = self.fspath.pyimport()
try:
module = self.fspath.pyimport()
except ImportError:
if self.config.getvalue('doctest_ignore_import_errors'):
pytest.skip('unable to import module %r' % self.fspath)
else:
raise
# satisfy `FixtureRequest` constructor...
self.funcargs = {}
self._fixtureinfo = FuncFixtureInfo((), [], {})
fixture_request = FixtureRequest(self)
failed, tot = doctest.testmod(
module, raise_on_error=True, verbose=0,
extraglobs=dict(getfixture=fixture_request.getfuncargvalue),
optionflags=doctest.ELLIPSIS)
fixture_request = _setup_fixtures(self)
doctest_globals = dict(getfixture=fixture_request.getfuncargvalue)
# uses internal doctest module parsing mechanism
finder = doctest.DocTestFinder()
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_unicode_checker())
for test in finder.find(module, module.__name__,
extraglobs=doctest_globals):
if test.examples: # skip empty doctests
yield DoctestItem(test.name, self, runner, test)
def _setup_fixtures(doctest_item):
"""
Used by DoctestTextfile and DoctestModule to setup fixture information.
"""
def func():
pass
doctest_item.funcargs = {}
fm = doctest_item.session._fixturemanager
doctest_item._fixtureinfo = fm.getfixtureinfo(node=doctest_item, func=func,
cls=None, funcargs=False)
fixture_request = FixtureRequest(doctest_item)
fixture_request._fillfixtures()
return fixture_request
def _get_unicode_checker():
"""
Returns a doctest.OutputChecker subclass that takes in account the
ALLOW_UNICODE option to ignore u'' prefixes in strings. Useful
when the same doctest should run in Python 2 and Python 3.
An inner class is used to avoid importing "doctest" at the module
level.
"""
if hasattr(_get_unicode_checker, 'UnicodeOutputChecker'):
return _get_unicode_checker.UnicodeOutputChecker()
import doctest
import re
class UnicodeOutputChecker(doctest.OutputChecker):
"""
Copied from doctest_nose_plugin.py from the nltk project:
https://github.com/nltk/nltk
"""
_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
def check_output(self, want, got, optionflags):
res = doctest.OutputChecker.check_output(self, want, got,
optionflags)
if res:
return True
if not (optionflags & _get_allow_unicode_flag()):
return False
else: # pragma: no cover
# the code below will end up executed only in Python 2 in
# our tests, and our coverage check runs in Python 3 only
def remove_u_prefixes(txt):
return re.sub(self._literal_re, r'\1\2', txt)
want = remove_u_prefixes(want)
got = remove_u_prefixes(got)
res = doctest.OutputChecker.check_output(self, want, got,
optionflags)
return res
_get_unicode_checker.UnicodeOutputChecker = UnicodeOutputChecker
return _get_unicode_checker.UnicodeOutputChecker()
def _get_allow_unicode_flag():
"""
Registers and returns the ALLOW_UNICODE flag.
"""
import doctest
return doctest.register_optionflag('ALLOW_UNICODE')

View File

@@ -1,8 +1,15 @@
""" generate a single-file self-contained version of py.test """
""" (deprecated) generate a single-file self-contained version of pytest """
import os
import sys
import pkgutil
import py
import _pytest
def find_toplevel(name):
for syspath in py.std.sys.path:
for syspath in sys.path:
base = py.path.local(syspath)
lib = base/name
if lib.check(dir=1):
@@ -25,12 +32,16 @@ def pkg_to_mapping(name):
for pyfile in toplevel.visit('*.py'):
pkg = pkgname(name, toplevel, pyfile)
name2src[pkg] = pyfile.read()
# with wheels py source code might be not be installed
# and the resulting genscript is useless, just bail out.
assert name2src, "no source code found for %r at %r" %(name, toplevel)
return name2src
def compress_mapping(mapping):
data = py.std.pickle.dumps(mapping, 2)
data = py.std.zlib.compress(data, 9)
data = py.std.base64.encodestring(data)
import base64, pickle, zlib
data = pickle.dumps(mapping, 2)
data = zlib.compress(data, 9)
data = base64.encodestring(data)
data = data.decode('ascii')
return data
@@ -54,16 +65,68 @@ def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption("--genscript", action="store", default=None,
dest="genscript", metavar="path",
help="create standalone py.test script at given target path.")
help="create standalone pytest script at given target path.")
def pytest_cmdline_main(config):
import _pytest.config
genscript = config.getvalue("genscript")
if genscript:
tw = _pytest.config.create_terminal_writer(config)
tw.line("WARNING: usage of genscript is deprecated.",
red=True)
deps = ['py', '_pytest', 'pytest'] # pluggy is vendored
if sys.version_info < (2,7):
deps.append("argparse")
tw.line("generated script will run on python2.6-python3.3++")
else:
tw.line("WARNING: generated script will not run on python2.6 "
"due to 'argparse' dependency. Use python2.6 "
"to generate a python2.6 compatible script", red=True)
script = generate_script(
'import py; raise SystemExit(py.test.cmdline.main())',
['py', '_pytest', 'pytest'],
'import pytest; raise SystemExit(pytest.cmdline.main())',
deps,
)
genscript = py.path.local(genscript)
genscript.write(script)
tw.line("generated pytest standalone script: %s" % genscript,
bold=True)
return 0
def pytest_namespace():
return {'freeze_includes': freeze_includes}
def freeze_includes():
"""
Returns a list of module names used by py.test that should be
included by cx_freeze.
"""
result = list(_iter_all_modules(py))
result += list(_iter_all_modules(_pytest))
return result
def _iter_all_modules(package, prefix=''):
"""
Iterates over the names of all modules that can be found in the given
package, recursively.
Example:
_iter_all_modules(_pytest) ->
['_pytest.assertion.newinterpret',
'_pytest.capture',
'_pytest.core',
...
]
"""
if type(package) is not str:
path, prefix = package.__path__[0], package.__name__ + '.'
else:
path = package
for _, name, is_package in pkgutil.iter_modules([path]):
if is_package:
for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'):
yield prefix + m
else:
yield prefix + name

View File

@@ -1,8 +1,7 @@
""" version info, help messages, tracing configuration. """
import py
import pytest
import os, inspect, sys
from _pytest.core import varnames
import os, sys
def pytest_addoption(parser):
group = parser.getgroup('debugconfig')
@@ -12,41 +11,44 @@ def pytest_addoption(parser):
help="show help message and configuration info")
group._addoption('-p', action="append", dest="plugins", default = [],
metavar="name",
help="early-load given plugin (multi-allowed).")
group.addoption('--traceconfig',
action="store_true", dest="traceconfig", default=False,
help="early-load given plugin (multi-allowed). "
"To avoid loading of plugins, use the `no:` prefix, e.g. "
"`no:doctest`.")
group.addoption('--traceconfig', '--trace-config',
action="store_true", default=False,
help="trace considerations of conftest.py files."),
group.addoption('--debug',
action="store_true", dest="debug", default=False,
help="store internal tracing debug information in 'pytestdebug.log'.")
def pytest_cmdline_parse(__multicall__):
config = __multicall__.execute()
@pytest.hookimpl(hookwrapper=True)
def pytest_cmdline_parse():
outcome = yield
config = outcome.get_result()
if config.option.debug:
path = os.path.abspath("pytestdebug.log")
f = open(path, 'w')
config._debugfile = f
f.write("versions pytest-%s, py-%s, python-%s\ncwd=%s\nargs=%s\n\n" %(
pytest.__version__, py.__version__, ".".join(map(str, sys.version_info)),
debugfile = open(path, 'w')
debugfile.write("versions pytest-%s, py-%s, "
"python-%s\ncwd=%s\nargs=%s\n\n" %(
pytest.__version__, py.__version__,
".".join(map(str, sys.version_info)),
os.getcwd(), config._origargs))
config.trace.root.setwriter(f.write)
config.trace.root.setwriter(debugfile.write)
undo_tracing = config.pluginmanager.enable_tracing()
sys.stderr.write("writing pytestdebug information to %s\n" % path)
return config
@pytest.mark.trylast
def pytest_unconfigure(config):
if hasattr(config, '_debugfile'):
config._debugfile.close()
sys.stderr.write("wrote pytestdebug information to %s\n" %
config._debugfile.name)
config.trace.root.setwriter(None)
def unset_tracing():
debugfile.close()
sys.stderr.write("wrote pytestdebug information to %s\n" %
debugfile.name)
config.trace.root.setwriter(None)
undo_tracing()
config.add_cleanup(unset_tracing)
def pytest_cmdline_main(config):
if config.option.version:
p = py.path.local(pytest.__file__)
sys.stderr.write("This is py.test version %s, imported from %s\n" %
sys.stderr.write("This is pytest version %s, imported from %s\n" %
(pytest.__version__, p))
plugininfo = getpluginversioninfo(config)
if plugininfo:
@@ -54,13 +56,14 @@ def pytest_cmdline_main(config):
sys.stderr.write(line + "\n")
return 0
elif config.option.help:
config.pluginmanager.do_configure(config)
config._do_configure()
showhelp(config)
config.pluginmanager.do_unconfigure(config)
config._ensure_unconfigure()
return 0
def showhelp(config):
tw = py.io.TerminalWriter()
reporter = config.pluginmanager.get_plugin('terminalreporter')
tw = reporter._tw
tw.write(config._parser.optparser.format_help())
tw.line()
tw.line()
@@ -77,20 +80,27 @@ def showhelp(config):
line = " %-24s %s" %(spec, help)
tw.line(line[:tw.fullwidth])
tw.line() ; tw.line()
#tw.sep("=")
tw.line()
tw.line("environment variables:")
vars = [
("PYTEST_ADDOPTS", "extra command line options"),
("PYTEST_PLUGINS", "comma-separated plugins to load during startup"),
("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals")
]
for name, help in vars:
tw.line(" %-24s %s" % (name, help))
tw.line()
tw.line()
tw.line("to see available markers type: py.test --markers")
tw.line("to see available fixtures type: py.test --fixtures")
tw.line("(shown according to specified file_or_dir or current dir "
"if not specified)")
for warningreport in reporter.stats.get('warnings', []):
tw.line("warning : " + warningreport.message, red=True)
return
tw.line("conftest.py options:")
tw.line()
conftestitems = sorted(config._parser._conftestdict.items())
for name, help in conftest_options + conftestitems:
line = " %-15s %s" %(name, help)
tw.line(line[:tw.fullwidth])
tw.line()
#tw.sep( "=")
conftest_options = [
('pytest_plugins', 'list of plugin names to load'),
@@ -98,10 +108,10 @@ conftest_options = [
def getpluginversioninfo(config):
lines = []
plugininfo = config.pluginmanager._plugin_distinfo
plugininfo = config.pluginmanager.list_plugin_distinfo()
if plugininfo:
lines.append("setuptools registered plugins:")
for dist, plugin in plugininfo:
for plugin, dist in plugininfo:
loc = getattr(plugin, '__file__', repr(plugin))
content = "%s-%s at %s" % (dist.project_name, dist.version, loc)
lines.append(" " + content)
@@ -119,8 +129,7 @@ def pytest_report_header(config):
if config.option.traceconfig:
lines.append("active plugins:")
plugins = []
items = config.pluginmanager._name2plugin.items()
items = config.pluginmanager.list_name_plugin()
for name, plugin in items:
if hasattr(plugin, '__file__'):
r = plugin.__file__
@@ -128,72 +137,3 @@ def pytest_report_header(config):
r = repr(plugin)
lines.append(" %-20s: %s" %(name, r))
return lines
# =====================================================
# validate plugin syntax and hooks
# =====================================================
def pytest_plugin_registered(manager, plugin):
methods = collectattr(plugin)
hooks = {}
for hookspec in manager.hook._hookspecs:
hooks.update(collectattr(hookspec))
stringio = py.io.TextIO()
def Print(*args):
if args:
stringio.write(" ".join(map(str, args)))
stringio.write("\n")
fail = False
while methods:
name, method = methods.popitem()
#print "checking", name
if isgenerichook(name):
continue
if name not in hooks:
if not getattr(method, 'optionalhook', False):
Print("found unknown hook:", name)
fail = True
else:
#print "checking", method
method_args = list(varnames(method))
if '__multicall__' in method_args:
method_args.remove('__multicall__')
hook = hooks[name]
hookargs = varnames(hook)
for arg in method_args:
if arg not in hookargs:
Print("argument %r not available" %(arg, ))
Print("actual definition: %s" %(formatdef(method)))
Print("available hook arguments: %s" %
", ".join(hookargs))
fail = True
break
#if not fail:
# print "matching hook:", formatdef(method)
if fail:
name = getattr(plugin, '__name__', plugin)
raise PluginValidationError("%s:\n%s" % (name, stringio.getvalue()))
class PluginValidationError(Exception):
""" plugin failed validation. """
def isgenerichook(name):
return name == "pytest_plugins" or \
name.startswith("pytest_funcarg__")
def collectattr(obj):
methods = {}
for apiname in dir(obj):
if apiname.startswith("pytest_"):
methods[apiname] = getattr(obj, apiname)
return methods
def formatdef(func):
return "%s%s" % (
func.__name__,
inspect.formatargspec(*inspect.getargspec(func))
)

View File

@@ -1,32 +1,44 @@
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
from _pytest._pluggy import HookspecMarker
hookspec = HookspecMarker("pytest")
# -------------------------------------------------------------------------
# Initialization
# Initialization hooks called for every plugin
# -------------------------------------------------------------------------
@hookspec(historic=True)
def pytest_addhooks(pluginmanager):
"""called at plugin load time to allow adding new hooks via a call to
pluginmanager.registerhooks(module)."""
"""called at plugin registration time to allow adding new hooks via a call to
pluginmanager.add_hookspecs(module_or_class, prefix)."""
@hookspec(historic=True)
def pytest_namespace():
"""return dict of name->object to be made globally available in
the py.test/pytest namespace. This hook is called before command
line options are parsed.
the pytest namespace. This hook is called at plugin registration
time.
"""
def pytest_cmdline_parse(pluginmanager, args):
"""return initialized config object, parsing the specified args. """
pytest_cmdline_parse.firstresult = True
@hookspec(historic=True)
def pytest_plugin_registered(plugin, manager):
""" a new pytest plugin got registered. """
def pytest_cmdline_preparse(config, args):
"""modify command line arguments before option parsing. """
@hookspec(historic=True)
def pytest_addoption(parser):
"""register optparse-style options and ini-style config values.
"""register argparse-style options and ini-style config values.
This function must be implemented in a :ref:`plugin <pluginorder>` and is
called once at the beginning of a test run.
.. warning::
This function must be implemented in a :ref:`plugin <pluginorder>`
and is called once at the beginning of a test run.
Implementing this hook from ``conftest.py`` files is **strongly**
discouraged because ``conftest.py`` files are lazily loaded and
may give strange *unknown option* errors depending on the directory
``py.test`` is invoked from.
:arg parser: To add command line options, call
:py:func:`parser.addoption(...) <_pytest.config.Parser.addoption>`.
@@ -47,31 +59,43 @@ def pytest_addoption(parser):
via (deprecated) ``pytest.config``.
"""
@hookspec(historic=True)
def pytest_configure(config):
""" called after command line options have been parsed
and all plugins and initial conftest files been loaded.
This hook is called for every plugin.
"""
# -------------------------------------------------------------------------
# Bootstrapping hooks called for plugins registered early enough:
# internal and 3rd party plugins as well as directly
# discoverable conftest.py local plugins.
# -------------------------------------------------------------------------
@hookspec(firstresult=True)
def pytest_cmdline_parse(pluginmanager, args):
"""return initialized config object, parsing the specified args. """
def pytest_cmdline_preparse(config, args):
"""(deprecated) modify command line arguments before option parsing. """
@hookspec(firstresult=True)
def pytest_cmdline_main(config):
""" called for performing the main command line action. The default
implementation will invoke the configure hooks and runtest_mainloop. """
pytest_cmdline_main.firstresult = True
def pytest_configure(config):
""" called after command line options have been parsed
and all plugins and initial conftest files been loaded.
"""
def pytest_load_initial_conftests(args, early_config, parser):
""" implements the loading of initial conftest files ahead
of command line option parsing. """
def pytest_unconfigure(config):
""" called before test process is exited. """
def pytest_runtestloop(session):
""" called for performing the main runtest loop
(after collection finished). """
pytest_runtestloop.firstresult = True
# -------------------------------------------------------------------------
# collection hooks
# -------------------------------------------------------------------------
@hookspec(firstresult=True)
def pytest_collection(session):
""" perform the collection protocol for the given session. """
pytest_collection.firstresult = True
def pytest_collection_modifyitems(session, config, items):
""" called after collection has been performed, may filter or re-order
@@ -80,16 +104,16 @@ def pytest_collection_modifyitems(session, config, items):
def pytest_collection_finish(session):
""" called after collection has been performed and modified. """
@hookspec(firstresult=True)
def pytest_ignore_collect(path, config):
""" return True to prevent considering this path for collection.
This hook is consulted for all files and directories prior to calling
more specific hooks.
"""
pytest_ignore_collect.firstresult = True
@hookspec(firstresult=True)
def pytest_collect_directory(path, parent):
""" called before traversing a directory for collection files. """
pytest_collect_directory.firstresult = True
def pytest_collect_file(path, parent):
""" return collection Node or None for the given path. Any new node
@@ -108,29 +132,29 @@ def pytest_collectreport(report):
def pytest_deselected(items):
""" called for test items deselected by keyword. """
@hookspec(firstresult=True)
def pytest_make_collect_report(collector):
""" perform ``collector.collect()`` and return a CollectReport. """
pytest_make_collect_report.firstresult = True
# -------------------------------------------------------------------------
# Python test function related hooks
# -------------------------------------------------------------------------
@hookspec(firstresult=True)
def pytest_pycollect_makemodule(path, parent):
""" return a Module collector or None for the given path.
This hook will be called for each matching test module path.
The pytest_collect_file hook needs to be used if you want to
create test modules for files that do not match as a test module.
"""
pytest_pycollect_makemodule.firstresult = True
@hookspec(firstresult=True)
def pytest_pycollect_makeitem(collector, name, obj):
""" return custom item/collector for a python object in a module, or None. """
pytest_pycollect_makeitem.firstresult = True
@hookspec(firstresult=True)
def pytest_pyfunc_call(pyfuncitem):
""" call underlying test function. """
pytest_pyfunc_call.firstresult = True
def pytest_generate_tests(metafunc):
""" generate (multiple) parametrized calls to a test function."""
@@ -138,9 +162,16 @@ def pytest_generate_tests(metafunc):
# -------------------------------------------------------------------------
# generic runtest related hooks
# -------------------------------------------------------------------------
def pytest_itemstart(item, node=None):
@hookspec(firstresult=True)
def pytest_runtestloop(session):
""" called for performing the main runtest loop
(after collection finished). """
def pytest_itemstart(item, node):
""" (deprecated, use pytest_runtest_logstart). """
@hookspec(firstresult=True)
def pytest_runtest_protocol(item, nextitem):
""" implements the runtest_setup/call/teardown protocol for
the given test item, including capturing exceptions and calling
@@ -148,13 +179,12 @@ def pytest_runtest_protocol(item, nextitem):
:arg item: test item for which the runtest protocol is performed.
:arg nexitem: the scheduled-to-be-next test item (or None if this
is the end my friend). This argument is passed on to
:py:func:`pytest_runtest_teardown`.
:arg nextitem: the scheduled-to-be-next test item (or None if this
is the end my friend). This argument is passed on to
:py:func:`pytest_runtest_teardown`.
:return boolean: True if no further hook implementations should be invoked.
"""
pytest_runtest_protocol.firstresult = True
def pytest_runtest_logstart(nodeid, location):
""" signal the start of running a single test item. """
@@ -168,18 +198,18 @@ def pytest_runtest_call(item):
def pytest_runtest_teardown(item, nextitem):
""" called after ``pytest_runtest_call``.
:arg nexitem: the scheduled-to-be-next test item (None if no further
test item is scheduled). This argument can be used to
perform exact teardowns, i.e. calling just enough finalizers
so that nextitem only needs to call setup-functions.
:arg nextitem: the scheduled-to-be-next test item (None if no further
test item is scheduled). This argument can be used to
perform exact teardowns, i.e. calling just enough finalizers
so that nextitem only needs to call setup-functions.
"""
@hookspec(firstresult=True)
def pytest_runtest_makereport(item, call):
""" return a :py:class:`_pytest.runner.TestReport` object
for the given :py:class:`pytest.Item` and
:py:class:`_pytest.runner.CallInfo`.
"""
pytest_runtest_makereport.firstresult = True
def pytest_runtest_logreport(report):
""" process a test setup/call/teardown report relating to
@@ -195,6 +225,9 @@ def pytest_sessionstart(session):
def pytest_sessionfinish(session, exitstatus):
""" whole test run finishes. """
def pytest_unconfigure(config):
""" called before test process is exited. """
# -------------------------------------------------------------------------
# hooks for customising the assert methods
@@ -216,33 +249,46 @@ def pytest_assertrepr_compare(config, op, left, right):
def pytest_report_header(config, startdir):
""" return a string to be displayed as header info for terminal reporting."""
@hookspec(firstresult=True)
def pytest_report_teststatus(report):
""" return result-category, shortletter and verbose word for reporting."""
pytest_report_teststatus.firstresult = True
def pytest_terminal_summary(terminalreporter):
""" add additional section in terminal summary reporting. """
""" add additional section in terminal summary reporting. """
@hookspec(historic=True)
def pytest_logwarning(message, code, nodeid, fslocation):
""" process a warning specified by a message, a code string,
a nodeid and fslocation (both of which may be None
if the warning is not tied to a partilar node/location)."""
# -------------------------------------------------------------------------
# doctest hooks
# -------------------------------------------------------------------------
@hookspec(firstresult=True)
def pytest_doctest_prepare_content(content):
""" return processed content for a given doctest"""
pytest_doctest_prepare_content.firstresult = True
# -------------------------------------------------------------------------
# error handling and internal debugging hooks
# -------------------------------------------------------------------------
def pytest_plugin_registered(plugin, manager):
""" a new py lib plugin got registered. """
def pytest_plugin_unregistered(plugin):
""" a py lib plugin got unregistered. """
def pytest_internalerror(excrepr):
def pytest_internalerror(excrepr, excinfo):
""" called for internal errors. """
def pytest_keyboard_interrupt(excinfo):
""" called for keyboard interrupt. """
def pytest_exception_interact(node, call, report):
""" (experimental, new in 2.4) called when
an exception was raised which can potentially be
interactively handled.
This hook is only called if an exception was raised
that is not an internal exception like "skip.Exception".
"""
def pytest_enter_pdb():
""" called upon pdb.set_trace()"""

View File

@@ -1,30 +1,24 @@
""" report test results in JUnit-XML format, for use with Hudson and build integration servers.
Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
Based on initial code from Ross Lawley.
"""
import py
import os
import re
import sys
import time
import pytest
# Python 2.X and 3.X compatibility
try:
unichr(65)
except NameError:
if sys.version_info[0] < 3:
from codecs import open
else:
unichr = chr
try:
unicode('A')
except NameError:
unicode = str
try:
long(1)
except NameError:
long = int
class Junit(py.xml.Namespace):
pass
@@ -36,7 +30,8 @@ class Junit(py.xml.Namespace):
# | [#x10000-#x10FFFF]
_legal_chars = (0x09, 0x0A, 0x0d)
_legal_ranges = (
(0x20, 0xD7FF),
(0x20, 0x7E),
(0x80, 0xD7FF),
(0xE000, 0xFFFD),
(0x10000, 0x10FFFF),
)
@@ -59,12 +54,26 @@ def bin_xml_escape(arg):
return unicode('#x%04X') % i
return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(arg)))
@pytest.fixture
def record_xml_property(request):
"""Fixture that adds extra xml properties to the tag for the calling test.
The fixture is callable with (name, value), with value being automatically
xml-encoded.
"""
def inner(name, value):
if hasattr(request.config, "_xml"):
request.config._xml.add_custom_property(name, value)
msg = 'record_xml_property is an experimental feature'
request.config.warn(code='C3', message=msg,
fslocation=request.node.location[:2])
return inner
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group.addoption('--junitxml', action="store", dest="xmlpath",
metavar="path", default=None,
group.addoption('--junitxml', '--junit-xml', action="store",
dest="xmlpath", metavar="path", default=None,
help="create junit-xml style report file at given path.")
group.addoption('--junitprefix', action="store", dest="junitprefix",
group.addoption('--junitprefix', '--junit-prefix', action="store",
metavar="str", default=None,
help="prepend prefix to classnames in junit-xml output")
@@ -81,7 +90,6 @@ def pytest_unconfigure(config):
del config._xml
config.pluginmanager.unregister(xml)
def mangle_testnames(names):
names = [x.replace(".py", "") for x in names if x != '()']
names[0] = names[0].replace("/", '.')
@@ -93,31 +101,63 @@ class LogXML(object):
self.logfile = os.path.normpath(os.path.abspath(logfile))
self.prefix = prefix
self.tests = []
self.tests_by_nodeid = {} # nodeid -> Junit.testcase
self.durations = {} # nodeid -> total duration (setup+call+teardown)
self.passed = self.skipped = 0
self.failed = self.errors = 0
self.custom_properties = {}
def add_custom_property(self, name, value):
self.custom_properties[str(name)] = bin_xml_escape(str(value))
def _opentestcase(self, report):
names = mangle_testnames(report.nodeid.split("::"))
classnames = names[:-1]
if self.prefix:
classnames.insert(0, self.prefix)
self.tests.append(Junit.testcase(
classname=".".join(classnames),
name=names[-1],
time=getattr(report, 'duration', 0)
))
attrs = {
"classname": ".".join(classnames),
"name": bin_xml_escape(names[-1]),
"file": report.location[0],
"time": self.durations.get(report.nodeid, 0),
}
if report.location[1] is not None:
attrs["line"] = report.location[1]
testcase = Junit.testcase(**attrs)
custom_properties = self.pop_custom_properties()
if custom_properties:
testcase.append(custom_properties)
self.tests.append(testcase)
self.tests_by_nodeid[report.nodeid] = testcase
def _write_captured_output(self, report):
sec = dict(report.sections)
for name in ('out', 'err'):
content = sec.get("Captured std%s" % name)
if content:
tag = getattr(Junit, 'system-'+name)
self.append(tag(bin_xml_escape(content)))
for capname in ('out', 'err'):
allcontent = ""
for name, content in report.get_sections("Captured std%s" %
capname):
allcontent += content
if allcontent:
tag = getattr(Junit, 'system-'+capname)
self.append(tag(bin_xml_escape(allcontent)))
def append(self, obj):
self.tests[-1].append(obj)
def pop_custom_properties(self):
"""Return a Junit node containing custom properties set for
the current test, if any, and reset the current custom properties.
"""
if self.custom_properties:
result = Junit.properties(
[
Junit.property(name=name, value=value)
for name, value in self.custom_properties.items()
]
)
self.custom_properties.clear()
return result
return None
def append_pass(self, report):
self.passed += 1
self._write_captured_output(report)
@@ -129,39 +169,46 @@ class LogXML(object):
Junit.skipped(message="xfail-marked test passes unexpectedly"))
self.skipped += 1
else:
fail = Junit.failure(message="test failure")
fail.append(str(report.longrepr))
if hasattr(report.longrepr, "reprcrash"):
message = report.longrepr.reprcrash.message
elif isinstance(report.longrepr, (unicode, str)):
message = report.longrepr
else:
message = str(report.longrepr)
message = bin_xml_escape(message)
fail = Junit.failure(message=message)
fail.append(bin_xml_escape(report.longrepr))
self.append(fail)
self.failed += 1
self._write_captured_output(report)
def append_collect_failure(self, report):
def append_collect_error(self, report):
#msg = str(report.longrepr.reprtraceback.extraline)
self.append(Junit.failure(str(report.longrepr),
message="collection failure"))
self.append(Junit.error(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,
Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason),
type="pytest.skip",
message=skipreason
))
@@ -169,8 +216,30 @@ class LogXML(object):
self._write_captured_output(report)
def pytest_runtest_logreport(self, report):
"""handle a setup/call/teardown report, generating the appropriate
xml tags as necessary.
note: due to plugins like xdist, this hook may be called in interlaced
order with reports from other nodes. for example:
usual call order:
-> setup node1
-> call node1
-> teardown node1
-> setup node2
-> call node2
-> teardown node2
possible call order in xdist:
-> setup node1
-> call node1
-> setup node2
-> call node2
-> teardown node2
-> teardown node1
"""
if report.passed:
if report.when == "call": # ignore setup/teardown
if report.when == "call": # ignore setup/teardown
self._opentestcase(report)
self.append_pass(report)
elif report.failed:
@@ -182,33 +251,45 @@ class LogXML(object):
elif report.skipped:
self._opentestcase(report)
self.append_skipped(report)
self.update_testcase_duration(report)
def update_testcase_duration(self, report):
"""accumulates total duration for nodeid from given report and updates
the Junit.testcase with the new total if already created.
"""
total = self.durations.get(report.nodeid, 0.0)
total += getattr(report, 'duration', 0.0)
self.durations[report.nodeid] = total
testcase = self.tests_by_nodeid.get(report.nodeid)
if testcase is not None:
testcase.attr.time = total
def pytest_collectreport(self, report):
if not report.passed:
self._opentestcase(report)
if report.failed:
self.append_collect_failure(report)
self.append_collect_error(report)
else:
self.append_collect_skipped(report)
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__):
if py.std.sys.version_info[0] < 3:
logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8')
else:
logfile = open(self.logfile, 'w', encoding='utf-8')
def pytest_sessionfinish(self):
dirname = os.path.dirname(os.path.abspath(self.logfile))
if not os.path.isdir(dirname):
os.makedirs(dirname)
logfile = open(self.logfile, 'w', encoding='utf-8')
suite_stop_time = time.time()
suite_time_delta = suite_stop_time - self.suite_start_time
numtests = self.passed + self.failed
@@ -216,7 +297,7 @@ class LogXML(object):
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
logfile.write(Junit.testsuite(
self.tests,
name="",
name="pytest",
errors=self.errors,
failures=self.failed,
skips=self.skipped,

View File

@@ -1,15 +1,15 @@
""" core implementation of testing process: init, session, runtest loop. """
import re
import py
import pytest, _pytest
import inspect
import os, sys, imp
try:
from collections import MutableMapping as MappingMixin
except ImportError:
from UserDict import DictMixin as MappingMixin
from _pytest.mark import MarkInfo
from _pytest.runner import collect_one_node
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
@@ -19,12 +19,15 @@ EXIT_TESTSFAILED = 1
EXIT_INTERRUPTED = 2
EXIT_INTERNALERROR = 3
EXIT_USAGEERROR = 4
EXIT_NOTESTSCOLLECTED = 5
name_re = py.std.re.compile("^[a-zA-Z_]\w*$")
name_re = re.compile("^[a-zA-Z_]\w*$")
def pytest_addoption(parser):
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
type="args", default=('.*', 'CVS', '_darcs', '{arch}'))
type="args", default=['.*', 'CVS', '_darcs', '{arch}', '*.egg'])
parser.addini("testpaths", "directories to search for tests when no files or directories are given in the command line.",
type="args", default=[])
#parser.addini("dirpatterns",
# "patterns specifying possible locations of test files",
# type="linelist", default=["**/test_*.txt",
@@ -35,22 +38,28 @@ def pytest_addoption(parser):
dest="exitfirst",
help="exit instantly on first error or failed test."),
group._addoption('--maxfail', metavar="num",
action="store", type="int", dest="maxfail", default=0,
action="store", type=int, dest="maxfail", default=0,
help="exit after first num failures or errors.")
group._addoption('--strict', action="store_true",
help="run pytest in strict mode, warnings become errors.")
group._addoption("-c", metavar="file", type=str, dest="inifilename",
help="load configuration from `file` instead of trying to locate one of the implicit configuration files.")
group = parser.getgroup("collect", "collection")
group.addoption('--collectonly',
action="store_true", dest="collectonly",
group.addoption('--collectonly', '--collect-only', action="store_true",
help="only collect tests, don't execute them."),
group.addoption('--pyargs', action="store_true",
help="try to interpret all arguments as python packages.")
group.addoption("--ignore", action="append", metavar="path",
help="ignore path during collection (multi-allowed).")
# when changing this to --conf-cut-dir, config.py Conftest.setinitial
# needs upgrading as well
group.addoption('--confcutdir', dest="confcutdir", default=None,
metavar="dir",
help="only load conftest.py's relative to specified dir.")
group.addoption('--noconftest', action="store_true",
dest="noconftest", default=False,
help="Don't load any conftest.py files.")
group = parser.getgroup("debugconfig",
"test session debugging and configuration")
@@ -63,7 +72,7 @@ def pytest_namespace():
return dict(collect=collect)
def pytest_configure(config):
py.test.config = config # compatibiltiy
pytest.config = config # compatibiltiy
if config.option.exitfirst:
config.option.maxfail = 1
@@ -74,35 +83,32 @@ def wrap_session(config, doit):
initstate = 0
try:
try:
config.pluginmanager.do_configure(config)
config._do_configure()
initstate = 1
config.hook.pytest_sessionstart(session=session)
initstate = 2
doit(config, session)
session.exitstatus = doit(config, session) or 0
except pytest.UsageError:
msg = sys.exc_info()[1].args[0]
sys.stderr.write("ERROR: %s\n" %(msg,))
session.exitstatus = EXIT_USAGEERROR
raise
except KeyboardInterrupt:
excinfo = py.code.ExceptionInfo()
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
session.exitstatus = EXIT_INTERRUPTED
except:
excinfo = py.code.ExceptionInfo()
config.pluginmanager.notify_exception(excinfo, config.option)
config.notify_exception(excinfo, config.option)
session.exitstatus = EXIT_INTERNALERROR
if excinfo.errisinstance(SystemExit):
sys.stderr.write("mainloop: caught Spurious SystemExit!\n")
else:
if session._testsfailed:
session.exitstatus = EXIT_TESTSFAILED
finally:
excinfo = None # Explicitly break reference cycle.
session.startdir.chdir()
if initstate >= 2:
config.hook.pytest_sessionfinish(
session=session,
exitstatus=session.exitstatus)
if initstate >= 1:
config.pluginmanager.do_unconfigure(config)
config._ensure_unconfigure()
return session.exitstatus
def pytest_cmdline_main(config):
@@ -114,6 +120,11 @@ def _main(config, session):
config.hook.pytest_collection(session=session)
config.hook.pytest_runtestloop(session=session)
if session.testsfailed:
return EXIT_TESTSFAILED
elif session.testscollected == 0:
return EXIT_NOTESTSCOLLECTED
def pytest_collection(session):
return session.perform_collect()
@@ -141,23 +152,21 @@ def pytest_ignore_collect(path, config):
p = path.dirpath()
ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
ignore_paths = ignore_paths or []
excludeopt = config.getvalue("ignore")
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend([py.path.local(x) for x in excludeopt])
return path in ignore_paths
class HookProxy:
def __init__(self, fspath, config):
class FSHookProxy:
def __init__(self, fspath, pm, remove_mods):
self.fspath = fspath
self.config = config
self.pm = pm
self.remove_mods = remove_mods
def __getattr__(self, name):
hookmethod = getattr(self.config.hook, name)
def call_matching_hooks(**kwargs):
plugins = self.config._getmatchingplugins(self.fspath)
return hookmethod.pcall(plugins, **kwargs)
return call_matching_hooks
x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods)
self.__dict__[name] = x
return x
def compatproperty(name):
def fget(self):
@@ -168,30 +177,39 @@ def compatproperty(name):
class NodeKeywords(MappingMixin):
def __init__(self, node):
parent = node.parent
bases = parent and (parent.keywords._markers,) or ()
self._markers = type("dynmarker", bases, {node.name: True})
self.node = node
self.parent = node.parent
self._markers = {node.name: True}
def __getitem__(self, key):
try:
return getattr(self._markers, key)
except AttributeError:
raise KeyError(key)
return self._markers[key]
except KeyError:
if self.parent is None:
raise
return self.parent.keywords[key]
def __setitem__(self, key, value):
setattr(self._markers, key, value)
self._markers[key] = value
def __delitem__(self, key):
delattr(self._markers, key)
raise ValueError("cannot delete key in keywords dict")
def __iter__(self):
return iter(self.keys())
seen = set(self._markers)
if self.parent is not None:
seen.update(self.parent.keywords)
return iter(seen)
def __len__(self):
return len(self.keys())
return len(self.__iter__())
def keys(self):
return dir(self._markers)
return list(self)
def __repr__(self):
return "<NodeKeywords for node %s>" % (self.node, )
class Node(object):
""" base class for Collector and Item the test collection tree.
@@ -216,6 +234,12 @@ class Node(object):
#: keywords/markers collected from all scopes
self.keywords = NodeKeywords(self)
#: 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
@@ -246,6 +270,20 @@ class Node(object):
return "<%s %r>" %(self.__class__.__name__,
getattr(self, 'name', None))
def warn(self, code, message):
""" generate a warning with the given code and message for this
item. """
assert isinstance(code, str)
fslocation = getattr(self, "location", None)
if fslocation is None:
fslocation = getattr(self, "fspath", None)
else:
fslocation = "%s:%s" % fslocation[:2]
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
code=code, message=message,
nodeid=self.nodeid, fslocation=fslocation))
# methods for ordering nodes
@property
def nodeid(self):
@@ -256,21 +294,11 @@ class Node(object):
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
@@ -290,7 +318,7 @@ class Node(object):
except py.builtin._sysex:
raise
except:
failure = py.std.sys.exc_info()
failure = sys.exc_info()
setattr(self, exattrname, failure)
raise
setattr(self, attrname, res)
@@ -307,13 +335,49 @@ class Node(object):
chain.reverse()
return chain
def add_marker(self, marker):
""" dynamically add a marker object to the node.
``marker`` can be a string or pytest.mark.* instance.
"""
from _pytest.mark import MarkDecorator
if isinstance(marker, py.builtin._basestring):
marker = MarkDecorator(marker)
elif not isinstance(marker, MarkDecorator):
raise ValueError("is not a string or pytest.mark.* Marker")
self.keywords[marker.name] = marker
def get_marker(self, name):
""" get a marker object from this node or None if
the node doesn't have a marker with that name. """
val = self.keywords.get(name, None)
if val is not None:
from _pytest.mark import MarkInfo, MarkDecorator
if isinstance(val, (MarkDecorator, MarkInfo)):
return val
def listextrakeywords(self):
""" Return a set of all extra keywords in self and any parents."""
extra_keywords = set()
item = self
for item in self.listchain():
extra_keywords.update(item.extra_keyword_matches)
return extra_keywords
def listnames(self):
return [x.name for x in self.listchain()]
def getplugins(self):
return self.config._getmatchingplugins(self.fspath)
def addfinalizer(self, fin):
""" register a function to be called when this node is finalized.
This method can only be called when this node is active
in a setup chain, for example during self.setup().
"""
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
@@ -326,20 +390,24 @@ class Node(object):
fm = self.session._fixturemanager
if excinfo.errisinstance(fm.FixtureLookupError):
return excinfo.value.formatrepr()
tbfilter = True
if self.config.option.fulltrace:
style="long"
else:
self._prunetraceback(excinfo)
# XXX should excinfo.getrepr record all data and toterminal()
# process it?
tbfilter = False # prunetraceback already does it
if style == "auto":
style = "long"
# XXX should excinfo.getrepr record all data and toterminal() process it?
if style is None:
if self.config.option.tbstyle == "short":
style = "short"
else:
style = "long"
return excinfo.getrepr(funcargs=True,
showlocals=self.config.option.showlocals,
style=style)
style=style, tbfilter=tbfilter)
repr_failure = _repr_failure_py
@@ -347,6 +415,7 @@ class Collector(Node):
""" Collector instances create children through collect()
and thus iteratively build a tree.
"""
class CollectError(Exception):
""" an error during collection, contains a custom message. """
@@ -369,7 +438,6 @@ class Collector(Node):
def _prunetraceback(self, excinfo):
if hasattr(self, 'fspath'):
path = self.fspath
traceback = excinfo.traceback
ntraceback = traceback.cut(path=self.fspath)
if ntraceback == traceback:
@@ -389,9 +457,7 @@ class FSCollector(Collector):
self.fspath = fspath
def _makeid(self):
if self == self.session:
return "."
relpath = self.session.fspath.bestrelpath(self.fspath)
relpath = self.fspath.relto(self.config.rootdir)
if os.sep != "/":
relpath = relpath.replace(os.sep, "/")
return relpath
@@ -405,6 +471,14 @@ class Item(Node):
"""
nextitem = None
def __init__(self, name, parent=None, config=None, session=None):
super(Item, self).__init__(name, parent, config, session)
self._report_sections = []
def add_report_section(self, when, key, content):
if content:
self._report_sections.append((when, key, content))
def reportinfo(self):
return self.fspath, None, ""
@@ -428,38 +502,64 @@ class Item(Node):
class NoMatch(Exception):
""" raised if matching cannot locate a matching names. """
class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """
__module__ = 'builtins' # for py3
class Session(FSCollector):
class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """
__module__ = 'builtins' # for py3
Interrupted = Interrupted
def __init__(self, config):
FSCollector.__init__(self, py.path.local(), parent=None,
FSCollector.__init__(self, config.rootdir, parent=None,
config=config, session=self)
self.config.pluginmanager.register(self, name="session", prepend=True)
self._testsfailed = 0
self._fs2hookproxy = {}
self.testsfailed = 0
self.testscollected = 0
self.shouldstop = False
self.trace = config.trace.root.get("collection")
self._norecursepatterns = config.getini("norecursedirs")
self.startdir = py.path.local()
self.config.pluginmanager.register(self, name="session")
def _makeid(self):
return ""
@pytest.hookimpl(tryfirst=True)
def pytest_collectstart(self):
if self.shouldstop:
raise self.Interrupted(self.shouldstop)
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logreport(self, report):
if report.failed and not hasattr(report, 'wasxfail'):
self._testsfailed += 1
self.testsfailed += 1
maxfail = self.config.getvalue("maxfail")
if maxfail and self._testsfailed >= maxfail:
if maxfail and self.testsfailed >= maxfail:
self.shouldstop = "stopping after %d failures" % (
self._testsfailed)
self.testsfailed)
pytest_collectreport = pytest_runtest_logreport
def isinitpath(self, path):
return path in self._initialpaths
def gethookproxy(self, fspath):
return HookProxy(fspath, self.config)
try:
return self._fs2hookproxy[fspath]
except KeyError:
# check if we have the common case of running
# hooks with all conftest.py filesall conftest.py
pm = self.config.pluginmanager
my_conftestmodules = pm._getconftestmodules(fspath)
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)
if remove_mods:
# one or more conftests are not in use at this fspath
proxy = FSHookProxy(fspath, pm, remove_mods)
else:
# all plugis are active for this fspath
proxy = self.config.hook
self._fs2hookproxy[fspath] = proxy
return proxy
def perform_collect(self, args=None, genitems=True):
hook = self.config.hook
@@ -469,6 +569,7 @@ class Session(FSCollector):
config=self.config, items=items)
finally:
hook.pytest_collection_finish(session=self)
self.testscollected = len(items)
return items
def _perform_collect(self, args, genitems):
@@ -484,14 +585,16 @@ class Session(FSCollector):
parts = self._parsearg(arg)
self._initialparts.append(parts)
self._initialpaths.add(parts[0])
self.ihook.pytest_collectstart(collector=self)
rep = self.ihook.pytest_make_collect_report(collector=self)
rep = collect_one_node(self)
self.ihook.pytest_collectreport(report=rep)
self.trace.root.indent -= 1
if self._notfound:
errors = []
for arg, exc in self._notfound:
line = "(no name %r in any of %r)" % (arg, exc.args[0])
raise pytest.UsageError("not found: %s\n%s" %(arg, line))
errors.append("not found: %s\n%s" % (arg, line))
#XXX: test this
raise pytest.UsageError(*errors)
if not genitems:
return rep.result
else:
@@ -512,8 +615,7 @@ class Session(FSCollector):
# we are inside a make_report hook so
# we cannot directly pass through the exception
self._notfound.append((arg, sys.exc_info()[1]))
self.trace.root.indent -= 1
break
self.trace.root.indent -= 1
def _collect(self, arg):
@@ -580,7 +682,7 @@ class Session(FSCollector):
arg = self._tryconvertpyarg(arg)
parts = str(arg).split("::")
relpath = parts[0].replace("/", os.sep)
path = self.fspath.join(relpath, abs=True)
path = self.config.invocation_dir.join(relpath, abs=True)
if not path.check():
if self.config.option.pyargs:
msg = "file or package not found: "
@@ -614,8 +716,7 @@ class Session(FSCollector):
resultnodes.append(node)
continue
assert isinstance(node, pytest.Collector)
node.ihook.pytest_collectstart(collector=node)
rep = node.ihook.pytest_make_collect_report(collector=node)
rep = collect_one_node(node)
if rep.passed:
has_matched = False
for x in rep.result:
@@ -636,19 +737,9 @@ class Session(FSCollector):
yield node
else:
assert isinstance(node, pytest.Collector)
node.ihook.pytest_collectstart(collector=node)
rep = node.ihook.pytest_make_collect_report(collector=node)
rep = collect_one_node(node)
if rep.passed:
for subnode in rep.result:
for x in self.genitems(subnode):
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

View File

@@ -1,49 +1,72 @@
""" generic mechanism for marking and selecting python functions. """
import pytest, py
import inspect
class MarkerError(Exception):
"""Error in use of a pytest marker/attribute."""
def pytest_namespace():
return {'mark': MarkGenerator()}
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('-k',
group._addoption(
'-k',
action="store", dest="keyword", default='', metavar="EXPRESSION",
help="only run tests which match the given substring expression. "
"An expression is a python evaluatable expression "
"where all names are substring-matched against test names "
"and keywords. Example: -k 'test_method or test_other' "
"matches all test functions whose name contains "
"'test_method' or 'test_other'.")
"and their parent classes. Example: -k 'test_method or test "
"other' matches all test functions and classes whose name "
"contains 'test_method' or 'test_other'. "
"Additionally keywords are matched to classes and functions "
"containing extra names in their 'extra_keyword_matches' set, "
"as well as functions which have names assigned directly to them."
)
group._addoption("-m",
group._addoption(
"-m",
action="store", dest="markexpr", default="", metavar="MARKEXPR",
help="only run tests matching given mark expression. "
"example: -m 'mark1 and not mark2'."
)
)
group.addoption("--markers", action="store_true", help=
"show markers (builtin, plugin and per-project ones).")
group.addoption(
"--markers", action="store_true",
help="show markers (builtin, plugin and per-project ones)."
)
parser.addini("markers", "markers for test functions", 'linelist')
def pytest_cmdline_main(config):
import _pytest.config
if config.option.markers:
config.pluginmanager.do_configure(config)
tw = py.io.TerminalWriter()
config._do_configure()
tw = _pytest.config.create_terminal_writer(config)
for line in config.getini("markers"):
name, rest = line.split(":", 1)
tw.write("@pytest.mark.%s:" % name, bold=True)
tw.write("@pytest.mark.%s:" % name, bold=True)
tw.line(rest)
tw.line()
config.pluginmanager.do_unconfigure(config)
config._ensure_unconfigure()
return 0
pytest_cmdline_main.tryfirst = True
def pytest_collection_modifyitems(items, config):
keywordexpr = config.option.keyword
matchexpr = config.option.markexpr
if not keywordexpr and not matchexpr:
return
# pytest used to allow "-" for negating
# but today we just allow "-" at the beginning, use "not" instead
# we probably remove "-" alltogether soon
if keywordexpr.startswith("-"):
keywordexpr = "not " + keywordexpr[1:]
selectuntil = False
if keywordexpr[-1:] == ":":
selectuntil = True
@@ -67,38 +90,87 @@ def pytest_collection_modifyitems(items, config):
config.hook.pytest_deselected(items=deselected)
items[:] = remaining
class BoolDict:
def __init__(self, mydict):
self._mydict = mydict
def __getitem__(self, name):
return name in self._mydict
class SubstringDict:
def __init__(self, mydict):
self._mydict = mydict
class MarkMapping:
"""Provides a local mapping for markers where item access
resolves to True if the marker is present. """
def __init__(self, keywords):
mymarks = set()
for key, value in keywords.items():
if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
mymarks.add(key)
self._mymarks = mymarks
def __getitem__(self, name):
for key in self._mydict:
if name in key:
return name in self._mymarks
class KeywordMapping:
"""Provides a local mapping for keywords.
Given a list of names, map any substring of one of these names to True.
"""
def __init__(self, names):
self._names = names
def __getitem__(self, subname):
for name in self._names:
if subname in name:
return True
return False
def matchmark(colitem, matchexpr):
return eval(matchexpr, {}, BoolDict(colitem.keywords))
def matchmark(colitem, markexpr):
"""Tries to match on any marker names, attached to the given colitem."""
return eval(markexpr, {}, MarkMapping(colitem.keywords))
def matchkeyword(colitem, keywordexpr):
keywordexpr = keywordexpr.replace("-", "not ")
return eval(keywordexpr, {}, SubstringDict(colitem.keywords))
"""Tries to match given keyword expression to given collector item.
Will match on the name of colitem, including the names of its parents.
Only matches names of items which are either a :class:`Class` or a
:class:`Function`.
Additionally, matches on names in the 'extra_keyword_matches' set of
any item, as well as names directly assigned to test functions.
"""
mapped_names = set()
# Add the names of the current item and any parent items
import pytest
for item in colitem.listchain():
if not isinstance(item, pytest.Instance):
mapped_names.add(item.name)
# Add the names added as extra keywords to current or parent items
for name in colitem.listextrakeywords():
mapped_names.add(name)
# Add the names attached to the current function through direct assignment
if hasattr(colitem, 'function'):
for name in colitem.function.__dict__:
mapped_names.add(name)
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):
import pytest
if config.option.strict:
pytest.mark._config = config
class MarkGenerator:
""" Factory for :class:`MarkDecorator` objects - exposed as
a ``py.test.mark`` singleton instance. Example::
a ``pytest.mark`` singleton instance. Example::
import py
@py.test.mark.slowtest
@pytest.mark.slowtest
def test_function():
pass
@@ -107,7 +179,7 @@ class MarkGenerator:
def __getattr__(self, name):
if name[0] == "_":
raise AttributeError(name)
raise AttributeError("Marker name must NOT start with underscore")
if hasattr(self, '_config'):
self._check(name)
return MarkDecorator(name)
@@ -126,59 +198,90 @@ class MarkGenerator:
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__", "<lambda>") != "<lambda>"
class MarkDecorator:
""" A decorator for test functions and test classes. When applied
it will create :class:`MarkInfo` objects which may be
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
MarkDecorator instances are often created like this::
mark1 = py.test.mark.NAME # simple MarkDecorator
mark2 = py.test.mark.NAME(name1=value) # parametrized MarkDecorator
mark1 = pytest.mark.NAME # simple MarkDecorator
mark2 = pytest.mark.NAME(name1=value) # parametrized MarkDecorator
and can then be applied as decorators to test functions::
@mark2
def test_function():
pass
When a MarkDecorator instance is called it does the following:
1. If called with a single class as its only positional argument and no
additional keyword arguments, it attaches itself to the class so it
gets applied automatically to all test cases found in that class.
2. If called with a single function as its only positional argument and
no additional keyword arguments, it attaches a MarkInfo object to the
function, containing all the arguments already stored internally in
the MarkDecorator.
3. When called in any other case, it performs a 'fake construction' call,
i.e. it returns a new MarkDecorator instance with the original
MarkDecorator's content updated with the arguments passed to this
call.
Note: The rules above prevent MarkDecorator objects from storing only a
single function or class reference as their positional argument with no
additional keyword or positional arguments.
"""
def __init__(self, name, args=None, kwargs=None):
self.markname = name
self.name = name
self.args = args or ()
self.kwargs = kwargs or {}
@property
def markname(self):
return self.name # for backward-compat (2.4.1 had this attr)
def __repr__(self):
d = self.__dict__.copy()
name = d.pop('markname')
return "<MarkDecorator %r %r>" %(name, d)
name = d.pop('name')
return "<MarkDecorator %r %r>" % (name, d)
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
otherwise add *args/**kwargs in-place to mark information. """
if args:
if args and not kwargs:
func = args[0]
if len(args) == 1 and hasattr(func, '__call__') or \
hasattr(func, '__bases__'):
if hasattr(func, '__bases__'):
is_class = inspect.isclass(func)
if len(args) == 1 and (istestfunc(func) or is_class):
if is_class:
if hasattr(func, 'pytestmark'):
l = func.pytestmark
if not isinstance(l, list):
func.pytestmark = [l, self]
else:
l.append(self)
mark_list = func.pytestmark
if not isinstance(mark_list, list):
mark_list = [mark_list]
# always work on a copy to avoid updating pytestmark
# from a superclass by accident
mark_list = mark_list + [self]
func.pytestmark = mark_list
else:
func.pytestmark = [self]
func.pytestmark = [self]
else:
holder = getattr(func, self.markname, None)
holder = getattr(func, self.name, None)
if holder is None:
holder = MarkInfo(self.markname, self.args, self.kwargs)
setattr(func, self.markname, holder)
holder = MarkInfo(
self.name, self.args, self.kwargs
)
setattr(func, self.name, holder)
else:
holder.add(self.args, self.kwargs)
return func
kw = self.kwargs.copy()
kw.update(kwargs)
args = self.args + args
return self.__class__(self.markname, args=args, kwargs=kw)
return self.__class__(self.name, args=args, kwargs=kw)
class MarkInfo:
""" Marking object created by :class:`MarkDecorator` instances. """
@@ -188,12 +291,13 @@ class MarkInfo:
#: positional argument list, empty if none specified
self.args = args
#: keyword argument dictionary, empty if nothing specified
self.kwargs = kwargs
self.kwargs = kwargs.copy()
self._arglist = [(args, kwargs.copy())]
def __repr__(self):
return "<MarkInfo %r args=%r kwargs=%r>" % (
self.name, self.args, self.kwargs)
self.name, self.args, self.kwargs
)
def add(self, args, kwargs):
""" add a MarkInfo with the given args and kwargs. """
@@ -205,4 +309,3 @@ class MarkInfo:
""" yield MarkInfo objects each relating to a marking-call. """
for args, kwargs in self._arglist:
yield MarkInfo(self.name, args, kwargs)

View File

@@ -1,6 +1,7 @@
""" monkeypatching and mocking functionality. """
import os, sys, inspect
import os, sys
from py.builtin import _basestring
def pytest_funcarg__monkeypatch(request):
"""The returned ``monkeypatch`` funcarg provides these
@@ -24,45 +25,128 @@ def pytest_funcarg__monkeypatch(request):
request.addfinalizer(mpatch.undo)
return mpatch
notset = object()
def derive_importpath(import_path, raising):
import pytest
if not isinstance(import_path, _basestring) or "." not in import_path:
raise TypeError("must be absolute import path string, not %r" %
(import_path,))
rest = []
target = import_path
while target:
try:
obj = __import__(target, None, None, "__doc__")
except ImportError:
if "." not in target:
__tracebackhide__ = True
pytest.fail("could not import any sub part: %s" %
import_path)
target, name = target.rsplit(".", 1)
rest.append(name)
else:
assert rest
try:
while len(rest) > 1:
attr = rest.pop()
obj = getattr(obj, attr)
attr = rest[0]
if raising:
getattr(obj, attr)
except AttributeError:
__tracebackhide__ = True
pytest.fail("object %r has no attribute %r" % (obj, attr))
return attr, obj
class Notset:
def __repr__(self):
return "<notset>"
notset = Notset()
class monkeypatch:
""" object keeping a record of setattr/item/env/syspath changes. """
""" Object keeping a record of setattr/item/env/syspath changes. """
def __init__(self):
self._setattr = []
self._setitem = []
self._cwd = None
self._savesyspath = None
def setattr(self, obj, name, value, raising=True):
""" set attribute ``name`` on ``obj`` to ``value``, by default
raise AttributeEror if the attribute did not exist. """
oldval = getattr(obj, name, notset)
def setattr(self, target, name, value=notset, raising=True):
""" Set attribute value on target, memorizing the old value.
By default raise AttributeError if the attribute did not exist.
For convenience you can specify a string as ``target`` which
will be interpreted as a dotted import path, with the last part
being the attribute name. Example:
``monkeypatch.setattr("os.getcwd", lambda x: "/")``
would set the ``getcwd`` function of the ``os`` module.
The ``raising`` value determines if the setattr should fail
if the attribute is not already present (defaults to True
which means it will raise).
"""
__tracebackhide__ = True
import inspect
if value is notset:
if not isinstance(target, _basestring):
raise TypeError("use setattr(target, name, value) or "
"setattr(target, value) with target being a dotted "
"import string")
value = name
name, target = derive_importpath(target, raising)
oldval = getattr(target, name, notset)
if raising and oldval is notset:
raise AttributeError("%r has no attribute %r" %(obj, name))
raise AttributeError("%r has no attribute %r" %(target, name))
# avoid class descriptors like staticmethod/classmethod
if inspect.isclass(obj):
oldval = obj.__dict__.get(name, notset)
self._setattr.insert(0, (obj, name, oldval))
setattr(obj, name, value)
if inspect.isclass(target):
oldval = target.__dict__.get(name, notset)
self._setattr.insert(0, (target, name, oldval))
setattr(target, name, value)
def delattr(self, obj, name, raising=True):
""" delete attribute ``name`` from ``obj``, by default raise
AttributeError it the attribute did not previously exist. """
if not hasattr(obj, name):
def delattr(self, target, name=notset, raising=True):
""" Delete attribute ``name`` from ``target``, by default raise
AttributeError it the attribute did not previously exist.
If no ``name`` is specified and ``target`` is a string
it will be interpreted as a dotted import path with the
last part being the attribute name.
If ``raising`` is set to False, no exception will be raised if the
attribute is missing.
"""
__tracebackhide__ = True
if name is notset:
if not isinstance(target, _basestring):
raise TypeError("use delattr(target, name) or "
"delattr(target) with target being a dotted "
"import string")
name, target = derive_importpath(target, raising)
if not hasattr(target, name):
if raising:
raise AttributeError(name)
else:
self._setattr.insert(0, (obj, name, getattr(obj, name, notset)))
delattr(obj, name)
self._setattr.insert(0, (target, name,
getattr(target, name, notset)))
delattr(target, name)
def setitem(self, dic, name, value):
""" set dictionary entry ``name`` to value. """
""" Set dictionary entry ``name`` to value. """
self._setitem.insert(0, (dic, name, dic.get(name, notset)))
dic[name] = value
def delitem(self, dic, name, raising=True):
""" delete ``name`` from dict, raise KeyError if it doesn't exist."""
""" Delete ``name`` from dict. Raise KeyError if it doesn't exist.
If ``raising`` is set to False, no exception will be raised if the
key is missing.
"""
if name not in dic:
if raising:
raise KeyError(name)
@@ -71,7 +155,7 @@ class monkeypatch:
del dic[name]
def setenv(self, name, value, prepend=None):
""" set environment variable ``name`` to ``value``. if ``prepend``
""" Set environment variable ``name`` to ``value``. If ``prepend``
is a character, read the current environment variable value
and prepend the ``value`` adjoined with the ``prepend`` character."""
value = str(value)
@@ -80,18 +164,23 @@ class monkeypatch:
self.setitem(os.environ, name, value)
def delenv(self, name, raising=True):
""" delete ``name`` from environment, raise KeyError it not exists."""
""" Delete ``name`` from the environment. Raise KeyError it does not
exist.
If ``raising`` is set to False, no exception will be raised if the
environment variable is missing.
"""
self.delitem(os.environ, name, raising=raising)
def syspath_prepend(self, path):
""" prepend ``path`` to ``sys.path`` list of import locations. """
if not hasattr(self, '_savesyspath'):
""" Prepend ``path`` to ``sys.path`` list of import locations. """
if self._savesyspath is None:
self._savesyspath = sys.path[:]
sys.path.insert(0, str(path))
def chdir(self, path):
""" change the current working directory to the specified path
path can be a string or a py.path.local object
""" Change the current working directory to the specified path.
Path can be a string or a py.path.local object.
"""
if self._cwd is None:
self._cwd = os.getcwd()
@@ -101,9 +190,19 @@ class monkeypatch:
os.chdir(path)
def undo(self):
""" undo previous changes. This call consumes the
undo stack. Calling it a second time has no effect unless
you do more monkeypatching after the undo call."""
""" Undo previous changes. This call consumes the
undo stack. Calling it a second time has no effect unless
you do more monkeypatching after the undo call.
There is generally no need to call `undo()`, since it is
called automatically during tear-down.
Note that the same `monkeypatch` fixture is used across a
single test function invocation. If `monkeypatch` is used both by
the test function itself and one of the test fixtures,
calling `undo()` will undo all of the changes made in
both functions.
"""
for obj, name, value in self._setattr:
if value is not notset:
setattr(obj, name, value)
@@ -119,9 +218,9 @@ class monkeypatch:
else:
dictionary[name] = value
self._setitem[:] = []
if hasattr(self, '_savesyspath'):
if self._savesyspath is not None:
sys.path[:] = self._savesyspath
del self._savesyspath
self._savesyspath = None
if self._cwd is not None:
os.chdir(self._cwd)

View File

@@ -1,21 +1,30 @@
""" run test suites written for nose. """
import pytest, py
import inspect
import sys
import py
import pytest
from _pytest import unittest
def pytest_runtest_makereport(__multicall__, item, call):
SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None)
if SkipTest:
if call.excinfo and call.excinfo.errisinstance(SkipTest):
# let's substitute the excinfo with a py.test.skip one
call2 = call.__class__(lambda: py.test.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo
def get_skip_exceptions():
skip_classes = set()
for module_name in ('unittest', 'unittest2', 'nose'):
mod = sys.modules.get(module_name)
if hasattr(mod, 'SkipTest'):
skip_classes.add(mod.SkipTest)
return tuple(skip_classes)
@pytest.mark.trylast
def pytest_runtest_makereport(item, call):
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
# let's substitute the excinfo with a pytest.skip one
call2 = call.__class__(lambda:
pytest.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo
@pytest.hookimpl(trylast=True)
def pytest_runtest_setup(item):
if is_potential_nosetest(item):
if isinstance(item.parent, pytest.Generator):
@@ -39,6 +48,7 @@ def teardown_nose(item):
# #call_optional(item._nosegensetup, 'teardown')
# del item.parent._nosegensetup
def pytest_make_collect_report(collector):
if isinstance(collector, pytest.Generator):
call_optional(collector.obj, 'setup')

View File

@@ -1,67 +1,88 @@
""" submit failure or test session information to a pastebin service. """
import py, sys
import pytest
import sys
import tempfile
class url:
base = "http://bpaste.net"
xmlrpc = base + "/xmlrpc/"
show = base + "/show/"
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group._addoption('--pastebin', metavar="mode",
action='store', dest="pastebin", default=None,
type="choice", choices=['failed', 'all'],
choices=['failed', 'all'],
help="send failed|all info to bpaste.net pastebin service.")
def pytest_configure(__multicall__, config):
import tempfile
__multicall__.execute()
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
if config.option.pastebin == "all":
config._pastebinfile = tempfile.TemporaryFile('w+')
tr = config.pluginmanager.getplugin('terminalreporter')
oldwrite = tr._tw.write
def tee_write(s, **kwargs):
oldwrite(s, **kwargs)
config._pastebinfile.write(str(s))
tr._tw.write = tee_write
# if no terminal reporter plugin is present, nothing we can do here;
# this can happen when this function executes in a slave node
# when using pytest-xdist, for example
if tr is not None:
config._pastebinfile = tempfile.TemporaryFile('w+')
oldwrite = tr._tw.write
def tee_write(s, **kwargs):
oldwrite(s, **kwargs)
config._pastebinfile.write(str(s))
tr._tw.write = tee_write
def pytest_unconfigure(config):
if hasattr(config, '_pastebinfile'):
# get terminal contents and delete file
config._pastebinfile.seek(0)
sessionlog = config._pastebinfile.read()
config._pastebinfile.close()
del config._pastebinfile
proxyid = getproxy().newPaste("python", sessionlog)
pastebinurl = "%s%s" % (url.show, proxyid)
sys.stderr.write("pastebin session-log: %s\n" % pastebinurl)
# undo our patching in the terminal reporter
tr = config.pluginmanager.getplugin('terminalreporter')
del tr._tw.__dict__['write']
# write summary
tr.write_sep("=", "Sending information to Paste Service")
pastebinurl = create_new_paste(sessionlog)
tr.write_line("pastebin session-log: %s\n" % pastebinurl)
def getproxy():
def create_new_paste(contents):
"""
Creates a new paste using bpaste.net service.
:contents: paste contents
:returns: url to the pasted contents
"""
import re
if sys.version_info < (3, 0):
from xmlrpclib import ServerProxy
from urllib import urlopen, urlencode
else:
from xmlrpc.client import ServerProxy
return ServerProxy(url.xmlrpc).pastes
from urllib.request import urlopen
from urllib.parse import urlencode
params = {
'code': contents,
'lexer': 'python3' if sys.version_info[0] == 3 else 'python',
'expiry': '1week',
}
url = 'https://bpaste.net'
response = urlopen(url, data=urlencode(params)).read()
m = re.search(r'href="/raw/(\w+)"', response)
if m:
return '%s/show/%s' % (url, m.group(1))
else:
return 'bad response: ' + response
def pytest_terminal_summary(terminalreporter):
import _pytest.config
if terminalreporter.config.option.pastebin != "failed":
return
tr = terminalreporter
if 'failed' in tr.stats:
terminalreporter.write_sep("=", "Sending information to Paste Service")
if tr.config.option.debug:
terminalreporter.write_line("xmlrpcurl: %s" %(url.xmlrpc,))
serverproxy = getproxy()
for rep in terminalreporter.stats.get('failed'):
try:
msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc
except AttributeError:
msg = tr._getfailureheadline(rep)
tw = py.io.TerminalWriter(stringio=True)
tw = _pytest.config.create_terminal_writer(terminalreporter.config, stringio=True)
rep.toterminal(tw)
s = tw.stringio.getvalue()
assert len(s)
proxyid = serverproxy.newPaste("python", s)
pastebinurl = "%s%s" % (url.show, proxyid)
pastebinurl = create_new_paste(s)
tr.write_line("%s --> %s" %(msg, pastebinurl))

View File

@@ -1,8 +1,11 @@
""" interactive debugging with PDB, the Python Debugger. """
import pytest, py
from __future__ import absolute_import
import pdb
import sys
import pytest
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--pdb',
@@ -16,67 +19,60 @@ def pytest_configure(config):
if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')
old = (pdb.set_trace, pytestPDB._pluginmanager)
def fin():
pdb.set_trace, pytestPDB._pluginmanager = old
pytestPDB._config = None
pdb.set_trace = pytest.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
config._cleanup.append(fin)
class pytestPDB:
""" Pseudo PDB that defers to the real pdb. """
item = None
collector = None
_pluginmanager = None
_config = None
def set_trace(self):
""" invoke PDB set_trace debugging, dropping any IO capturing. """
import _pytest.config
frame = sys._getframe().f_back
item = self.item or self.collector
if item is not None:
capman = item.config.pluginmanager.getplugin("capturemanager")
out, err = capman.suspendcapture()
if hasattr(item, 'outerr'):
item.outerr = (item.outerr[0] + out, item.outerr[1] + err)
tw = py.io.TerminalWriter()
capman = None
if self._pluginmanager is not None:
capman = self._pluginmanager.getplugin("capturemanager")
if capman:
capman.suspendcapture(in_=True)
tw = _pytest.config.create_terminal_writer(self._config)
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
py.std.pdb.Pdb().set_trace(frame)
self._pluginmanager.hook.pytest_enter_pdb()
pdb.Pdb().set_trace(frame)
def pdbitem(item):
pytestPDB.item = item
pytest_runtest_setup = pytest_runtest_call = pytest_runtest_teardown = pdbitem
@pytest.mark.tryfirst
def pytest_make_collect_report(__multicall__, collector):
try:
pytestPDB.collector = collector
return __multicall__.execute()
finally:
pytestPDB.collector = None
def pytest_runtest_makereport():
pytestPDB.item = None
class PdbInvoke:
@pytest.mark.tryfirst
def pytest_runtest_makereport(self, item, call, __multicall__):
rep = __multicall__.execute()
if not call.excinfo or \
call.excinfo.errisinstance(pytest.skip.Exception) or \
call.excinfo.errisinstance(py.std.bdb.BdbQuit):
return rep
if hasattr(rep, "wasxfail"):
return rep
return _enter_pdb(item, call.excinfo, rep)
def pytest_exception_interact(self, node, call, report):
capman = node.config.pluginmanager.getplugin("capturemanager")
if capman:
capman.suspendcapture(in_=True)
_enter_pdb(node, call.excinfo, report)
def pytest_internalerror(self, excrepr, excinfo):
for line in str(excrepr).split("\n"):
sys.stderr.write("INTERNALERROR> %s\n" %line)
sys.stderr.flush()
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
def _enter_pdb(item, excinfo, rep):
# we assume that the above execute() suspended capturing
def _enter_pdb(node, excinfo, rep):
# XXX we re-use the TerminalReporter's terminalwriter
# because this seems to avoid some encoding related troubles
# for not completely clear reasons.
tw = item.config.pluginmanager.getplugin("terminalreporter")._tw
tw = node.config.pluginmanager.getplugin("terminalreporter")._tw
tw.line()
tw.sep(">", "traceback")
rep.toterminal(tw)
tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
rep._pdbshown = True
@@ -86,7 +82,8 @@ def _enter_pdb(item, excinfo, rep):
def _postmortem_traceback(excinfo):
# A doctest.UnexpectedException is not useful for post_mortem.
# Use the underlying exception instead:
if isinstance(excinfo.value, py.std.doctest.UnexpectedException):
from doctest import UnexpectedException
if isinstance(excinfo.value, UnexpectedException):
return excinfo.value.exc_info[2]
else:
return excinfo._excinfo[2]
@@ -100,7 +97,6 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t):
pdb = py.std.pdb
class Pdb(pdb.Pdb):
def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,99 +1,190 @@
""" recording warnings during test function execution. """
import inspect
import py
import sys, os
import sys
import warnings
import pytest
def pytest_funcarg__recwarn(request):
@pytest.yield_fixture
def recwarn(request):
"""Return a WarningsRecorder instance that provides these methods:
* ``pop(category=None)``: return last warning matching the category.
* ``clear()``: clear list of warnings
See http://docs.python.org/library/warnings.html for information
on warning categories.
"""
if sys.version_info >= (2,7):
import warnings
oldfilters = warnings.filters[:]
warnings.simplefilter('default')
def reset_filters():
warnings.filters[:] = oldfilters
request.addfinalizer(reset_filters)
wrec = WarningsRecorder()
request.addfinalizer(wrec.finalize)
return wrec
with wrec:
warnings.simplefilter('default')
yield wrec
def pytest_namespace():
return {'deprecated_call': deprecated_call}
return {'deprecated_call': deprecated_call,
'warns': warns}
def deprecated_call(func, *args, **kwargs):
""" assert that calling ``func(*args, **kwargs)``
triggers a DeprecationWarning.
"""Assert that ``func(*args, **kwargs)`` triggers a DeprecationWarning.
"""
warningmodule = py.std.warnings
l = []
oldwarn_explicit = getattr(warningmodule, 'warn_explicit')
def warn_explicit(*args, **kwargs):
l.append(args)
oldwarn_explicit(*args, **kwargs)
oldwarn = getattr(warningmodule, 'warn')
def warn(*args, **kwargs):
l.append(args)
oldwarn(*args, **kwargs)
warningmodule.warn_explicit = warn_explicit
warningmodule.warn = warn
try:
wrec = WarningsRecorder()
with wrec:
warnings.simplefilter('always') # ensure all warnings are triggered
ret = func(*args, **kwargs)
finally:
warningmodule.warn_explicit = warn_explicit
warningmodule.warn = warn
if not l:
#print warningmodule
depwarnings = (DeprecationWarning, PendingDeprecationWarning)
if not any(r.category in depwarnings for r in wrec):
__tracebackhide__ = True
raise AssertionError("%r did not produce DeprecationWarning" %(func,))
raise AssertionError("%r did not produce DeprecationWarning" % (func,))
return ret
class RecordedWarning:
def __init__(self, message, category, filename, lineno, line):
def warns(expected_warning, *args, **kwargs):
"""Assert that code raises a particular class of warning.
Specifically, the input @expected_warning can be a warning class or
tuple of warning classes, and the code must return that warning
(if a single class) or one of those warnings (if a tuple).
This helper produces a list of ``warnings.WarningMessage`` objects,
one for each warning raised.
This function can be used as a context manager, or any of the other ways
``pytest.raises`` can be used::
>>> with warns(RuntimeWarning):
... warnings.warn("my warning", RuntimeWarning)
"""
wcheck = WarningsChecker(expected_warning)
if not args:
return wcheck
elif isinstance(args[0], str):
code, = args
assert isinstance(code, str)
frame = sys._getframe(1)
loc = frame.f_locals.copy()
loc.update(kwargs)
with wcheck:
code = py.code.Source(code).compile()
py.builtin.exec_(code, frame.f_globals, loc)
else:
func = args[0]
with wcheck:
return func(*args[1:], **kwargs)
class RecordedWarning(object):
def __init__(self, message, category, filename, lineno, file, line):
self.message = message
self.category = category
self.filename = filename
self.lineno = lineno
self.file = file
self.line = line
class WarningsRecorder:
def __init__(self):
warningmodule = py.std.warnings
self.list = []
def showwarning(message, category, filename, lineno, line=0):
self.list.append(RecordedWarning(
message, category, filename, lineno, line))
try:
self.old_showwarning(message, category,
filename, lineno, line=line)
except TypeError:
# < python2.6
self.old_showwarning(message, category, filename, lineno)
self.old_showwarning = warningmodule.showwarning
warningmodule.showwarning = showwarning
class WarningsRecorder(object):
"""A context manager to record raised warnings.
Adapted from `warnings.catch_warnings`.
"""
def __init__(self, module=None):
self._module = sys.modules['warnings'] if module is None else module
self._entered = False
self._list = []
@property
def list(self):
"""The list of recorded warnings."""
return self._list
def __getitem__(self, i):
"""Get a recorded warning by index."""
return self._list[i]
def __iter__(self):
"""Iterate through the recorded warnings."""
return iter(self._list)
def __len__(self):
"""The number of recorded warnings."""
return len(self._list)
def pop(self, cls=Warning):
""" pop the first recorded warning, raise exception if not exists."""
for i, w in enumerate(self.list):
"""Pop the first recorded warning, raise exception if not exists."""
for i, w in enumerate(self._list):
if issubclass(w.category, cls):
return self.list.pop(i)
return self._list.pop(i)
__tracebackhide__ = True
assert 0, "%r not found in %r" %(cls, self.list)
#def resetregistry(self):
# import warnings
# warnings.onceregistry.clear()
# warnings.__warningregistry__.clear()
raise AssertionError("%r not found in warning list" % cls)
def clear(self):
self.list[:] = []
"""Clear the list of recorded warnings."""
self._list[:] = []
def finalize(self):
py.std.warnings.showwarning = self.old_showwarning
def __enter__(self):
if self._entered:
__tracebackhide__ = True
raise RuntimeError("Cannot enter %r twice" % self)
self._entered = True
self._filters = self._module.filters
self._module.filters = self._filters[:]
self._showwarning = self._module.showwarning
def showwarning(message, category, filename, lineno,
file=None, line=None):
self._list.append(RecordedWarning(
message, category, filename, lineno, file, line))
# still perform old showwarning functionality
self._showwarning(
message, category, filename, lineno, file=file, line=line)
self._module.showwarning = showwarning
# allow the same warning to be raised more than once
self._module.simplefilter('always', append=True)
return self
def __exit__(self, *exc_info):
if not self._entered:
__tracebackhide__ = True
raise RuntimeError("Cannot exit %r without entering first" % self)
self._module.filters = self._filters
self._module.showwarning = self._showwarning
class WarningsChecker(WarningsRecorder):
def __init__(self, expected_warning=None, module=None):
super(WarningsChecker, self).__init__(module=module)
msg = ("exceptions must be old-style classes or "
"derived from Warning, not %s")
if isinstance(expected_warning, tuple):
for exc in expected_warning:
if not inspect.isclass(exc):
raise TypeError(msg % type(exc))
elif inspect.isclass(expected_warning):
expected_warning = (expected_warning,)
elif expected_warning is not None:
raise TypeError(msg % type(expected_warning))
self.expected_warning = expected_warning
def __exit__(self, *exc_info):
super(WarningsChecker, self).__exit__(*exc_info)
# only check if we're not currently handling an exception
if all(a is None for a in exc_info):
if self.expected_warning is not None:
if not any(r.category in self.expected_warning for r in self):
__tracebackhide__ = True
pytest.fail("DID NOT WARN")

View File

@@ -3,10 +3,11 @@ text file.
"""
import py
import os
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "resultlog plugin options")
group.addoption('--resultlog', action="store", dest="resultlog",
group.addoption('--resultlog', '--result-log', action="store",
metavar="path", default=None,
help="path for machine-readable result log.")
@@ -14,6 +15,9 @@ def pytest_configure(config):
resultlog = config.option.resultlog
# prevent opening resultlog on slave nodes (xdist)
if resultlog and not hasattr(config, 'slaveinput'):
dirname = os.path.dirname(os.path.abspath(resultlog))
if not os.path.isdir(dirname):
os.makedirs(dirname)
logfile = open(resultlog, 'w', 1) # line buffered
config._resultlog = ResultLog(config, logfile)
config.pluginmanager.register(config._resultlog)
@@ -85,7 +89,7 @@ class ResultLog(object):
if not report.passed:
if report.failed:
code = "F"
longrepr = str(report.longrepr.reprcrash)
longrepr = str(report.longrepr)
else:
assert report.skipped
code = "S"

View File

@@ -1,7 +1,10 @@
""" basic collect and runtest protocol implementations """
import py, sys
import bdb
import sys
from time import time
import py
import pytest
from py._code.code import TerminalRepr
def pytest_namespace():
@@ -18,7 +21,7 @@ def pytest_namespace():
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group.addoption('--durations',
action="store", type="int", default=None, metavar="N",
action="store", type=int, default=None, metavar="N",
help="show N slowest setup/test durations (N=0 for all)."),
def pytest_terminal_summary(terminalreporter):
@@ -83,7 +86,17 @@ def pytest_runtest_setup(item):
item.session._setupstate.prepare(item)
def pytest_runtest_call(item):
item.runtest()
try:
item.runtest()
except Exception:
# Store trace info to allow postmortem debugging
type, value, tb = sys.exc_info()
tb = tb.tb_next # Skip *this* frame
sys.last_type = type
sys.last_value = value
sys.last_traceback = tb
del tb # Get rid of it in this namespace
raise
def pytest_runtest_teardown(item, nextitem):
item.session._setupstate.teardown_exact(item, nextitem)
@@ -108,8 +121,16 @@ def call_and_report(item, when, log=True, **kwds):
report = hook.pytest_runtest_makereport(item=item, call=call)
if log:
hook.pytest_runtest_logreport(report=report)
if check_interactive_exception(call, report):
hook.pytest_exception_interact(node=item, call=call, report=report)
return report
def check_interactive_exception(call, report):
return call.excinfo and not (
hasattr(report, "wasxfail") or
call.excinfo.errisinstance(skip.Exception) or
call.excinfo.errisinstance(bdb.BdbQuit))
def call_runtest_hook(item, when, **kwds):
hookname = "pytest_runtest_" + when
ihook = getattr(item.ihook, hookname)
@@ -125,14 +146,13 @@ class CallInfo:
self.when = when
self.start = time()
try:
try:
self.result = func()
except KeyboardInterrupt:
raise
except:
self.excinfo = py.code.ExceptionInfo()
finally:
self.result = func()
except KeyboardInterrupt:
self.stop = time()
raise
except:
self.excinfo = py.code.ExceptionInfo()
self.stop = time()
def __repr__(self):
if self.excinfo:
@@ -168,6 +188,11 @@ class BaseReport(object):
except UnicodeEncodeError:
out.line("<unprintable longrepr>")
def get_sections(self, prefix):
for name, content in self.sections:
if name.startswith(prefix):
yield prefix, content
passed = property(lambda x: x.outcome == "passed")
failed = property(lambda x: x.outcome == "failed")
skipped = property(lambda x: x.outcome == "skipped")
@@ -181,15 +206,15 @@ def pytest_runtest_makereport(item, call):
duration = call.stop-call.start
keywords = dict([(x,1) for x in item.keywords])
excinfo = call.excinfo
sections = []
if not call.excinfo:
outcome = "passed"
longrepr = None
else:
excinfo = call.excinfo
if not isinstance(excinfo, py.code.ExceptionInfo):
outcome = "failed"
longrepr = excinfo
elif excinfo.errisinstance(py.test.skip.Exception):
elif excinfo.errisinstance(pytest.skip.Exception):
outcome = "skipped"
r = excinfo._getreprcrash()
longrepr = (str(r.path), r.lineno, r.message)
@@ -198,17 +223,20 @@ def pytest_runtest_makereport(item, call):
if call.when == "call":
longrepr = item.repr_failure(excinfo)
else: # exception in setup or teardown
longrepr = item._repr_failure_py(excinfo)
longrepr = item._repr_failure_py(excinfo,
style=item.config.option.tbstyle)
for rwhen, key, content in item._report_sections:
sections.append(("Captured %s %s" %(key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
duration=duration)
sections, duration)
class TestReport(BaseReport):
""" Basic test report object (also used for setup and teardown calls if
they fail).
"""
def __init__(self, nodeid, location,
keywords, outcome, longrepr, when, sections=(), duration=0, **extra):
def __init__(self, nodeid, location, keywords, outcome,
longrepr, when, sections=(), duration=0, **extra):
#: normalized collection node id
self.nodeid = nodeid
@@ -257,7 +285,9 @@ def pytest_make_collect_report(collector):
if not call.excinfo:
outcome = "passed"
else:
if call.excinfo.errisinstance(py.test.skip.Exception):
from _pytest import nose
skip_exceptions = (Skipped,) + nose.get_skip_exceptions()
if call.excinfo.errisinstance(skip_exceptions):
outcome = "skipped"
r = collector._repr_failure_py(call.excinfo, "line").reprcrash
longrepr = (str(r.path), r.lineno, r.message)
@@ -267,11 +297,15 @@ def pytest_make_collect_report(collector):
if not hasattr(errorinfo, "toterminal"):
errorinfo = CollectErrorRepr(errorinfo)
longrepr = errorinfo
return CollectReport(collector.nodeid, outcome, longrepr,
rep = CollectReport(collector.nodeid, outcome, longrepr,
getattr(call, 'result', None))
rep.call = call # see collect_one_node
return rep
class CollectReport(BaseReport):
def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra):
def __init__(self, nodeid, outcome, longrepr, result,
sections=(), **extra):
self.nodeid = nodeid
self.outcome = outcome
self.longrepr = longrepr
@@ -303,11 +337,10 @@ class SetupState(object):
""" attach a finalizer to the given colitem.
if colitem is None, this will add a finalizer that
is called at the end of teardown_all().
if colitem is a tuple, it will be used as a key
and needs an explicit call to _callfinalizers(key) later on.
"""
assert hasattr(finalizer, '__call__')
#assert colitem in self.stack
assert colitem and not isinstance(colitem, tuple)
assert py.builtin.callable(finalizer)
#assert colitem in self.stack # some unit tests don't setup stack :/
self._finalizers.setdefault(colitem, []).append(finalizer)
def _pop_and_teardown(self):
@@ -316,9 +349,18 @@ class SetupState(object):
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)
@@ -363,6 +405,16 @@ class SetupState(object):
col._prepare_exc = sys.exc_info()
raise
def collect_one_node(collector):
ihook = collector.ihook
ihook.pytest_collectstart(collector=collector)
rep = ihook.pytest_make_collect_report(collector=collector)
call = rep.__dict__.pop("call", None)
if call and check_interactive_exception(call, rep):
ihook.pytest_exception_interact(node=collector, call=call, report=rep)
return rep
# =============================================================
# Test OutcomeExceptions and helpers for creating them.
@@ -388,7 +440,7 @@ class Skipped(OutcomeException):
__module__ = 'builtins'
class Failed(OutcomeException):
""" raised from an explicit call to py.test.fail() """
""" raised from an explicit call to pytest.fail() """
__module__ = 'builtins'
class Exit(KeyboardInterrupt):
@@ -408,7 +460,7 @@ exit.Exception = Exit
def skip(msg=""):
""" skip an executing test with the given message. Note: it's usually
better to use the py.test.mark.skipif marker to declare a test to be
better to use the pytest.mark.skipif marker to declare a test to be
skipped under certain conditions like mismatching platforms or
dependencies. See the pytest_skipping plugin for details.
"""
@@ -428,25 +480,28 @@ fail.Exception = Failed
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.
"""
__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))
if minversion is not None:
try:
from pkg_resources import parse_version as pv
except ImportError:
skip("we have a required version for %r but can not import "
"no pkg_resources to parse version strings." %(modname,))
if verattr is None or pv(verattr) < pv(minversion):
skip("module %r has __version__ %r, required is: %r" %(
modname, verattr, minversion))
return mod

View File

@@ -1,7 +1,10 @@
""" support for skip/xfail functions and markers. """
import py, pytest
import os
import sys
import traceback
import py
import pytest
def pytest_addoption(parser):
group = parser.getgroup("general")
@@ -10,6 +13,14 @@ def pytest_addoption(parser):
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 "
@@ -18,18 +29,20 @@ def pytest_configure(config):
"http://pytest.org/latest/skipping.html"
)
config.addinivalue_line("markers",
"xfail(condition, reason=None, run=True): mark the the test function "
"xfail(condition, reason=None, run=True, raises=None): 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"
"you don't even want to execute the test function. If only specific "
"exception(s) are expected, you can list them in raises, and if the test fails "
"in other ways, it will be reported as a true failure. "
"See http://pytest.org/latest/skipping.html"
)
def pytest_namespace():
return dict(xfail=xfail)
class XFailed(pytest.fail.Exception):
""" raised from an explicit call to py.test.xfail() """
""" raised from an explicit call to pytest.xfail() """
def xfail(reason=""):
""" xfail an executing test or setup functions with the given reason."""
@@ -44,7 +57,8 @@ class MarkEvaluator:
@property
def holder(self):
return self.item.keywords.get(self.name, None)
return self.item.keywords.get(self.name)
def __bool__(self):
return bool(self.holder)
__nonzero__ = __bool__
@@ -52,18 +66,22 @@ class MarkEvaluator:
def wasvalid(self):
return not hasattr(self, 'exc')
def invalidraise(self, exc):
raises = self.get('raises')
if not raises:
return
return not isinstance(exc, raises)
def istrue(self):
try:
return self._istrue()
except KeyboardInterrupt:
raise
except:
except Exception:
self.exc = sys.exc_info()
if isinstance(self.exc[1], SyntaxError):
msg = [" " * (self.exc[1].offset + 4) + "^",]
msg.append("SyntaxError: invalid syntax")
else:
msg = py.std.traceback.format_exception_only(*self.exc[:2])
msg = traceback.format_exception_only(*self.exc[:2])
pytest.fail("Error evaluating %r expression\n"
" %s\n"
"%s"
@@ -71,7 +89,7 @@ class MarkEvaluator:
pytrace=False)
def _getglobals(self):
d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config}
d = {'os': os, 'sys': sys, 'config': self.item.config}
func = self.item.obj
try:
d.update(func.__globals__)
@@ -80,20 +98,36 @@ class MarkEvaluator:
return d
def _istrue(self):
if hasattr(self, 'result'):
return self.result
if self.holder:
d = self._getglobals()
if self.holder.args:
self.result = False
for expr in self.holder.args:
self.expr = expr
if isinstance(expr, py.builtin._basestring):
result = cached_eval(self.item.config, expr, d)
else:
pytest.fail("expression is not a string")
if result:
self.result = True
# "holder" might be a MarkInfo or a MarkDecorator; only
# MarkInfo keeps track of all parameters it received in an
# _arglist attribute
if hasattr(self.holder, '_arglist'):
arglist = self.holder._arglist
else:
arglist = [(self.holder.args, self.holder.kwargs)]
for args, kwargs in arglist:
for expr in args:
self.expr = expr
break
if isinstance(expr, py.builtin._basestring):
result = cached_eval(self.item.config, expr, d)
else:
if "reason" not in kwargs:
# XXX better be checked at collection time
msg = "you need to specify reason=STRING " \
"when using booleans as conditions."
pytest.fail(msg)
result = bool(expr)
if result:
self.result = True
self.reason = kwargs.get('reason', None)
self.expr = expr
return self.result
else:
self.result = True
return getattr(self, 'result', False)
@@ -102,7 +136,7 @@ class MarkEvaluator:
return self.holder.kwargs.get(attr, default)
def getexplanation(self):
expl = self.get('reason', None)
expl = getattr(self, 'reason', None) or self.get('reason', None)
if not expl:
if not hasattr(self, 'expr'):
return ""
@@ -111,13 +145,12 @@ class MarkEvaluator:
return expl
@pytest.mark.tryfirst
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
if not isinstance(item, pytest.Function):
return
evalskip = MarkEvaluator(item, 'skipif')
if evalskip.istrue():
py.test.skip(evalskip.getexplanation())
item._evalskip = evalskip
pytest.skip(evalskip.getexplanation())
item._evalxfail = MarkEvaluator(item, 'xfail')
check_xfail_no_run(item)
@@ -129,44 +162,42 @@ def check_xfail_no_run(item):
evalxfail = item._evalxfail
if evalxfail.istrue():
if not evalxfail.get('run', True):
py.test.xfail("[NOTRUN] " + evalxfail.getexplanation())
pytest.xfail("[NOTRUN] " + evalxfail.getexplanation())
def pytest_runtest_makereport(__multicall__, item, call):
if not isinstance(item, pytest.Function):
return
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
evalxfail = getattr(item, '_evalxfail', None)
evalskip = getattr(item, '_evalskip', None)
# unitttest special case, see setting of _unexpectedsuccess
if hasattr(item, '_unexpectedsuccess'):
rep = __multicall__.execute()
if rep.when == "call":
# we need to translate into how py.test encodes xpass
rep.wasxfail = "reason: " + repr(item._unexpectedsuccess)
rep.outcome = "failed"
return rep
if not (call.excinfo and
call.excinfo.errisinstance(py.test.xfail.Exception)):
evalxfail = getattr(item, '_evalxfail', None)
if not evalxfail:
return
if call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception):
if not item.config.getvalue("runxfail"):
rep = __multicall__.execute()
rep.wasxfail = "reason: " + call.excinfo.value.msg
rep.outcome = "skipped"
return rep
rep = __multicall__.execute()
evalxfail = item._evalxfail
if not rep.skipped:
if not item.config.option.runxfail:
if evalxfail.wasvalid() and evalxfail.istrue():
if call.excinfo:
rep.outcome = "skipped"
elif call.when == "call":
rep.outcome = "failed"
else:
return rep
if hasattr(item, '_unexpectedsuccess') and rep.when == "call":
# we need to translate into how pytest encodes xpass
rep.wasxfail = "reason: " + repr(item._unexpectedsuccess)
rep.outcome = "failed"
elif item.config.option.runxfail:
pass # don't interefere
elif call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception):
rep.wasxfail = "reason: " + call.excinfo.value.msg
rep.outcome = "skipped"
elif evalxfail and not rep.skipped and evalxfail.wasvalid() and \
evalxfail.istrue():
if call.excinfo:
if evalxfail.invalidraise(call.excinfo.value):
rep.outcome = "failed"
else:
rep.outcome = "skipped"
rep.wasxfail = evalxfail.getexplanation()
return rep
return rep
elif call.when == "call":
rep.outcome = "failed" # xpass outcome
rep.wasxfail = evalxfail.getexplanation()
elif evalskip is not None and rep.skipped and type(rep.longrepr) is tuple:
# skipped by mark.skipif; change the location of the failure
# to point to the item definition, otherwise it will display
# the location of where the skip exception was raised within pytest
filename, line, reason = rep.longrepr
filename, line = item.location[:2]
rep.longrepr = filename, line, reason
# called by terminalreporter progress reporting
def pytest_report_teststatus(report):
@@ -174,7 +205,7 @@ def pytest_report_teststatus(report):
if report.skipped:
return "xfailed", "x", "xfail"
elif report.failed:
return "xpassed", "X", "XPASS"
return "xpassed", "X", ("XPASS", {'yellow': True})
# called by the terminalreporter instance/plugin
def pytest_terminal_summary(terminalreporter):
@@ -205,18 +236,17 @@ def pytest_terminal_summary(terminalreporter):
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:
pos = rep.nodeid
lines.append(format %(pos, ))
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
lines.append(format %(pos,))
def show_xfailed(terminalreporter, lines):
xfailed = terminalreporter.stats.get("xfailed")
if xfailed:
for rep in xfailed:
pos = rep.nodeid
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
reason = rep.wasxfail
lines.append("XFAIL %s" % (pos,))
if reason:
@@ -226,7 +256,7 @@ def show_xpassed(terminalreporter, lines):
xpassed = terminalreporter.stats.get("xpassed")
if xpassed:
for rep in xpassed:
pos = rep.nodeid
pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
reason = rep.wasxfail
lines.append("XPASS %s %s" %(pos, reason))

View File

@@ -1,18 +1,40 @@
#! /usr/bin/env python
# Hi There!
# You may be wondering what this giant blob of binary data here is, you might
# even be worried that we're up to something nefarious (good for you for being
# paranoid!). This is a base64 encoding of a zip file, this zip file contains
# a fully functional basic pytest script.
#
# Pytest is a thing that tests packages, pytest itself is a package that some-
# one might want to install, especially if they're looking to run tests inside
# some package they want to install. Pytest has a lot of code to collect and
# execute tests, and other such sort of "tribal knowledge" that has been en-
# coded in its code base. Because of this we basically include a basic copy
# of pytest inside this blob. We do this because it let's you as a maintainer
# or application developer who wants people who don't deal with python much to
# easily run tests without installing the complete pytest package.
#
# If you're wondering how this is created: you can create it yourself if you
# have a complete pytest installation by using this command on the command-
# line: ``py.test --genscript=runtests.py``.
sources = """
@SOURCES@"""
import sys
import base64
import zlib
import imp
class DictImporter(object):
def __init__(self, sources):
self.sources = sources
def find_module(self, fullname, path=None):
if fullname == "argparse" and sys.version_info >= (2,7):
# we were generated with <python2.7 (which pulls in argparse)
# but we are running now on a stdlib which has it, so use that.
return None
if fullname in self.sources:
return self
if fullname + '.__init__' in self.sources:
@@ -36,7 +58,7 @@ class DictImporter(object):
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):
@@ -46,6 +68,11 @@ class DictImporter(object):
return res
if __name__ == "__main__":
try:
import pkg_resources # noqa
except ImportError:
sys.stderr.write("ERROR: setuptools not installed\n")
sys.exit(2)
if sys.version_info >= (3, 0):
exec("def do_exec(co, loc): exec(co, loc)\n")
import pickle
@@ -58,6 +85,5 @@ if __name__ == "__main__":
importer = DictImporter(sources)
sys.meta_path.insert(0, importer)
entry = "@ENTRY@"
do_exec(entry, locals())
do_exec(entry, locals()) # noqa

View File

@@ -2,10 +2,16 @@
This is a good source for looking at the various reporting hooks.
"""
from _pytest.main import EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, \
EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED
import pytest
import py
import sys
import os
import time
import platform
import _pytest._pluggy as pluggy
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
@@ -16,7 +22,7 @@ def pytest_addoption(parser):
group._addoption('-r',
action="store", dest="reportchars", default=None, metavar="chars",
help="show extra test summary info as specified by chars (f)ailed, "
"(E)error, (s)skipped, (x)failed, (X)passed.")
"(E)error, (s)skipped, (x)failed, (X)passed (w)pytest-warnings (a)all.")
group._addoption('-l', '--showlocals',
action="store_true", dest="showlocals", default=False,
help="show locals in tracebacks (disabled by default).")
@@ -24,30 +30,20 @@ def pytest_addoption(parser):
action="store", dest="report", default=None, metavar="opts",
help="(deprecated, use -r)")
group._addoption('--tb', metavar="style",
action="store", dest="tbstyle", default='long',
type="choice", choices=['long', 'short', 'no', 'line', 'native'],
help="traceback print mode (long/short/line/native/no).")
group._addoption('--fulltrace',
action="store_true", dest="fulltrace", default=False,
action="store", dest="tbstyle", default='auto',
choices=['auto', 'long', 'short', 'no', 'line', 'native'],
help="traceback print mode (auto/long/short/line/native/no).")
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
# we try hard to make printing resilient against
# later changes on FD level.
stdout = py.std.sys.stdout
if hasattr(os, 'dup') and hasattr(stdout, 'fileno'):
try:
newstdout = py.io.dupfile(stdout, buffering=1,
encoding=stdout.encoding)
except ValueError:
pass
else:
config._cleanup.append(lambda: newstdout.close())
assert stdout.encoding == newstdout.encoding
stdout = newstdout
reporter = TerminalReporter(config, stdout)
reporter = TerminalReporter(config, sys.stdout)
config.pluginmanager.register(reporter, 'terminalreporter')
if config.option.debug or config.option.traceconfig:
def mywriter(tags, args):
@@ -60,7 +56,7 @@ def getreportopt(config):
optvalue = config.option.report
if optvalue:
py.builtin.print_("DEPRECATED: use -r instead of --report option.",
file=py.std.sys.stderr)
file=sys.stderr)
if optvalue:
for setting in optvalue.split(","):
setting = setting.strip()
@@ -71,8 +67,10 @@ def getreportopt(config):
reportchars = config.option.reportchars
if reportchars:
for char in reportchars:
if char not in reportopts:
if char not in reportopts and char != 'a':
reportopts += char
elif char == 'a':
reportopts = 'fEsxXw'
return reportopts
def pytest_report_teststatus(report):
@@ -86,8 +84,17 @@ def pytest_report_teststatus(report):
letter = "f"
return report.outcome, letter, report.outcome.upper()
class WarningReport:
def __init__(self, code, message, nodeid=None, fslocation=None):
self.code = code
self.message = message
self.nodeid = nodeid
self.fslocation = fslocation
class TerminalReporter:
def __init__(self, config, file=None):
import _pytest.config
self.config = config
self.verbosity = self.config.option.verbose
self.showheader = self.verbosity >= 0
@@ -96,24 +103,25 @@ class TerminalReporter:
self._numcollected = 0
self.stats = {}
self.startdir = self.curdir = py.path.local()
self.startdir = py.path.local()
if file is None:
file = py.std.sys.stdout
self._tw = py.io.TerminalWriter(file)
file = sys.stdout
self._tw = self.writer = _pytest.config.create_terminal_writer(config,
file)
self.currentfspath = None
self.reportchars = getreportopt(config)
self.hasmarkup = self._tw.hasmarkup
def hasopt(self, char):
char = {'xfailed': 'x', 'skipped': 's'}.get(char,char)
char = {'xfailed': 'x', 'skipped': 's'}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, fspath, res):
def write_fspath_result(self, nodeid, res):
fspath = self.config.rootdir.join(nodeid.split("::")[0])
if fspath != self.currentfspath:
self.currentfspath = fspath
#fspath = self.startdir.bestrelpath(fspath)
fspath = self.startdir.bestrelpath(fspath)
self._tw.line()
#relpath = self.startdir.bestrelpath(fspath)
self._tw.write(fspath + " ")
self._tw.write(res)
@@ -135,7 +143,8 @@ class TerminalReporter:
self._tw.write(content, **markup)
def write_line(self, line, **markup):
line = str(line)
if not py.builtin._istext(line):
line = py.builtin.text(line, errors="replace")
self.ensure_newline()
self._tw.line(line, **markup)
@@ -147,14 +156,28 @@ class TerminalReporter:
self.ensure_newline()
self._tw.sep(sep, title, **markup)
def section(self, title, sep="=", **kw):
self._tw.sep(sep, title, **kw)
def line(self, msg, **kw):
self._tw.line(msg, **kw)
def pytest_internalerror(self, excrepr):
for line in str(excrepr).split("\n"):
for line in py.builtin.text(excrepr).split("\n"):
self.write_line("INTERNALERROR> " + line)
return 1
def pytest_logwarning(self, code, fslocation, message, nodeid):
warnings = self.stats.setdefault("warnings", [])
if isinstance(fslocation, tuple):
fslocation = "%s:%d" % fslocation
warning = WarningReport(code=code, fslocation=fslocation,
message=message, nodeid=nodeid)
warnings.append(warning)
def pytest_plugin_registered(self, plugin):
if self.config.option.traceconfig:
msg = "PLUGIN registered: %s" %(plugin,)
msg = "PLUGIN registered: %s" % (plugin,)
# XXX this event may happen during setup/teardown time
# which unfortunately captures our output here
# which garbles our output if we use self.write_line
@@ -166,24 +189,25 @@ class TerminalReporter:
def pytest_runtest_logstart(self, nodeid, location):
# ensure that the path is printed before the
# 1st test of a module starts running
fspath = nodeid.split("::")[0]
if self.showlongtestinfo:
line = self._locationline(fspath, *location)
line = self._locationline(nodeid, *location)
self.write_ensure_prefix(line, "")
elif self.showfspath:
self.write_fspath_result(fspath, "")
fsid = nodeid.split("::")[0]
self.write_fspath_result(fsid, "")
def pytest_runtest_logreport(self, report):
rep = report
res = self.config.hook.pytest_report_teststatus(report=rep)
cat, letter, word = res
self.stats.setdefault(cat, []).append(rep)
self._tests_ran = True
if not letter and not word:
# probably passed setup/teardown
return
if self.verbosity <= 0:
if not hasattr(rep, 'node') and self.showfspath:
self.write_fspath_result(rep.fspath, letter)
self.write_fspath_result(rep.nodeid, letter)
else:
self._tw.write(letter)
else:
@@ -196,7 +220,7 @@ class TerminalReporter:
markup = {'red':True}
elif rep.skipped:
markup = {'yellow':True}
line = self._locationline(str(rep.fspath), *rep.location)
line = self._locationline(rep.nodeid, *rep.location)
if not hasattr(rep, 'node'):
self.write_ensure_prefix(line, word, **markup)
#self._tw.write(word, **markup)
@@ -209,7 +233,7 @@ class TerminalReporter:
self.currentfspath = -2
def pytest_collection(self):
if not self.hasmarkup and self.config.option.verbose >=1:
if not self.hasmarkup and self.config.option.verbose >= 1:
self.write("collecting ... ", bold=True)
def pytest_collectreport(self, report):
@@ -220,7 +244,7 @@ class TerminalReporter:
items = [x for x in report.result if isinstance(x, pytest.Item)]
self._numcollected += len(items)
if self.hasmarkup:
#self.write_fspath_result(report.fspath, 'E')
#self.write_fspath_result(report.nodeid, 'E')
self.report_collect()
def report_collect(self, final=False):
@@ -248,18 +272,19 @@ class TerminalReporter:
def pytest_collection_modifyitems(self):
self.report_collect(True)
@pytest.mark.trylast
@pytest.hookimpl(trylast=True)
def pytest_sessionstart(self, session):
self._sessionstarttime = py.std.time.time()
self._sessionstarttime = time.time()
if not self.showheader:
return
self.write_sep("=", "test session starts", bold=True)
verinfo = ".".join(map(str, sys.version_info[:3]))
verinfo = platform.python_version()
msg = "platform %s -- Python %s" % (sys.platform, verinfo)
if hasattr(sys, 'pypy_version_info'):
verinfo = ".".join(map(str, sys.pypy_version_info[:3]))
msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3])
msg += " -- pytest-%s" % (py.test.__version__)
msg += ", pytest-%s, py-%s, pluggy-%s" % (
pytest.__version__, py.__version__, pluggy.__version__)
if self.verbosity > 0 or self.config.option.debug or \
getattr(self.config.option, 'pastebin', None):
msg += " -- " + str(sys.executable)
@@ -271,15 +296,17 @@ class TerminalReporter:
self.write_line(line)
def pytest_report_header(self, config):
plugininfo = config.pluginmanager._plugin_distinfo
inifile = ""
if config.inifile:
inifile = config.rootdir.bestrelpath(config.inifile)
lines = ["rootdir: %s, inifile: %s" %(config.rootdir, inifile)]
plugininfo = config.pluginmanager.list_plugin_distinfo()
if plugininfo:
l = []
for dist, plugin in plugininfo:
name = dist.project_name
if name.startswith("pytest-"):
name = name[7:]
l.append(name)
return "plugins: %s" % ", ".join(l)
lines.append(
"plugins: %s" % ", ".join(_plugin_nameversions(plugininfo)))
return lines
def pytest_collection_finish(self, session):
if self.config.option.collectonly:
@@ -325,17 +352,23 @@ class TerminalReporter:
stack.append(col)
#if col.name == "()":
# continue
indent = (len(stack)-1) * " "
self._tw.line("%s%s" %(indent, col))
indent = (len(stack) - 1) * " "
self._tw.line("%s%s" % (indent, col))
def pytest_sessionfinish(self, exitstatus, __multicall__):
__multicall__.execute()
@pytest.hookimpl(hookwrapper=True)
def pytest_sessionfinish(self, exitstatus):
outcome = yield
outcome.get_result()
self._tw.line("")
if exitstatus in (0, 1, 2, 4):
summary_exit_codes = (
EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, EXIT_USAGEERROR,
EXIT_NOTESTSCOLLECTED)
if exitstatus in summary_exit_codes:
self.summary_errors()
self.summary_failures()
self.summary_warnings()
self.config.hook.pytest_terminal_summary(terminalreporter=self)
if exitstatus == 2:
if exitstatus == EXIT_INTERRUPTED:
self._report_keyboardinterrupt()
del self._keyboardinterrupt_memo
self.summary_deselected()
@@ -358,20 +391,24 @@ class TerminalReporter:
else:
excrepr.reprcrash.toterminal(self._tw)
def _locationline(self, collect_fspath, fspath, lineno, domain):
def _locationline(self, nodeid, fspath, lineno, domain):
def mkrel(nodeid):
line = self.config.cwd_relative_nodeid(nodeid)
if domain and line.endswith(domain):
line = line[:-len(domain)]
l = domain.split("[")
l[0] = l[0].replace('.', '::') # don't replace '.' in params
line += "[".join(l)
return line
# collect_fspath comes from testid which has a "/"-normalized path
if fspath and fspath.replace("\\", "/") != collect_fspath:
fspath = "%s <- %s" % (collect_fspath, fspath)
if fspath:
line = str(fspath)
if lineno is not None:
lineno += 1
line += ":" + str(lineno)
if domain:
line += ": " + str(domain)
res = mkrel(nodeid).replace("::()", "") # parens-normalization
if nodeid.split("::")[0] != fspath.replace("\\", "/"):
res += " <- " + self.startdir.bestrelpath(fspath)
else:
line = "[location]"
return line + " "
res = "[location]"
return res + " "
def _getfailureheadline(self, rep):
if hasattr(rep, 'location'):
@@ -399,6 +436,16 @@ class TerminalReporter:
l.append(x)
return l
def summary_warnings(self):
if self.hasopt("w"):
warnings = self.stats.get("warnings")
if not warnings:
return
self.write_sep("=", "pytest-warning summary")
for w in warnings:
self._tw.line("W%s %s %s" % (w.code,
w.fslocation, w.message))
def summary_failures(self):
if self.config.option.tbstyle != "no":
reports = self.getreports('failed')
@@ -441,25 +488,15 @@ class TerminalReporter:
self._tw.line(content)
def summary_stats(self):
session_duration = py.std.time.time() - self._sessionstarttime
session_duration = time.time() - self._sessionstarttime
(line, color) = build_summary_stats_line(self.stats)
msg = "%s in %.2f seconds" % (line, session_duration)
markup = {color: True, 'bold': True}
keys = "failed passed skipped deselected xfailed xpassed".split()
for key in self.stats.keys():
if key not in keys:
keys.append(key)
parts = []
for key in keys:
if key: # setup/teardown reports have an empty key, ignore them
val = self.stats.get(key, None)
if val:
parts.append("%d %s" %(len(val), key))
line = ", ".join(parts)
# XXX coloring
msg = "%s in %.2f seconds" %(line, session_duration)
if self.verbosity >= 0:
self.write_sep("=", msg, bold=True)
#else:
# self.write_line(msg, bold=True)
self.write_sep("=", msg, **markup)
if self.verbosity == -1:
self.write_line(msg, **markup)
def summary_deselected(self):
if 'deselected' in self.stats:
@@ -471,7 +508,7 @@ class TerminalReporter:
if m:
l.append("-m %r" % m)
if l:
self.write_sep("=", "%d tests deselected by %r" %(
self.write_sep("=", "%d tests deselected by %r" % (
len(self.stats['deselected']), " ".join(l)), bold=True)
def repr_pythonversion(v=None):
@@ -490,3 +527,46 @@ def flatten(l):
else:
yield x
def build_summary_stats_line(stats):
keys = ("failed passed skipped deselected "
"xfailed xpassed warnings error").split()
key_translation = {'warnings': 'pytest-warnings'}
unknown_key_seen = False
for key in stats.keys():
if key not in keys:
if key: # setup/teardown reports have an empty key, ignore them
keys.append(key)
unknown_key_seen = True
parts = []
for key in keys:
val = stats.get(key, None)
if val:
key_name = key_translation.get(key, key)
parts.append("%d %s" % (len(val), key_name))
line = ", ".join(parts)
if 'failed' in stats or 'error' in stats:
color = 'red'
elif 'warnings' in stats or unknown_key_seen:
color = 'yellow'
elif 'passed' in stats:
color = 'green'
else:
color = 'yellow'
return (line, color)
def _plugin_nameversions(plugininfo):
l = []
for plugin, dist in plugininfo:
# gets us name and version!
name = '{dist.project_name}-{dist.version}'.format(dist=dist)
# questionable convenience, but it keeps things short
if name.startswith("pytest-"):
name = name[7:]
# we decided to print python package names
# they can have more than one plugin
if name not in l:
l.append(name)
return l

View File

@@ -1,8 +1,17 @@
""" support for providing temporary directories to test functions. """
import pytest, py
import re
import pytest
import py
from _pytest.monkeypatch import monkeypatch
class TempdirHandler:
class TempdirFactory:
"""Factory for temporary directories under the common base temp directory.
The base directory can be configured using the ``--basetemp`` option.
"""
def __init__(self, config):
self.config = config
self.trace = config.trace.get("tmpdir")
@@ -18,6 +27,10 @@ class TempdirHandler:
return self.getbasetemp().ensure(string, dir=dir)
def mktemp(self, basename, numbered=True):
"""Create a subdirectory of the base temporary directory and return it.
If ``numbered``, ensure the directory is unique by adding a number
prefix greater than any existing one.
"""
basetemp = self.getbasetemp()
if not numbered:
p = basetemp.mkdir(basename)
@@ -39,7 +52,17 @@ class TempdirHandler:
basetemp.remove()
basetemp.mkdir()
else:
basetemp = py.path.local.make_numbered_dir(prefix='pytest-')
temproot = py.path.local.get_temproot()
user = get_user()
if user:
# use a sub-directory in the temproot to speed-up
# make_numbered_dir() call
rootdir = temproot.join('pytest-of-%s' % user)
else:
rootdir = temproot
rootdir.ensure(dir=1)
basetemp = py.path.local.make_numbered_dir(prefix='pytest-',
rootdir=rootdir)
self._basetemp = t = basetemp.realpath()
self.trace("new basetemp", t)
return t
@@ -47,15 +70,44 @@ class TempdirHandler:
def finish(self):
self.trace("finish")
def get_user():
"""Return the current user name, or None if getuser() does not work
in the current environment (see #1010).
"""
import getpass
try:
return getpass.getuser()
except (ImportError, KeyError):
return None
# backward compatibility
TempdirHandler = TempdirFactory
def pytest_configure(config):
"""Create a TempdirFactory and attach it to the config object.
This is to comply with existing plugins which expect the handler to be
available at pytest_configure time, but ideally should be moved entirely
to the tmpdir_factory session fixture.
"""
mp = monkeypatch()
t = TempdirHandler(config)
t = TempdirFactory(config)
config._cleanup.extend([mp.undo, t.finish])
mp.setattr(config, '_tmpdirhandler', t, raising=False)
mp.setattr(pytest, 'ensuretemp', t.ensuretemp, raising=False)
@pytest.fixture(scope='session')
def tmpdir_factory(request):
"""Return a TempdirFactory instance for the test session.
"""
return request.config._tmpdirhandler
@pytest.fixture
def tmpdir(request):
def tmpdir(request, tmpdir_factory):
"""return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
@@ -63,6 +115,9 @@ def tmpdir(request):
path object.
"""
name = request.node.name
name = py.std.re.sub("[\W]", "_", name)
x = request.config._tmpdirhandler.mktemp(name, numbered=True)
name = re.sub("[\W]", "_", name)
MAXVAL = 30
if len(name) > MAXVAL:
name = name[:MAXVAL]
x = tmpdir_factory.mktemp(name, numbered=True)
return x

View File

@@ -1,40 +1,57 @@
""" discovery and running of std-library "unittest" style tests. """
import pytest, py
import sys, pdb
from __future__ import absolute_import
import traceback
import sys
import pytest
import py
# for transfering markers
from _pytest.python import transfer_markers
from _pytest.skipping import MarkEvaluator
def pytest_pycollect_makeitem(collector, name, obj):
unittest = sys.modules.get('unittest')
if unittest is None:
return # nobody can have derived unittest.TestCase
# has unittest been imported and is obj a subclass of its TestCase?
try:
isunit = issubclass(obj, unittest.TestCase)
except KeyboardInterrupt:
raise
if not issubclass(obj, sys.modules["unittest"].TestCase):
return
except Exception:
pass
else:
if isunit:
return UnitTestCase(name, parent=collector)
return
# yes, so let's collect it
return UnitTestCase(name, parent=collector)
class UnitTestCase(pytest.Class):
nofuncargs = True # marker for fixturemanger.getfixtureinfo()
# to declare that our children do not support funcargs
#
def setup(self):
cls = self.obj
if getattr(cls, '__unittest_skip__', False):
return # skipped
setup = getattr(cls, 'setUpClass', None)
if setup is not None:
setup()
teardown = getattr(cls, 'tearDownClass', None)
if teardown is not None:
self.addfinalizer(teardown)
super(UnitTestCase, self).setup()
def collect(self):
self.session._fixturemanager.parsefactories(self, unittest=True)
loader = py.std.unittest.TestLoader()
module = self.getparent(pytest.Module).obj
from unittest import TestLoader
cls = self.obj
if not getattr(cls, "__test__", True):
return
self.session._fixturemanager.parsefactories(self, unittest=True)
loader = TestLoader()
module = self.getparent(pytest.Module).obj
foundsomething = False
for name in loader.getTestCaseNames(self.obj):
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
@@ -45,21 +62,7 @@ class UnitTestCase(pytest.Class):
if ut is None or runtest != ut.TestCase.runTest:
yield TestCaseFunction('runTest', parent=self)
def setup(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'setUpClass', None)
if meth is not None:
meth()
super(UnitTestCase, self).setup()
def teardown(self):
if getattr(self.obj, '__unittest_skip__', False):
return
meth = getattr(self.obj, 'tearDownClass', None)
if meth is not None:
meth()
super(UnitTestCase, self).teardown()
class TestCaseFunction(pytest.Function):
_excinfo = None
@@ -67,10 +70,6 @@ class TestCaseFunction(pytest.Function):
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"):
@@ -91,7 +90,7 @@ class TestCaseFunction(pytest.Function):
except TypeError:
try:
try:
l = py.std.traceback.format_exception(*rawexcinfo)
l = traceback.format_exception(*rawexcinfo)
l.insert(0, "NOTE: Incompatible Exception Representation, "
"displaying natively:\n\n")
pytest.fail("".join(l), pytrace=False)
@@ -115,6 +114,8 @@ class TestCaseFunction(pytest.Function):
try:
pytest.skip(reason)
except pytest.skip.Exception:
self._evalskip = MarkEvaluator(self, 'SkipTest')
self._evalskip.result = True
self._addexcinfo(sys.exc_info())
def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
@@ -142,38 +143,44 @@ class TestCaseFunction(pytest.Function):
if traceback:
excinfo.traceback = traceback
@pytest.mark.tryfirst
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call):
if isinstance(item, TestCaseFunction):
if item._excinfo:
call.excinfo = item._excinfo.pop(0)
del call.result
try:
del call.result
except AttributeError:
pass
# twisted trial support
def pytest_runtest_protocol(item, __multicall__):
if isinstance(item, TestCaseFunction):
if 'twisted.trial.unittest' in sys.modules:
ut = sys.modules['twisted.python.failure']
Failure__init__ = ut.Failure.__init__.im_func
check_testcase_implements_trial_reporter()
def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
captureVars=None):
if exc_value is None:
self._rawexcinfo = sys.exc_info()
else:
if exc_type is None:
exc_type = type(exc_value)
self._rawexcinfo = (exc_type, exc_value, exc_tb)
try:
Failure__init__(self, exc_value, exc_type, exc_tb,
captureVars=captureVars)
except TypeError:
Failure__init__(self, exc_value, exc_type, exc_tb)
ut.Failure.__init__ = excstore
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item):
if isinstance(item, TestCaseFunction) and \
'twisted.trial.unittest' in sys.modules:
ut = sys.modules['twisted.python.failure']
Failure__init__ = ut.Failure.__init__
check_testcase_implements_trial_reporter()
def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
captureVars=None):
if exc_value is None:
self._rawexcinfo = sys.exc_info()
else:
if exc_type is None:
exc_type = type(exc_value)
self._rawexcinfo = (exc_type, exc_value, exc_tb)
try:
return __multicall__.execute()
finally:
ut.Failure.__init__ = Failure__init__
Failure__init__(self, exc_value, exc_type, exc_tb,
captureVars=captureVars)
except TypeError:
Failure__init__(self, exc_value, exc_type, exc_tb)
ut.Failure.__init__ = excstore
yield
ut.Failure.__init__ = Failure__init__
else:
yield
def check_testcase_implements_trial_reporter(done=[]):
if done:

View File

@@ -0,0 +1,13 @@
This directory vendors the `pluggy` module.
For a more detailed discussion for the reasons to vendoring this
package, please see [this issue](https://github.com/pytest-dev/pytest/issues/944).
To update the current version, execute:
```
$ pip install -U pluggy==<version> --no-compile --target=_pytest/vendored_packages
```
And commit the modified files. The `pluggy-<version>.dist-info` directory
created by `pip` should be ignored.

View File

@@ -0,0 +1,10 @@
Plugin registration and hook calling for Python
===============================================
This is the plugin manager as used by pytest but stripped
of pytest specific details.
During the 0.x series this plugin does not have much documentation
except extensive docstrings in the pluggy.py module.

View File

@@ -0,0 +1,39 @@
Metadata-Version: 2.0
Name: pluggy
Version: 0.3.1
Summary: plugin and hook calling mechanisms for python
Home-page: UNKNOWN
Author: Holger Krekel
Author-email: holger at merlinux.eu
License: MIT license
Platform: unix
Platform: linux
Platform: osx
Platform: win32
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Utilities
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Plugin registration and hook calling for Python
===============================================
This is the plugin manager as used by pytest but stripped
of pytest specific details.
During the 0.x series this plugin does not have much documentation
except extensive docstrings in the pluggy.py module.

View File

@@ -0,0 +1,8 @@
pluggy.py,sha256=v_RfWzyW6DPU1cJu_EFoL_OHq3t13qloVdR6UaMCXQA,29862
pluggy-0.3.1.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7
pluggy-0.3.1.dist-info/pbr.json,sha256=xX3s6__wOcAyF-AZJX1sdZyW6PUXT-FkfBlM69EEUCg,47
pluggy-0.3.1.dist-info/RECORD,,
pluggy-0.3.1.dist-info/metadata.json,sha256=nLKltOT78dMV-00uXD6Aeemp4xNsz2q59j6ORSDeLjw,1027
pluggy-0.3.1.dist-info/METADATA,sha256=1b85Ho2u4iK30M099k7axMzcDDhLcIMb-A82JUJZnSo,1334
pluggy-0.3.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
pluggy-0.3.1.dist-info/DESCRIPTION.rst,sha256=P5Akh1EdIBR6CeqtV2P8ZwpGSpZiTKPw0NyS7jEiD-g,306

View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.24.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@@ -0,0 +1 @@
{"license": "MIT license", "name": "pluggy", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "plugin and hook calling mechanisms for python", "platform": "unix", "version": "0.3.1", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "Holger Krekel"}]}}, "classifiers": ["Development Status :: 4 - Beta", "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 :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"]}

View File

@@ -0,0 +1 @@
{"is_release": false, "git_version": "7d4c9cd"}

View File

@@ -0,0 +1 @@
pluggy

View File

@@ -0,0 +1,777 @@
"""
PluginManager, basic initialization and tracing.
pluggy is the cristallized core of plugin management as used
by some 150 plugins for pytest.
Pluggy uses semantic versioning. Breaking changes are only foreseen for
Major releases (incremented X in "X.Y.Z"). If you want to use pluggy in
your project you should thus use a dependency restriction like
"pluggy>=0.1.0,<1.0" to avoid surprises.
pluggy is concerned with hook specification, hook implementations and hook
calling. For any given hook specification a hook call invokes up to N implementations.
A hook implementation can influence its position and type of execution:
if attributed "tryfirst" or "trylast" it will be tried to execute
first or last. However, if attributed "hookwrapper" an implementation
can wrap all calls to non-hookwrapper implementations. A hookwrapper
can thus execute some code ahead and after the execution of other hooks.
Hook specification is done by way of a regular python function where
both the function name and the names of all its arguments are significant.
Each hook implementation function is verified against the original specification
function, including the names of all its arguments. To allow for hook specifications
to evolve over the livetime of a project, hook implementations can
accept less arguments. One can thus add new arguments and semantics to
a hook specification by adding another argument typically without breaking
existing hook implementations.
The chosen approach is meant to let a hook designer think carefuly about
which objects are needed by an extension writer. By contrast, subclass-based
extension mechanisms often expose a lot more state and behaviour than needed,
thus restricting future developments.
Pluggy currently consists of functionality for:
- a way to register new hook specifications. Without a hook
specification no hook calling can be performed.
- a registry of plugins which contain hook implementation functions. It
is possible to register plugins for which a hook specification is not yet
known and validate all hooks when the system is in a more referentially
consistent state. Setting an "optionalhook" attribution to a hook
implementation will avoid PluginValidationError's if a specification
is missing. This allows to have optional integration between plugins.
- a "hook" relay object from which you can launch 1:N calls to
registered hook implementation functions
- a mechanism for ordering hook implementation functions
- mechanisms for two different type of 1:N calls: "firstresult" for when
the call should stop when the first implementation returns a non-None result.
And the other (default) way of guaranteeing that all hook implementations
will be called and their non-None result collected.
- mechanisms for "historic" extension points such that all newly
registered functions will receive all hook calls that happened
before their registration.
- a mechanism for discovering plugin objects which are based on
setuptools based entry points.
- a simple tracing mechanism, including tracing of plugin calls and
their arguments.
"""
import sys
import inspect
__version__ = '0.3.1'
__all__ = ["PluginManager", "PluginValidationError",
"HookspecMarker", "HookimplMarker"]
_py3 = sys.version_info > (3, 0)
class HookspecMarker:
""" Decorator helper class for marking functions as hook specifications.
You can instantiate it with a project_name to get a decorator.
Calling PluginManager.add_hookspecs later will discover all marked functions
if the PluginManager uses the same project_name.
"""
def __init__(self, project_name):
self.project_name = project_name
def __call__(self, function=None, firstresult=False, historic=False):
""" if passed a function, directly sets attributes on the function
which will make it discoverable to add_hookspecs(). If passed no
function, returns a decorator which can be applied to a function
later using the attributes supplied.
If firstresult is True the 1:N hook call (N being the number of registered
hook implementation functions) will stop at I<=N when the I'th function
returns a non-None result.
If historic is True calls to a hook will be memorized and replayed
on later registered plugins.
"""
def setattr_hookspec_opts(func):
if historic and firstresult:
raise ValueError("cannot have a historic firstresult hook")
setattr(func, self.project_name + "_spec",
dict(firstresult=firstresult, historic=historic))
return func
if function is not None:
return setattr_hookspec_opts(function)
else:
return setattr_hookspec_opts
class HookimplMarker:
""" Decorator helper class for marking functions as hook implementations.
You can instantiate with a project_name to get a decorator.
Calling PluginManager.register later will discover all marked functions
if the PluginManager uses the same project_name.
"""
def __init__(self, project_name):
self.project_name = project_name
def __call__(self, function=None, hookwrapper=False, optionalhook=False,
tryfirst=False, trylast=False):
""" if passed a function, directly sets attributes on the function
which will make it discoverable to register(). If passed no function,
returns a decorator which can be applied to a function later using
the attributes supplied.
If optionalhook is True a missing matching hook specification will not result
in an error (by default it is an error if no matching spec is found).
If tryfirst is True this hook implementation will run as early as possible
in the chain of N hook implementations for a specfication.
If trylast is True this hook implementation will run as late as possible
in the chain of N hook implementations.
If hookwrapper is True the hook implementations needs to execute exactly
one "yield". The code before the yield is run early before any non-hookwrapper
function is run. The code after the yield is run after all non-hookwrapper
function have run. The yield receives an ``_CallOutcome`` object representing
the exception or result outcome of the inner calls (including other hookwrapper
calls).
"""
def setattr_hookimpl_opts(func):
setattr(func, self.project_name + "_impl",
dict(hookwrapper=hookwrapper, optionalhook=optionalhook,
tryfirst=tryfirst, trylast=trylast))
return func
if function is None:
return setattr_hookimpl_opts
else:
return setattr_hookimpl_opts(function)
def normalize_hookimpl_opts(opts):
opts.setdefault("tryfirst", False)
opts.setdefault("trylast", False)
opts.setdefault("hookwrapper", False)
opts.setdefault("optionalhook", False)
class _TagTracer:
def __init__(self):
self._tag2proc = {}
self.writer = None
self.indent = 0
def get(self, name):
return _TagTracerSub(self, (name,))
def format_message(self, tags, args):
if isinstance(args[-1], dict):
extra = args[-1]
args = args[:-1]
else:
extra = {}
content = " ".join(map(str, args))
indent = " " * self.indent
lines = [
"%s%s [%s]\n" % (indent, content, ":".join(tags))
]
for name, value in extra.items():
lines.append("%s %s: %s\n" % (indent, name, value))
return lines
def processmessage(self, tags, args):
if self.writer is not None and args:
lines = self.format_message(tags, args)
self.writer(''.join(lines))
try:
self._tag2proc[tags](tags, args)
except KeyError:
pass
def setwriter(self, writer):
self.writer = writer
def setprocessor(self, tags, processor):
if isinstance(tags, str):
tags = tuple(tags.split(":"))
else:
assert isinstance(tags, tuple)
self._tag2proc[tags] = processor
class _TagTracerSub:
def __init__(self, root, tags):
self.root = root
self.tags = tags
def __call__(self, *args):
self.root.processmessage(self.tags, args)
def setmyprocessor(self, processor):
self.root.setprocessor(self.tags, processor)
def get(self, name):
return self.__class__(self.root, self.tags + (name,))
def _raise_wrapfail(wrap_controller, msg):
co = wrap_controller.gi_code
raise RuntimeError("wrap_controller at %r %s:%d %s" %
(co.co_name, co.co_filename, co.co_firstlineno, msg))
def _wrapped_call(wrap_controller, func):
""" Wrap calling to a function with a generator which needs to yield
exactly once. The yield point will trigger calling the wrapped function
and return its _CallOutcome to the yield point. The generator then needs
to finish (raise StopIteration) in order for the wrapped call to complete.
"""
try:
next(wrap_controller) # first yield
except StopIteration:
_raise_wrapfail(wrap_controller, "did not yield")
call_outcome = _CallOutcome(func)
try:
wrap_controller.send(call_outcome)
_raise_wrapfail(wrap_controller, "has second yield")
except StopIteration:
pass
return call_outcome.get_result()
class _CallOutcome:
""" Outcome of a function call, either an exception or a proper result.
Calling the ``get_result`` method will return the result or reraise
the exception raised when the function was called. """
excinfo = None
def __init__(self, func):
try:
self.result = func()
except BaseException:
self.excinfo = sys.exc_info()
def force_result(self, result):
self.result = result
self.excinfo = None
def get_result(self):
if self.excinfo is None:
return self.result
else:
ex = self.excinfo
if _py3:
raise ex[1].with_traceback(ex[2])
_reraise(*ex) # noqa
if not _py3:
exec("""
def _reraise(cls, val, tb):
raise cls, val, tb
""")
class _TracedHookExecution:
def __init__(self, pluginmanager, before, after):
self.pluginmanager = pluginmanager
self.before = before
self.after = after
self.oldcall = pluginmanager._inner_hookexec
assert not isinstance(self.oldcall, _TracedHookExecution)
self.pluginmanager._inner_hookexec = self
def __call__(self, hook, hook_impls, kwargs):
self.before(hook.name, hook_impls, kwargs)
outcome = _CallOutcome(lambda: self.oldcall(hook, hook_impls, kwargs))
self.after(outcome, hook.name, hook_impls, kwargs)
return outcome.get_result()
def undo(self):
self.pluginmanager._inner_hookexec = self.oldcall
class PluginManager(object):
""" Core Pluginmanager class which manages registration
of plugin objects and 1:N hook calling.
You can register new hooks by calling ``addhooks(module_or_class)``.
You can register plugin objects (which contain hooks) by calling
``register(plugin)``. The Pluginmanager is initialized with a
prefix that is searched for in the names of the dict of registered
plugin objects. An optional excludefunc allows to blacklist names which
are not considered as hooks despite a matching prefix.
For debugging purposes you can call ``enable_tracing()``
which will subsequently send debug information to the trace helper.
"""
def __init__(self, project_name, implprefix=None):
""" if implprefix is given implementation functions
will be recognized if their name matches the implprefix. """
self.project_name = project_name
self._name2plugin = {}
self._plugin2hookcallers = {}
self._plugin_distinfo = []
self.trace = _TagTracer().get("pluginmanage")
self.hook = _HookRelay(self.trace.root.get("hook"))
self._implprefix = implprefix
self._inner_hookexec = lambda hook, methods, kwargs: \
_MultiCall(methods, kwargs, hook.spec_opts).execute()
def _hookexec(self, hook, methods, kwargs):
# called from all hookcaller instances.
# enable_tracing will set its own wrapping function at self._inner_hookexec
return self._inner_hookexec(hook, methods, kwargs)
def register(self, plugin, name=None):
""" Register a plugin and return its canonical name or None if the name
is blocked from registering. Raise a ValueError if the plugin is already
registered. """
plugin_name = name or self.get_canonical_name(plugin)
if plugin_name in self._name2plugin or plugin in self._plugin2hookcallers:
if self._name2plugin.get(plugin_name, -1) is None:
return # blocked plugin, return None to indicate no registration
raise ValueError("Plugin already registered: %s=%s\n%s" %
(plugin_name, plugin, self._name2plugin))
# XXX if an error happens we should make sure no state has been
# changed at point of return
self._name2plugin[plugin_name] = plugin
# register matching hook implementations of the plugin
self._plugin2hookcallers[plugin] = hookcallers = []
for name in dir(plugin):
hookimpl_opts = self.parse_hookimpl_opts(plugin, name)
if hookimpl_opts is not None:
normalize_hookimpl_opts(hookimpl_opts)
method = getattr(plugin, name)
hookimpl = HookImpl(plugin, plugin_name, method, hookimpl_opts)
hook = getattr(self.hook, name, None)
if hook is None:
hook = _HookCaller(name, self._hookexec)
setattr(self.hook, name, hook)
elif hook.has_spec():
self._verify_hook(hook, hookimpl)
hook._maybe_apply_history(hookimpl)
hook._add_hookimpl(hookimpl)
hookcallers.append(hook)
return plugin_name
def parse_hookimpl_opts(self, plugin, name):
method = getattr(plugin, name)
res = getattr(method, self.project_name + "_impl", None)
if res is not None and not isinstance(res, dict):
# false positive
res = None
elif res is None and self._implprefix and name.startswith(self._implprefix):
res = {}
return res
def unregister(self, plugin=None, name=None):
""" unregister a plugin object and all its contained hook implementations
from internal data structures. """
if name is None:
assert plugin is not None, "one of name or plugin needs to be specified"
name = self.get_name(plugin)
if plugin is None:
plugin = self.get_plugin(name)
# if self._name2plugin[name] == None registration was blocked: ignore
if self._name2plugin.get(name):
del self._name2plugin[name]
for hookcaller in self._plugin2hookcallers.pop(plugin, []):
hookcaller._remove_plugin(plugin)
return plugin
def set_blocked(self, name):
""" block registrations of the given name, unregister if already registered. """
self.unregister(name=name)
self._name2plugin[name] = None
def is_blocked(self, name):
""" return True if the name blogs registering plugins of that name. """
return name in self._name2plugin and self._name2plugin[name] is None
def add_hookspecs(self, module_or_class):
""" add new hook specifications defined in the given module_or_class.
Functions are recognized if they have been decorated accordingly. """
names = []
for name in dir(module_or_class):
spec_opts = self.parse_hookspec_opts(module_or_class, name)
if spec_opts is not None:
hc = getattr(self.hook, name, None)
if hc is None:
hc = _HookCaller(name, self._hookexec, module_or_class, spec_opts)
setattr(self.hook, name, hc)
else:
# plugins registered this hook without knowing the spec
hc.set_specification(module_or_class, spec_opts)
for hookfunction in (hc._wrappers + hc._nonwrappers):
self._verify_hook(hc, hookfunction)
names.append(name)
if not names:
raise ValueError("did not find any %r hooks in %r" %
(self.project_name, module_or_class))
def parse_hookspec_opts(self, module_or_class, name):
method = getattr(module_or_class, name)
return getattr(method, self.project_name + "_spec", None)
def get_plugins(self):
""" return the set of registered plugins. """
return set(self._plugin2hookcallers)
def is_registered(self, plugin):
""" Return True if the plugin is already registered. """
return plugin in self._plugin2hookcallers
def get_canonical_name(self, plugin):
""" Return canonical name for a plugin object. Note that a plugin
may be registered under a different name which was specified
by the caller of register(plugin, name). To obtain the name
of an registered plugin use ``get_name(plugin)`` instead."""
return getattr(plugin, "__name__", None) or str(id(plugin))
def get_plugin(self, name):
""" Return a plugin or None for the given name. """
return self._name2plugin.get(name)
def get_name(self, plugin):
""" Return name for registered plugin or None if not registered. """
for name, val in self._name2plugin.items():
if plugin == val:
return name
def _verify_hook(self, hook, hookimpl):
if hook.is_historic() and hookimpl.hookwrapper:
raise PluginValidationError(
"Plugin %r\nhook %r\nhistoric incompatible to hookwrapper" %
(hookimpl.plugin_name, hook.name))
for arg in hookimpl.argnames:
if arg not in hook.argnames:
raise PluginValidationError(
"Plugin %r\nhook %r\nargument %r not available\n"
"plugin definition: %s\n"
"available hookargs: %s" %
(hookimpl.plugin_name, hook.name, arg,
_formatdef(hookimpl.function), ", ".join(hook.argnames)))
def check_pending(self):
""" Verify that all hooks which have not been verified against
a hook specification are optional, otherwise raise PluginValidationError"""
for name in self.hook.__dict__:
if name[0] != "_":
hook = getattr(self.hook, name)
if not hook.has_spec():
for hookimpl in (hook._wrappers + hook._nonwrappers):
if not hookimpl.optionalhook:
raise PluginValidationError(
"unknown hook %r in plugin %r" %
(name, hookimpl.plugin))
def load_setuptools_entrypoints(self, entrypoint_name):
""" Load modules from querying the specified setuptools entrypoint name.
Return the number of loaded plugins. """
from pkg_resources import iter_entry_points, DistributionNotFound
for ep in iter_entry_points(entrypoint_name):
# is the plugin registered or blocked?
if self.get_plugin(ep.name) or self.is_blocked(ep.name):
continue
try:
plugin = ep.load()
except DistributionNotFound:
continue
self.register(plugin, name=ep.name)
self._plugin_distinfo.append((plugin, ep.dist))
return len(self._plugin_distinfo)
def list_plugin_distinfo(self):
""" return list of distinfo/plugin tuples for all setuptools registered
plugins. """
return list(self._plugin_distinfo)
def list_name_plugin(self):
""" return list of name/plugin pairs. """
return list(self._name2plugin.items())
def get_hookcallers(self, plugin):
""" get all hook callers for the specified plugin. """
return self._plugin2hookcallers.get(plugin)
def add_hookcall_monitoring(self, before, after):
""" add before/after tracing functions for all hooks
and return an undo function which, when called,
will remove the added tracers.
``before(hook_name, hook_impls, kwargs)`` will be called ahead
of all hook calls and receive a hookcaller instance, a list
of HookImpl instances and the keyword arguments for the hook call.
``after(outcome, hook_name, hook_impls, kwargs)`` receives the
same arguments as ``before`` but also a :py:class:`_CallOutcome`` object
which represents the result of the overall hook call.
"""
return _TracedHookExecution(self, before, after).undo
def enable_tracing(self):
""" enable tracing of hook calls and return an undo function. """
hooktrace = self.hook._trace
def before(hook_name, methods, kwargs):
hooktrace.root.indent += 1
hooktrace(hook_name, kwargs)
def after(outcome, hook_name, methods, kwargs):
if outcome.excinfo is None:
hooktrace("finish", hook_name, "-->", outcome.result)
hooktrace.root.indent -= 1
return self.add_hookcall_monitoring(before, after)
def subset_hook_caller(self, name, remove_plugins):
""" Return a new _HookCaller instance for the named method
which manages calls to all registered plugins except the
ones from remove_plugins. """
orig = getattr(self.hook, name)
plugins_to_remove = [plug for plug in remove_plugins if hasattr(plug, name)]
if plugins_to_remove:
hc = _HookCaller(orig.name, orig._hookexec, orig._specmodule_or_class,
orig.spec_opts)
for hookimpl in (orig._wrappers + orig._nonwrappers):
plugin = hookimpl.plugin
if plugin not in plugins_to_remove:
hc._add_hookimpl(hookimpl)
# we also keep track of this hook caller so it
# gets properly removed on plugin unregistration
self._plugin2hookcallers.setdefault(plugin, []).append(hc)
return hc
return orig
class _MultiCall:
""" execute a call into multiple python functions/methods. """
# XXX note that the __multicall__ argument is supported only
# for pytest compatibility reasons. It was never officially
# supported there and is explicitely deprecated since 2.8
# so we can remove it soon, allowing to avoid the below recursion
# in execute() and simplify/speed up the execute loop.
def __init__(self, hook_impls, kwargs, specopts={}):
self.hook_impls = hook_impls
self.kwargs = kwargs
self.kwargs["__multicall__"] = self
self.specopts = specopts
def execute(self):
all_kwargs = self.kwargs
self.results = results = []
firstresult = self.specopts.get("firstresult")
while self.hook_impls:
hook_impl = self.hook_impls.pop()
args = [all_kwargs[argname] for argname in hook_impl.argnames]
if hook_impl.hookwrapper:
return _wrapped_call(hook_impl.function(*args), self.execute)
res = hook_impl.function(*args)
if res is not None:
if firstresult:
return res
results.append(res)
if not firstresult:
return results
def __repr__(self):
status = "%d meths" % (len(self.hook_impls),)
if hasattr(self, "results"):
status = ("%d results, " % len(self.results)) + status
return "<_MultiCall %s, kwargs=%r>" % (status, self.kwargs)
def varnames(func, startindex=None):
""" 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 cache["_varnames"]
except KeyError:
pass
if inspect.isclass(func):
try:
func = func.__init__
except AttributeError:
return ()
startindex = 1
else:
if not inspect.isfunction(func) and not inspect.ismethod(func):
func = getattr(func, '__call__', func)
if startindex is None:
startindex = int(inspect.ismethod(func))
try:
rawcode = func.__code__
except AttributeError:
return ()
try:
x = rawcode.co_varnames[startindex:rawcode.co_argcount]
except AttributeError:
x = ()
else:
defaults = func.__defaults__
if defaults:
x = x[:-len(defaults)]
try:
cache["_varnames"] = x
except TypeError:
pass
return x
class _HookRelay:
""" hook holder object for performing 1:N hook calls where N is the number
of registered plugins.
"""
def __init__(self, trace):
self._trace = trace
class _HookCaller(object):
def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None):
self.name = name
self._wrappers = []
self._nonwrappers = []
self._hookexec = hook_execute
if specmodule_or_class is not None:
assert spec_opts is not None
self.set_specification(specmodule_or_class, spec_opts)
def has_spec(self):
return hasattr(self, "_specmodule_or_class")
def set_specification(self, specmodule_or_class, spec_opts):
assert not self.has_spec()
self._specmodule_or_class = specmodule_or_class
specfunc = getattr(specmodule_or_class, self.name)
argnames = varnames(specfunc, startindex=inspect.isclass(specmodule_or_class))
assert "self" not in argnames # sanity check
self.argnames = ["__multicall__"] + list(argnames)
self.spec_opts = spec_opts
if spec_opts.get("historic"):
self._call_history = []
def is_historic(self):
return hasattr(self, "_call_history")
def _remove_plugin(self, plugin):
def remove(wrappers):
for i, method in enumerate(wrappers):
if method.plugin == plugin:
del wrappers[i]
return True
if remove(self._wrappers) is None:
if remove(self._nonwrappers) is None:
raise ValueError("plugin %r not found" % (plugin,))
def _add_hookimpl(self, hookimpl):
if hookimpl.hookwrapper:
methods = self._wrappers
else:
methods = self._nonwrappers
if hookimpl.trylast:
methods.insert(0, hookimpl)
elif hookimpl.tryfirst:
methods.append(hookimpl)
else:
# find last non-tryfirst method
i = len(methods) - 1
while i >= 0 and methods[i].tryfirst:
i -= 1
methods.insert(i + 1, hookimpl)
def __repr__(self):
return "<_HookCaller %r>" % (self.name,)
def __call__(self, **kwargs):
assert not self.is_historic()
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
def call_historic(self, proc=None, kwargs=None):
self._call_history.append((kwargs or {}, proc))
# historizing hooks don't return results
self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
def call_extra(self, methods, kwargs):
""" Call the hook with some additional temporarily participating
methods using the specified kwargs as call parameters. """
old = list(self._nonwrappers), list(self._wrappers)
for method in methods:
opts = dict(hookwrapper=False, trylast=False, tryfirst=False)
hookimpl = HookImpl(None, "<temp>", method, opts)
self._add_hookimpl(hookimpl)
try:
return self(**kwargs)
finally:
self._nonwrappers, self._wrappers = old
def _maybe_apply_history(self, method):
if self.is_historic():
for kwargs, proc in self._call_history:
res = self._hookexec(self, [method], kwargs)
if res and proc is not None:
proc(res[0])
class HookImpl:
def __init__(self, plugin, plugin_name, function, hook_impl_opts):
self.function = function
self.argnames = varnames(self.function)
self.plugin = plugin
self.opts = hook_impl_opts
self.plugin_name = plugin_name
self.__dict__.update(hook_impl_opts)
class PluginValidationError(Exception):
""" plugin failed validation. """
if hasattr(inspect, 'signature'):
def _formatdef(func):
return "%s%s" % (
func.__name__,
str(inspect.signature(func))
)
else:
def _formatdef(func):
return "%s%s" % (
func.__name__,
inspect.formatargspec(*inspect.getargspec(func))
)

98
appveyor.yml Normal file
View File

@@ -0,0 +1,98 @@
environment:
matrix:
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x" # currently 2.7.9
PYTHON_ARCH: "32"
TESTENV: "py27"
- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7.x" # currently 2.7.9
PYTHON_ARCH: "64"
TESTENV: "py27"
- PYTHON: "C:\\Python33"
PYTHON_VERSION: "3.3.x" # currently 3.3.5
PYTHON_ARCH: "32"
TESTENV: "py33"
- PYTHON: "C:\\Python33-x64"
PYTHON_VERSION: "3.3.x" # currently 3.3.5
PYTHON_ARCH: "64"
TESTENV: "py33"
- PYTHON: "C:\\Python34"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
PYTHON_ARCH: "32"
TESTENV: "py34"
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
PYTHON_ARCH: "64"
TESTENV: "py34"
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5.x" # currently 3.5.0
PYTHON_ARCH: "32"
TESTENV: "py35"
- PYTHON: "C:\\Python35-x64"
PYTHON_VERSION: "3.5.x" # currently 3.5.0
PYTHON_ARCH: "64"
TESTENV: "py35"
# Also test a Python version not pre-installed
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
- PYTHON: "C:\\Python266"
PYTHON_VERSION: "2.6.6"
PYTHON_ARCH: "32"
TESTENV: "py26"
# xdist testing
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x" # currently 2.7.9
PYTHON_ARCH: "32"
TESTENV: "py27-xdist"
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5.x" # currently 3.5.0
PYTHON_ARCH: "32"
TESTENV: "py35-xdist"
install:
- ECHO "Filesystem root:"
- ps: "ls \"C:/\""
- ECHO "Installed SDKs:"
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
# Install Python (from the official .msi of http://python.org) and pip when
# not already installed.
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
# Prepend newly installed Python to the PATH of this build (this cannot be
# done from inside the powershell script as it would require to restart
# the parent CMD process).
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
# Check that we have the expected version and architecture for Python
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
# Install the build dependencies of the project. If some dependencies contain
# compiled extensions and are not provided as pre-built wheel packages,
# pip will build them from source using the MSVC compiler matching the
# target Python version and architecture
- C:\Python27\python -m pip install tox
build: false # Not a C# project, build stuff at the test step instead.
test_script:
# Build the compiled extension and run the project tests
- C:\Python27\python -m tox -e %TESTENV%

180
appveyor/install.ps1 Normal file
View File

@@ -0,0 +1,180 @@
# Sample script to install Python and pip under Windows
# Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
$BASE_URL = "https://www.python.org/ftp/python/"
$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
$GET_PIP_PATH = "C:\get-pip.py"
function DownloadPython ($python_version, $platform_suffix) {
$webclient = New-Object System.Net.WebClient
$filename = "python-" + $python_version + $platform_suffix + ".msi"
$url = $BASE_URL + $python_version + "/" + $filename
$basedir = $pwd.Path + "\"
$filepath = $basedir + $filename
if (Test-Path $filename) {
Write-Host "Reusing" $filepath
return $filepath
}
# Download and retry up to 3 times in case of network transient errors.
Write-Host "Downloading" $filename "from" $url
$retry_attempts = 2
for($i=0; $i -lt $retry_attempts; $i++){
try {
$webclient.DownloadFile($url, $filepath)
break
}
Catch [Exception]{
Start-Sleep 1
}
}
if (Test-Path $filepath) {
Write-Host "File saved at" $filepath
} else {
# Retry once to get the error message if any at the last try
$webclient.DownloadFile($url, $filepath)
}
return $filepath
}
function InstallPython ($python_version, $architecture, $python_home) {
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
if (Test-Path $python_home) {
Write-Host $python_home "already exists, skipping."
return $false
}
if ($architecture -eq "32") {
$platform_suffix = ""
} else {
$platform_suffix = ".amd64"
}
$msipath = DownloadPython $python_version $platform_suffix
Write-Host "Installing" $msipath "to" $python_home
$install_log = $python_home + ".log"
$install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
$uninstall_args = "/qn /x $msipath"
RunCommand "msiexec.exe" $install_args
if (-not(Test-Path $python_home)) {
Write-Host "Python seems to be installed else-where, reinstalling."
RunCommand "msiexec.exe" $uninstall_args
RunCommand "msiexec.exe" $install_args
}
if (Test-Path $python_home) {
Write-Host "Python $python_version ($architecture) installation complete"
} else {
Write-Host "Failed to install Python in $python_home"
Get-Content -Path $install_log
Exit 1
}
}
function RunCommand ($command, $command_args) {
Write-Host $command $command_args
Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
}
function InstallPip ($python_home) {
$pip_path = $python_home + "\Scripts\pip.exe"
$python_path = $python_home + "\python.exe"
if (-not(Test-Path $pip_path)) {
Write-Host "Installing pip..."
$webclient = New-Object System.Net.WebClient
$webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
Write-Host "Executing:" $python_path $GET_PIP_PATH
Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru
} else {
Write-Host "pip already installed."
}
}
function DownloadMiniconda ($python_version, $platform_suffix) {
$webclient = New-Object System.Net.WebClient
if ($python_version -eq "3.4") {
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
} else {
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
}
$url = $MINICONDA_URL + $filename
$basedir = $pwd.Path + "\"
$filepath = $basedir + $filename
if (Test-Path $filename) {
Write-Host "Reusing" $filepath
return $filepath
}
# Download and retry up to 3 times in case of network transient errors.
Write-Host "Downloading" $filename "from" $url
$retry_attempts = 2
for($i=0; $i -lt $retry_attempts; $i++){
try {
$webclient.DownloadFile($url, $filepath)
break
}
Catch [Exception]{
Start-Sleep 1
}
}
if (Test-Path $filepath) {
Write-Host "File saved at" $filepath
} else {
# Retry once to get the error message if any at the last try
$webclient.DownloadFile($url, $filepath)
}
return $filepath
}
function InstallMiniconda ($python_version, $architecture, $python_home) {
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
if (Test-Path $python_home) {
Write-Host $python_home "already exists, skipping."
return $false
}
if ($architecture -eq "32") {
$platform_suffix = "x86"
} else {
$platform_suffix = "x86_64"
}
$filepath = DownloadMiniconda $python_version $platform_suffix
Write-Host "Installing" $filepath "to" $python_home
$install_log = $python_home + ".log"
$args = "/S /D=$python_home"
Write-Host $filepath $args
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
if (Test-Path $python_home) {
Write-Host "Python $python_version ($architecture) installation complete"
} else {
Write-Host "Failed to install Python in $python_home"
Get-Content -Path $install_log
Exit 1
}
}
function InstallMinicondaPip ($python_home) {
$pip_path = $python_home + "\Scripts\pip.exe"
$conda_path = $python_home + "\Scripts\conda.exe"
if (-not(Test-Path $pip_path)) {
Write-Host "Installing pip..."
$args = "install --yes pip"
Write-Host $conda_path $args
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
} else {
Write-Host "pip already installed."
}
}
function main () {
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
InstallPip $env:PYTHON
}
main

View File

@@ -1,10 +1,12 @@
import sys
if __name__ == '__main__':
import cProfile
import py
import pytest
import pstats
stats = cProfile.run('py.test.cmdline.main(["empty.py", ])', 'prof')
script = sys.argv[1:] if len(sys.argv) > 1 else "empty.py"
stats = cProfile.run('pytest.cmdline.main(%r)' % script, 'prof')
p = pstats.Stats("prof")
p.strip_dirs()
p.sort_stats('cumulative')
print(p.print_stats(30))
print(p.print_stats(500))

View File

@@ -0,0 +1,19 @@
# 10000 iterations, just for relative comparison
# 2.7.5 3.3.2
# FilesCompleter 75.1109 69.2116
# FastFilesCompleter 0.7383 1.0760
if __name__ == '__main__':
import sys
import timeit
from argcomplete.completers import FilesCompleter
from _pytest._argcomplete import FastFilesCompleter
count = 1000 # only a few seconds
setup = 'from __main__ import FastFilesCompleter\nfc = FastFilesCompleter()'
run = 'fc("/d")'
sys.stdout.write('%s\n' % (timeit.timeit(run,
setup=setup.replace('Fast', ''), number=count)))
sys.stdout.write('%s\n' % (timeit.timeit(run, setup=setup, number=count)))

12
bench/manyparam.py Normal file
View File

@@ -0,0 +1,12 @@
import pytest
@pytest.fixture(scope='module', params=range(966))
def foo(request):
return request.param
def test_it(foo):
pass
def test_it2(foo):
pass

10
bench/skip.py Normal file
View File

@@ -0,0 +1,10 @@
import pytest
SKIP = True
@pytest.mark.parametrize("x", xrange(5000))
def test_foo(x):
if SKIP:
pytest.skip("heh")

View File

@@ -1,497 +0,0 @@
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import sys
import time
import fnmatch
import tempfile
import tarfile
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.27"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
finally:
os.chdir(old_wd)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>="+version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
if was_imported:
sys.stderr.write(
"The required version of distribute (>=%s) is not available,\n"
"and can't be installed while this script is running. Please\n"
"install a more recent version first, using\n"
"'easy_install -U distribute'."
"\n\n(Currently using %r)\n" % (version, e.args[0]))
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return _do_download(version, download_base, to_dir,
download_delay)
except pkg_resources.DistributionNotFound:
return _do_download(version, download_base, to_dir,
download_delay)
finally:
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
`version` should be a valid distribute version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download
attempt.
"""
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
tgz_name = "distribute-%s.tar.gz" % version
url = download_base + tgz_name
saveto = os.path.join(to_dir, tgz_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
log.warn("Downloading %s", url)
src = urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = src.read()
dst = open(saveto, "wb")
dst.write(data)
finally:
if src:
src.close()
if dst:
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
from setuptools.sandbox import DirectorySandbox
if not hasattr(DirectorySandbox, '_old'):
def violation(*args):
pass
DirectorySandbox._old = DirectorySandbox._violation
DirectorySandbox._violation = violation
patched = True
else:
patched = False
except ImportError:
patched = False
try:
return function(*args, **kw)
finally:
if patched:
DirectorySandbox._violation = DirectorySandbox._old
del DirectorySandbox._old
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
existing_content = open(path).read()
if existing_content == content:
# already patched
log.warn('Already patched.')
return False
log.warn('Patching...')
_rename_path(path)
f = open(path, 'w')
try:
f.write(content)
finally:
f.close()
return True
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
return open(path).read() == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s into %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
return False
found = False
for file in os.listdir(placeholder):
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
found = True
break
if not found:
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Removing elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
else:
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
if not patched:
log.warn('%s already patched.', pkg_info)
return False
# now let's move the files out of the way
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
element = os.path.join(placeholder, element)
if os.path.exists(element):
_rename_path(element)
else:
log.warn('Could not find the %s element of the '
'Setuptools distribution', element)
return True
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
return
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
(SETUPTOOLS_FAKED_VERSION, pyver)
pkg_info = os.path.join(placeholder, setuptools_file)
if os.path.exists(pkg_info):
log.warn('%s already exists', pkg_info)
return
if not os.access(pkg_info, os.W_OK):
log.warn("Don't have permissions to write %s, skipping", pkg_info)
log.warn('Creating %s', pkg_info)
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
pth_file = os.path.join(placeholder, 'setuptools.pth')
log.warn('Creating %s', pth_file)
f = open(pth_file, 'w')
try:
f.write(os.path.join(os.curdir, setuptools_file))
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
def _patch_egg_dir(path):
# let's check if it's already patched
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
if os.path.exists(pkg_info):
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
log.warn('%s already patched.', pkg_info)
return False
_rename_path(path)
os.mkdir(path)
os.mkdir(os.path.join(path, 'EGG-INFO'))
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
f = open(pkg_info, 'w')
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
f.close()
return True
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install')+1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
top_dir = arg.split('root=')[-1]
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index+1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
return True
def _fake_setuptools():
log.warn('Scanning installed packages')
try:
import pkg_resources
except ImportError:
# we're cool
log.warn('Setuptools or Distribute does not seem to be installed.')
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
replacement=False))
except TypeError:
# old distribute API
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
if setuptools_dist is None:
log.warn('No setuptools distribution found')
return
# detecting if it was already faked
setuptools_location = setuptools_dist.location
log.warn('Setuptools installation detected at %s', setuptools_location)
# if --root or --preix was provided, and if
# setuptools is not located in them, we don't patch it
if not _under_prefix(setuptools_location):
log.warn('Not patching, --root or --prefix is installing Distribute'
' in another location')
return
# let's see if its an egg
if not setuptools_location.endswith('.egg'):
log.warn('Non-egg installation')
res = _remove_flat_installation(setuptools_location)
if not res:
return
else:
log.warn('Egg installation')
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
if (os.path.exists(pkg_info) and
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
log.warn('Already patched.')
return
log.warn('Patching...')
# let's create a fake egg replacing setuptools one
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patched done.')
_relaunch()
def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
def _extractall(self, path=".", members=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers().
"""
import copy
import operator
from tarfile import ExtractError
directories = []
if members is None:
members = self
for tarinfo in members:
if tarinfo.isdir():
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
if sys.version_info < (2, 4):
def sorter(dir1, dir2):
return cmp(dir1.name, dir2.name)
directories.sort(sorter)
directories.reverse()
else:
directories.sort(key=operator.attrgetter('name'), reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
dirpath = os.path.join(path, tarinfo.name)
try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError:
e = sys.exc_info()[1]
if self.errorlevel > 1:
raise
else:
self._dbg(1, "tarfile: %s" % e)
def _build_install_args(argv):
install_args = []
user_install = '--user' in argv
if user_install and sys.version_info < (2,6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
if user_install:
install_args.append('--user')
return install_args
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools()
_install(tarball, _build_install_args(argv))
if __name__ == '__main__':
main(sys.argv[1:])

View File

@@ -12,46 +12,49 @@ PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
SITETARGET=latest
REGENDOC_ARGS := \
--normalize "/={8,} (.*) ={8,}/======= \1 ========/" \
--normalize "/_{8,} (.*) _{8,}/_______ \1 ________/" \
--normalize "/in \d+.\d+ seconds/in 0.12 seconds/" \
--normalize "@/tmp/pytest-of-.*/pytest-\d+@PYTEST_TMPDIR@" \
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
regen:
PYTHONDONTWRITEBYTECODE=1 COLUMNS=76 regendoc --update *.txt */*.txt
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " showtarget to show the pytest.org target directory"
@echo " install to install docs to pytest.org/SITETARGET"
@echo " install-ldf to install the doc pdf to pytest.org/SITETARGET"
@echo " regen to regenerate pytest examples using the installed pytest"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
SITETARGET=$(shell ./_getdoctarget.py)
showtarget:
@echo $(SITETARGET)
install: html
rsync -avz _build/html/ pytest.org:/www/pytest.org/$(SITETARGET)
# for access talk to someone with login rights to
# pytest-dev@pytest.org to add your ssh key
rsync -avz _build/html/ pytest-dev@pytest.org:pytest.org/$(SITETARGET)
installpdf: latexpdf
@scp $(BUILDDIR)/latex/pytest.pdf pytest.org:/www/pytest.org/$(SITETARGET)
@scp $(BUILDDIR)/latex/pytest.pdf pytest-dev@pytest.org:pytest.org/$(SITETARGET)
installall: clean install installpdf
@echo "done"
regen:
PYTHONDONTWRITEBYTECODE=1 COLUMNS=76 regendoc --update *.rst */*.rst ${REGENDOC_ARGS}
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo

16
doc/en/_getdoctarget.py Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env python
import py
def get_version_string():
fn = py.path.local(__file__).join("..", "..", "..",
"_pytest", "__init__.py")
for line in fn.readlines():
if "version" in line and not line.strip().startswith('#'):
return eval(line.split("=")[-1])
def get_minor_version_string():
return ".".join(get_version_string().split(".")[:2])
if __name__ == "__main__":
print (get_minor_version_string())

View File

@@ -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;
}

View File

@@ -0,0 +1,17 @@
<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
<ul>
<li><a href="{{ pathto('index') }}">Home</a></li>
<li><a href="{{ pathto('contents') }}">Contents</a></li>
<li><a href="{{ pathto('getting-started') }}">Install</a></li>
<li><a href="{{ pathto('example/index') }}">Examples</a></li>
<li><a href="{{ pathto('customize') }}">Customize</a></li>
<li><a href="{{ pathto('contact') }}">Contact</a></li>
<li><a href="{{ pathto('talks') }}">Talks/Posts</a></li>
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
</ul>
{%- if display_toc %}
<hr>
{{ toc }}
{%- endif %}

View File

@@ -1,22 +0,0 @@
<h3>Download</h3>
{% if version.endswith('(hg)') %}
<p>This documentation is for version <b>{{ version }}</b>, which is
not released yet.</p>
<p>You can use it from the
<a href="http://bitbucket.org/hpk42/pytest">Bitbucket Repo</a> or look for
released versions in the <a href="http://pypi.python.org/pypi/pytest">Python
Package Index</a>.</p>
{% else %}
<p><b><a href="{{ pathto('announce/index')}}">{{ release }} release</a></b>
[<a href="{{ pathto('changelog') }}">Changelog</a>]</p>
<p>
<a href="http://pypi.python.org/pypi/pytest">pytest/PyPI</a>
</p>
<pre>easy_install pytest</pre>
<pre>pip install pytest</pre>
{% endif %}
<h3>Questions? Suggestions?</h3>
<p><a href="{{ pathto('contact') }}">contact channels</a>
</p>

View File

@@ -1,10 +1,5 @@
{% extends "!layout.html" %}
{% block relbaritems %}
{{ super() }}
<g:plusone></g:plusone>
{% endblock %}
{% block footer %}
{{ super() }}
<script type="text/javascript">
@@ -20,5 +15,4 @@
})();
</script>
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
{% endblock %}

View File

@@ -0,0 +1,11 @@
<h3>Useful Links</h3>
<ul>
<li><a href="{{ pathto('index') }}">The pytest Website</a></li>
<li><a href="{{ pathto('contributing') }}">Contribution Guide</a></li>
<li><a href="https://pypi.python.org/pypi/pytest">pytest @ PyPI</a></li>
<li><a href="https://github.com/pytest-dev/pytest/">pytest @ GitHub</a></li>
<li><a href="http://pytest.org/latest/plugins_index/index.html">3rd party plugins</a></li>
<li><a href="https://github.com/pytest-dev/pytest/issues">Issue Tracker</a></li>
<li><a href="http://pytest.org/latest/pytest.pdf">PDF Documentation</a>
</ul>

View File

@@ -1,37 +0,0 @@
{%- if pagename != "search" %}
<div id="searchbox" style="display: none">
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="{{ _('Search') }}" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
{%- endif %}
<h3>quicklinks</h3>
<div style="text-align: left; font-size: 100%; vertical-align: middle;">
<table>
<tr>
<td>
<a href="{{ pathto('index') }}">home</a>
</td><td>
<a href="{{ pathto('contents') }}">TOC/contents</a>
</td></tr><tr><td>
<a href="{{ pathto('getting-started') }}">install</a>
</td><td>
<a href="{{ pathto('changelog') }}">changelog</a>
</td></tr><tr><td>
<a href="{{ pathto('example/index') }}">examples</a>
</td><td>
<a href="{{ pathto('customize') }}">customize</a>
</td></tr><tr><td>
<a href="https://bitbucket.org/hpk42/pytest/issues?status=new&status=open">issues[bb]</a>
</td><td>
<a href="{{ pathto('contact') }}">contact</a>
</td></tr></table>
</div>
{% extends "basic/localtoc.html" %}

View File

@@ -0,0 +1,5 @@
<h3>About pytest</h3>
<p>
pytest is a mature full-featured Python testing tool that helps
you write better programs.
</p>

3
doc/en/_themes/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.pyc
*.pyo
.DS_Store

37
doc/en/_themes/LICENSE Normal file
View File

@@ -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.

31
doc/en/_themes/README Normal file
View File

@@ -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

View File

@@ -0,0 +1,24 @@
{%- extends "basic/layout.html" %}
{%- block extrahead %}
{{ super() }}
{% if theme_touch_icon %}
<link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" />
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9">
{% endblock %}
{%- block relbar2 %}{% endblock %}
{% block header %}
{{ super() }}
{% if pagename == 'index' %}
<div class=indexwrapper>
{% endif %}
{% endblock %}
{%- block footer %}
<div class="footer">
&copy; Copyright {{ copyright }}.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
</div>
{% if pagename == 'index' %}
</div>
{% endif %}
{%- endblock %}

View File

@@ -0,0 +1,19 @@
<h3>Related Topics</h3>
<ul>
<li><a href="{{ pathto(master_doc) }}">Documentation overview</a><ul>
{%- for parent in parents %}
<li><a href="{{ parent.link|e }}">{{ parent.title }}</a><ul>
{%- endfor %}
{%- if prev %}
<li>Previous: <a href="{{ prev.link|e }}" title="{{ _('previous chapter')
}}">{{ prev.title }}</a></li>
{%- endif %}
{%- if next %}
<li>Next: <a href="{{ next.link|e }}" title="{{ _('next chapter')
}}">{{ next.title }}</a></li>
{%- endif %}
{%- for parent in parents %}
</ul></li>
{%- endfor %}
</ul></li>
</ul>

View File

@@ -0,0 +1,557 @@
/*
* flasky.css_t
* ~~~~~~~~~~~~
*
* :copyright: Copyright 2010 by Armin Ronacher.
* :license: Flask Design License, see LICENSE for details.
*/
{% set page_width = '1020px' %}
{% set sidebar_width = '220px' %}
/* orange of logo is #d67c29 but we use black for links for now */
{% set link_color = '#000' %}
{% set link_hover_color = '#000' %}
{% set base_font = 'sans-serif' %}
{% set header_font = 'serif' %}
@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, code {
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.9em;
background: #eee;
}
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;
}

View File

@@ -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 =

View File

@@ -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'
}

78
doc/en/adopt.rst Normal file
View File

@@ -0,0 +1,78 @@
April 2015 is "adopt pytest month"
=============================================
Are you an enthusiastic pytest user, the local testing guru in your workplace? Or are you considering using pytest for your open source project, but not sure how to get started? Then you may be interested in "adopt pytest month"!
We will pair experienced pytest users with open source projects, for a month's effort of getting new development teams started with pytest.
In 2015 we are trying this for the first time. In February and March 2015 we will gather volunteers on both sides, in April we will do the work, and in May we will evaluate how it went. This effort is being coordinated by Brianna Laugher. If you have any questions or comments, you can raise them on the `@pytestdotorg twitter account <https://twitter.com/pytestdotorg>`_ the `issue tracker`_ or the `pytest-dev mailing list`_.
.. _`issue tracker`: https://github.com/pytest-dev/pytest/issues/676
.. _`pytest-dev mailing list`: https://mail.python.org/mailman/listinfo/pytest-dev
The ideal pytest helper
-----------------------------------------
- will be able to commit 2-4 hours a week to working with their particular project (this might involve joining their mailing list, installing the software and exploring any existing tests, offering advice, writing some example tests)
- feels confident in using pytest (e.g. has explored command line options, knows how to write parametrized tests, has an idea about conftest contents)
- does not need to be an expert in every aspect!
`Pytest helpers, sign up here`_! (preferably in February, hard deadline 22 March)
.. _`Pytest helpers, sign up here`: http://goo.gl/forms/nxqAhqWt1P
The ideal partner project
-----------------------------------------
- is open source, and predominantly written in Python
- has an automated/documented install process for developers
- has more than one core developer
- has at least one official release (e.g. is available on pypi)
- has the support of the core development team, in trying out pytest adoption
- has no tests... or 100% test coverage... or somewhere in between!
`Partner projects, sign up here`_! (by 22 March)
.. _`Partner projects, sign up here`: http://goo.gl/forms/ZGyqlHiwk3
What does it mean to "adopt pytest"?
-----------------------------------------
There can be many different definitions of "success". Pytest can run many `nose and unittest`_ tests by default, so using pytest as your testrunner may be possible from day 1. Job done, right?
Progressive success might look like:
- tests can be run (by pytest) without errors (there may be failures)
- tests can be run (by pytest) without failures
- test runner is integrated into CI server
- existing tests are rewritten to take advantage of pytest features - this can happen in several iterations, for example:
- changing to native assert_ statements (pycmd_ has a script to help with that, ``pyconvert_unittest.py``)
- changing `setUp/tearDown methods`_ to fixtures_
- adding markers_
- other changes to reduce boilerplate
- assess needs for future tests to be written, e.g. new fixtures, distributed_ testing tweaks
"Success" should also include that the development team feels comfortable with their knowledge of how to use pytest. In fact this is probably more important than anything else. So spending a lot of time on communication, giving examples, etc will probably be important - both in running the tests, and in writing them.
It may be after the month is up, the partner project decides that pytest is not right for it. That's okay - hopefully the pytest team will also learn something about its weaknesses or deficiencies.
.. _`nose and unittest`: faq.html#how-does-pytest-relate-to-nose-and-unittest
.. _assert: asserts.html
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
.. _`setUp/tearDown methods`: xunit_setup.html
.. _fixtures: fixture.html
.. _markers: markers.html
.. _distributed: xdist.html
Other ways to help
-----------------------------------------
Promote! Do your favourite open source Python projects use pytest? If not, why not tell them about this page?

View File

@@ -5,6 +5,21 @@ Release announcements
.. toctree::
:maxdepth: 2
release-2.8.2
release-2.7.2
release-2.7.1
release-2.7.0
release-2.6.3
release-2.6.2
release-2.6.1
release-2.6.0
release-2.5.2
release-2.5.1
release-2.5.0
release-2.4.2
release-2.4.1
release-2.4.0
release-2.3.5
release-2.3.4
release-2.3.3
release-2.3.2

Some files were not shown because too many files have changed in this diff Show More