Compare commits

...

207 Commits

Author SHA1 Message Date
Ran Benita
e0ea00a70d Merge pull request #7798 from bluetech/cherry-pick-release
Cherry-pick 6.1.0 release notes
2020-09-26 21:24:11 +03:00
Ran Benita
19c78ab574 Merge pull request #7797 from pytest-dev/release-6.1.0
Prepare release 6.1.0

(cherry picked from commit 08a1ab3a8a)
2020-09-26 21:11:48 +03:00
Ran Benita
0b327cc75b Merge pull request #7796 from bluetech/changelog-cleanups
changelog: some consistency cleanups
2020-09-26 20:13:45 +03:00
Ran Benita
d3c746eb8e changelog: some consistency cleanups 2020-09-26 20:04:17 +03:00
Kamran Ahmad
d3f47bf346 Improved 'Declaring new hooks' section in docs. (#7782)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-09-23 11:15:55 -03:00
Bruno Oliveira
3db24893b4 Merge pull request #7784 from nicoddemus/use-new-pip-solver-7783
Use new pip resolver in plugins tox env
2020-09-23 09:32:02 -03:00
Bruno Oliveira
8215625135 Use new pip resolver in plugins tox env
Fix #7783
2020-09-23 09:16:48 -03:00
Ran Benita
5cfd7c0ddd Merge pull request #7780 from bluetech/final
Mark some public and to-be-public classes as `@final`
2020-09-23 13:42:11 +03:00
Ran Benita
a99ca879e7 Mark some public and to-be-public classes as @final
This indicates at least for people using type checkers that these
classes are not designed for inheritance and we make no stability
guarantees regarding inheritance of them.

Currently this doesn't show up in the docs. Sphinx does actually support
`@final`, however it only works when imported directly from `typing`,
while we import from `_pytest.compat`.

In the future there might also be a `@sealed` decorator which would
cover some more cases.
2020-09-22 12:40:40 +03:00
Bruno Oliveira
050c2df737 Use multiple issue template types and mention Discussions (#7739) 2020-09-21 20:22:25 +02:00
Bruno Oliveira
cdfdb3a25d Add docs about reusing fixtures from other projects (#7772)
Co-authored-by: Ran Benita <ran@unusedvar.com>
2020-09-19 16:10:22 -03:00
Ran Benita
8eefe4eaf5 Merge pull request #7741 from bluetech/releasing-order
RELEASING: ~~first merge PR, then tag~~ clarify where to push the tag
2020-09-19 22:01:00 +03:00
Sorin Sbarnea
b031a7cecf Smoke tests for assorted plugins (#7721)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
Co-authored-by: Kyle Altendorf <sda@fstab.net>
2020-09-19 15:56:52 -03:00
Ran Benita
027415502a RELEASING: clarify where to push the tag 2020-09-19 21:35:17 +03:00
Ran Benita
9f164b7227 Merge pull request #7766 from nicoddemus/backporting-docs
Add guidelines section about backporting
2020-09-19 21:18:41 +03:00
Ran Benita
4e460cdd9e Merge pull request #7773 from nicoddemus/xml-properties-xdist-docs
Warning about record_testsuite_property not working with xdist
2020-09-19 21:06:40 +03:00
Florian Bruhin
89305e7b09 Improve output for missing config keys (#7572)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-09-19 12:57:29 -03:00
Bruno Oliveira
c4ce5f2c98 Warning about record_testsuite_property not working with xdist
Related to #7767
2020-09-19 12:36:08 -03:00
Bruno Oliveira
9bfd14a443 Merge pull request #7749 from bluetech/fix-get_source-crash 2020-09-19 10:38:32 -03:00
Bruno Oliveira
895a8cf296 Add guidelines section about backporting
From https://github.com/pytest-dev/pytest/pull/7723#issuecomment-693310439
2020-09-17 10:06:04 -03:00
Bruno Oliveira
98608c439f Merge pull request #7760 from finn0/docs/punctuation-mark
[Docs] remove semi-colon punctuation mark
2020-09-16 12:42:20 -03:00
Faris A Chugthai
9ceb4e6efc Mistyped was mistyped (#7762) 2020-09-16 12:18:03 +02:00
Sorin Sbarnea
da21fc5883 Improve output for missing required plugins/unknown config keys (#7723)
Co-authored-by: Florian Bruhin <me@the-compiler.org>
2020-09-16 12:13:17 +02:00
Vipul Kumar
7470270f20 [Docs] remove semi-colon punctuation mark
Usually, we use semi-colon punctuation mark to connect closely related
ideas. Sentences which are after semicolon, begins with small letter,
and last sentence always ends with a period mark, see "Garner's Modern
American Usage" book for more information about usage of punctuation
mark. So removing punctuation mark altogether is a good idea, as
@gnikonorov suggested [1].

[1]: https://github.com/pytest-dev/pytest/pull/7760#pullrequestreview-489232607
2020-09-16 06:17:17 +00:00
Faris A Chugthai
cdf2024070 Update writing_plugins.rst (#7757)
Capitalize the first word in a sentence and add a period at the end.
2020-09-15 16:41:27 +02:00
Bruno Oliveira
f42c0cd1ec Merge pull request #7747 from nicoddemus/cmdline-flags-docs
Add full command-line flags to the reference docs
2020-09-14 13:47:43 -03:00
Bruno Oliveira
4b46db8ae5 Add full command-line flags to the reference docs
Fix #7728
2020-09-14 13:42:06 -03:00
Anthony Sottile
7f7e383daf Merge pull request #7753 from pytest-dev/asottile-patch-1
Update to deadsnakes/action@v2.0.0
2020-09-14 08:55:25 -07:00
Anthony Sottile
a5fd2895b6 Update to deadsnakes/action@v2.0.0
should be a noop (despite the major version bump) -- I rewrote the action to be more stable and need fewer security updates
2020-09-13 12:55:56 -07:00
Anthony Sottile
bc0020ad96 Merge pull request #7750 from pytest-dev/graingert-patch-1
permit tox config in non-tox.ini files for pytest-dev member projects
2020-09-13 09:37:35 -07:00
Anthony Sottile
e04bc05e7e Merge pull request #7751 from pytest-dev/graingert-patch-2
remove unused bitbucket link
2020-09-12 20:16:38 -07:00
Thomas Grainger
51752108b8 remove unused bitbucket link 2020-09-13 03:02:10 +01:00
Thomas Grainger
24c26a046e permit tox config in non-tox.ini files for pytest-dev member projects 2020-09-13 00:41:00 +01:00
Ran Benita
d18cb961cf assertion/rewrite: fix internal error on collection error due to decorated function
For decorated functions, the lineno of the FunctionDef AST node points
to the `def` line, not to the first decorator line. On the other hand,
in code objects, the `co_firstlineno` points to the first decorator
line.

Assertion rewriting inserts some imports to code it rewrites. The
imports are inserted at the lineno of the first statement in the AST. In
turn, the code object compiled from the rewritten AST uses the lineno of
the first statement (which is the first inserted import).

This means that given a module like this,

```py
@foo
@bar
def baz(): pass
```

the lineno of the code object without assertion rewriting
(`--assertion=plain`) is 1, but with assertion rewriting it is 3.

And *this* causes some issues for the exception repr when e.g. the
decorator line is invalid and raises during collection. The code becomes
confused and crashes with

INTERNALERROR>   File "_pytest/_code/code.py", line 638, in get_source
INTERNALERROR>     lines.append(space_prefix + source.lines[line_index].strip())
INTERNALERROR> IndexError: list index out of range

Fix it by special casing decorators. Maybe there are other cases like
this but off hand I can't think of another Python construct where the
lineno of the item would be after its first line, and this is the only
such issue we have had reported.
2020-09-12 23:05:08 +03:00
Ran Benita
35350e11cd assertion/rewrite: rewrite condition to be easier to follow 2020-09-12 22:57:50 +03:00
Bruno Oliveira
634cde9506 Merge pull request #7745 from asottile/exec_globals_type_problem
Fix INTERNALERROR when accessing locals / globals with faulty `exec`
2020-09-12 08:09:48 -03:00
Bruno Oliveira
ec58ae5bae Merge pull request #7736 from nicoddemus/extend-fixture-parametrize-1953 2020-09-12 08:08:31 -03:00
Anthony Sottile
96a17b1683 Fix INTERNALERROR when accessing locals / globals with faulty exec 2020-09-11 18:13:48 -07:00
Ran Benita
389e30283c Merge pull request #7744 from bluetech/cherry-pick-release
Merge pull request #7720 from pytest-dev/release-6.0.2
2020-09-12 02:21:41 +03:00
Ran Benita
e0dd2111a0 Merge pull request #7720 from pytest-dev/release-6.0.2
Prepare release 6.0.2

(cherry picked from commit fe69bd5baf)
2020-09-12 02:05:47 +03:00
Bruno Oliveira
e36adbaadc Use ParameterSet to extract argnames from parametrize mark 2020-09-11 16:53:34 -03:00
Bruno Oliveira
c00fe960ba Allow ovewriting a parametrized fixture while reusing the parent fixture's value
Fix #1953
2020-09-11 16:53:34 -03:00
Ran Benita
78ed3e48db Merge pull request #7729 from bluetech/doc-fix-crossrefs
doc: fix a few broken cross references
2020-09-11 12:44:29 +03:00
Bruno Oliveira
9c0e0c756a Merge pull request #7734 from pytest-dev/asottile-patch-1
Update pytest-dev requirements
2020-09-09 10:37:03 -03:00
Joseph Lucas
6ae0f741ef Add example for __test__ (#7733)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-09-09 10:33:39 -03:00
Anthony Sottile
7da6ebede0 Update pytest-dev requirements
- be more vague about "packaging metadata" over explicitly mentioning `setup.py`
  (such that `pyproject.toml`-based distributions are allowed)
- drop extensions on `README.txt` / `LICENSE.txt` (it's more common to have `.md`
  / `.rst` / no extension)
- remove duplicate mention of license packaging metadata
2020-09-08 09:52:59 -07:00
Ran Benita
e503c9a9f8 doc: fix broken cross references 2020-09-06 19:06:43 +03:00
Anthony Sottile
4df39e3a1d Merge pull request #7722 from The-Compiler/update-trainings
doc: Remove Workshoptage training
2020-09-05 18:00:34 -07:00
Florian Bruhin
5bdfd719e6 doc: Remove Workshoptage training
The sign-up is closed.
2020-09-05 18:11:23 +02:00
Sorin Sbarnea
1df2471f17 Make min duration configurable for slowest tests (#7667)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-09-05 09:18:29 -03:00
Bruno Oliveira
54f7a87ea8 Merge pull request #7714 from bluetech/doc-prefer-public
doc: prefer to reference by public name when possible
2020-09-04 20:39:03 -03:00
Bruno Oliveira
db12d79c2a Merge pull request #7713 from bluetech/doc-one-pm
doc/reference: include PluginManager in PytestPluginManager and remove it
2020-09-04 20:38:20 -03:00
Bruno Oliveira
44fc0192bc Merge pull request #7719 from nicoddemus/fix-release-script
Use tox to execute release script
2020-09-04 18:45:29 -03:00
Bruno Oliveira
5371be4cf6 Use tox to execute release script
The release-on-comment script is always executed on *master*, so we should
execute the `release.py` script using tox to ensure we create the
right environment.

Also fixed errors in the error handling code.
2020-09-04 18:35:54 -03:00
Ran Benita
0ca2327069 doc: prefer to reference by public name when possible
When a name is exported from `pytest`, prefer to refer to it by that
rather than its `_pytest` import path. It is shorter and more
appropriate in user-facing documentation (although that's not really
visible).

Our plan is to expose more names for typing purposes, in which can this
could be more comprehensive.
2020-09-04 20:46:15 +03:00
Ran Benita
48a8c373a0 doc/reference: include PluginManager in PytestPluginManager and remove it
Before, `PluginManager` was a copy of the pluggy doc, and
`PytestPluginManager` was documented separately.

pytest users only really need to know about `PytestPluginManager`, so
instead of splitting have the `PytestPluginManager` documentation
include all of `PluginManager` members and remove `PluginManager` from
the reference (it is still shown as the base class).
2020-09-04 20:14:39 +03:00
Ran Benita
885d969484 Merge pull request #7685 from bluetech/py-to-pathlib-2
config: start migrating Config.{rootdir,inifile} from py.path.local to pathlib
2020-09-04 18:42:52 +03:00
Bruno Oliveira
0d0b798663 Merge pull request #7708 from nicoddemus/repr-line-7707
Fix handle of exceptions in ReprEntry with tb=line
2020-09-04 12:06:11 -03:00
Ran Benita
62e249a1f9 Replace some usages of config.{rootdir,inifile} with config.{rootpath,inipath} 2020-09-04 18:05:42 +03:00
Ran Benita
a346028006 config: add Config.{rootpath,inipath}, turn Config.{rootdir,inifile} to properties 2020-09-04 18:04:25 +03:00
Ran Benita
3085c99e47 config: small doc improvements 2020-09-04 18:04:25 +03:00
Bruno Oliveira
19e99ab413 Integrate warnings filtering directly into Config (#7700)
Warnings are a central part of Python, so much that Python itself has
command-line and environtment variables to handle warnings.

By moving the concept of warning handling into Config, it becomes natural to
filter warnings issued as early as possible, even before the "_pytest.warnings"
plugin is given a chance to spring into action. This also avoids the weird
coupling between config and the warnings plugin that was required before.

Fix #6681
Fix #2891
Fix #7620
Fix #7626
Close #7649

Co-authored-by: Ran Benita <ran@unusedvar.com>
2020-09-04 11:57:15 -03:00
Bruno Oliveira
9f672c85c5 Fix handle of exceptions in ReprEntry with tb=line
Fix #7707
2020-09-03 07:44:45 -03:00
Anthony Sottile
91dbdb6093 Merge pull request #7698 from bluetech/rm-scopedproperty
fixture: remove `@scopeproperty`
2020-08-28 17:26:10 -07:00
Bruno Oliveira
877c62166a Merge pull request #7699 from bluetech/optimize-makeitem
python: small optimization in PyCollector.collect()
2020-08-28 09:53:00 -03:00
Bruno Oliveira
21aa6c42b7 Merge pull request #7697 from nicoddemus/file-docs 2020-08-28 09:52:02 -03:00
Bruno Oliveira
ceea6000ba Add missing File reference to the docs
As related in #7696
2020-08-28 08:49:22 -03:00
Ran Benita
12de92cd2b fixture: remove @scopeproperty
I think the straight code is easier to understand.
2020-08-28 10:02:02 +03:00
Ran Benita
daca174c98 python: small optimization in PyCollector.collect()
Inline `_makeitem()` so that `self.ihook` (which is moderately
expensive) can be called only once.

Note: the removed test "test_makeitem_non_underscore" comes from an old
behavior of skipping names that start with `_` which has since been
generalized, making the test no longer relevant.
2020-08-27 10:18:37 +03:00
Ran Benita
2fcf763d7e Merge pull request #7671 from bluetech/ignored-names
RFC: python: skip work pytest_pycollect_makeitem work on certain names
2020-08-27 10:03:09 +03:00
Ran Benita
98891a5947 python: skip pytest_pycollect_makeitem work on certain names
When a Python object (module/class/instance) is collected, for each name
in `obj.__dict__` (and up its MRO) the pytest_pycollect_makeitem hook is
called for potentially creating a node for it.

These Python objects have a bunch of builtin attributes that are
extremely unlikely to be collected. But due to their pervasiveness,
dispatching the hook for them ends up being mildly expensive and also
pollutes PYTEST_DEBUG=1 output and such.

Let's just ignore these attributes.

On the pandas test suite commit 04e9e0afd476b1b8bed930e47bf60e,
collect only, irrelevant lines snipped, about 5% improvement:

Before:

```
         51195095 function calls (48844352 primitive calls) in 39.089 seconds

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
226602/54    0.145    0.000   38.940    0.721 manager.py:90(_hookexec)
    72227    0.285    0.000   20.146    0.000 python.py:424(_makeitem)
    72227    0.171    0.000   16.678    0.000 python.py:218(pytest_pycollect_makeitem)
```

After:

```
          48410921 function calls (46240870 primitive calls) in 36.950 seconds

    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 181429/54    0.113    0.000   36.777    0.681 manager.py:90(_hookexec)
     27054    0.130    0.000   17.755    0.001 python.py:465(_makeitem)
     27054    0.121    0.000   16.219    0.001 python.py:218(pytest_pycollect_makeitem)
```
2020-08-26 17:43:57 +03:00
Bruno Oliveira
8730a7bb14 Merge pull request #7687 from bluetech/idval-notset
python: fix empty parametrize() leading to "NotSetType.token" id
2020-08-25 19:48:26 -03:00
Ran Benita
a267a622eb python: fix empty parametrize() leading to "NotSetType.token" id
In ff8b7884e8 NOTSET was changed to a
singleton enum, which ended up unexpectedly triggering a code path in ID
generation which checks for `isinstance(Enum)`.

Add an explicit case for it, which is not too bad anyway.
2020-08-25 22:01:43 +03:00
Florian Bruhin
00996adeb8 Update talks/trainings page (#7661)
* Update talks/trainings page

- Remove past webinar
- Add new open training
- Add some talks/webinars by Oliver Bestwalter and by me
- Remove some stale link targets

* Move sidebar to index
2020-08-25 17:02:33 +02:00
Ran Benita
ff41e7ad5d Merge pull request #7670 from bluetech/session-inline
Start simplifying collection code in Session
2020-08-25 10:28:07 +03:00
Ran Benita
c1f975668e main: couple of code simplifications 2020-08-24 18:15:11 +03:00
Ran Benita
023f0510af main: move collection cache attributes to local variables in collect()
They are only used for the duration of this function.
2020-08-24 18:15:11 +03:00
Ran Benita
c867452488 main: inline matchnodes() into collect()
Now all of the logic is in one place and may be simplified and
refactored in more sensible way.
2020-08-24 18:15:11 +03:00
Ran Benita
d0e8b71404 main: inline _collect() into collect()
This removes an unhelpful level of indirection and enables some upcoming
upcoming simplifications.
2020-08-24 18:15:11 +03:00
Ran Benita
eec13ba57e main: get rid of NoMatch
Things are easier to understand without the weird exception.
2020-08-24 18:15:11 +03:00
Ran Benita
c4fd461617 main: better name for _collection_node_cache3
The weird name was due to f3967333a1, now
that I understand it a bit better can give it a more descriptive name.
2020-08-24 18:15:11 +03:00
Ran Benita
c2256189ae main: make matchnodes non-recursive
It's a little more sane this way.
2020-08-24 18:15:11 +03:00
Ran Benita
841521fedb main: only perform one recursive matchnodes call per node 2020-08-24 18:15:11 +03:00
Ran Benita
0c6b2f39b2 main: move NoMatch raising to _collect()
This is a more sensible interface for matchnodes.

This also fixes a sort-of bug where a recursive call to matchnodes
raises NoMatch which would terminate the entire tree, even if other
branches may find a match. Though I don't think it's actually possible.
2020-08-24 18:15:11 +03:00
Ran Benita
a2c919d350 main: refactor a bit to reduce indentation 2020-08-24 18:15:11 +03:00
Ran Benita
adaec2da90 main: remove impossible condition in matchnodes
Already covered in a condition above.
2020-08-24 18:15:11 +03:00
Ran Benita
1b2de81404 main: remove unneeded condition in matchnodes
The end result in the `else` branch is the same, but flows naturally.
2020-08-24 18:15:11 +03:00
Ran Benita
5356a0979a main: small code simplification in matchnodes 2020-08-24 18:15:11 +03:00
Ran Benita
0b41b79dcb main: better solution to a type ignore 2020-08-24 18:15:11 +03:00
Ran Benita
57aca11d4a hookspec: type annotate parent argument to pytest_collect_file 2020-08-24 18:15:11 +03:00
Ran Benita
4b8e1a1771 Revert "Move common code between Session and Package to FSCollector"
This reverts commit f10ab021e2.

The commit was good in that it removed a non-trivial amount of code
duplication. However it was done in the wrong layer (nodes.py) and split
up a major part of the collection (the filesystem traversal) to a
separate class making it harder to understand.

We should try to reduce the duplication, but in a more appropriate
manner.
2020-08-24 18:15:11 +03:00
Ran Benita
32edc4655c main: inline Session._matchnodes() into Session.matchnodes()
Similar to the previous commit, this makes things more straightforward.
2020-08-24 18:15:11 +03:00
Ran Benita
d121d7c917 main: inline Session._perform_collect() into perform_collect()
It doesn't add much, mostly just an eye sore, particularly with the
overloads.
2020-08-24 18:15:10 +03:00
Ran Benita
1dad5c6433 Merge pull request #7669 from bluetech/collection-doc
hookspec: improve collection phase documentation a bit
2020-08-24 14:57:37 +03:00
Ran Benita
172b6e15c5 hookspec: improve collection phase documentation a bit
Make it a bit more accurate and use the same format that
pytest_runtest_protocol uses.
2020-08-24 13:00:09 +03:00
Ran Benita
bb38ae9c52 Merge pull request #7651 from bluetech/capture-safe-disable
capture: fix disabled()/global_and_fixture_disabled() enabling capturing when it was disabled
2020-08-24 12:11:09 +03:00
Bruno Oliveira
6cf89338d3 Merge pull request #7677 from bluetech/flaky-no-tests-ran
testing: fix flaky test when executed slowly
2020-08-23 09:25:26 -03:00
Ran Benita
b47b488e3d testing: fix flaky test when executed slowly
The 0-1 was a bit too optimistic: CI got "no tests ran in 3.98s".
2020-08-23 12:32:30 +03:00
Ran Benita
143e3ab846 Merge pull request #7673 from bluetech/logging-fix-handler-restore
logging: fix handler level restored incorrectly if caplog.set_level is called more than once
2020-08-23 12:06:09 +03:00
Ran Benita
837687c21a Merge pull request #7668 from bluetech/dir-match-msg
main: improve message on `pytest path/to/a/directory::mytest`
2020-08-23 12:05:22 +03:00
Ran Benita
b1354608cc logging: fix handler level restored incorrectly if caplog.set_level is called more than once 2020-08-22 17:46:23 +03:00
Maximilian Cosmo Sitter
75af2bfa06 Reintroduce warnings postponed in 6.0 (#7637) 2020-08-22 11:17:50 -03:00
Ran Benita
5e39cd5e71 main: improve message on pytest path/to/a/directory::mytest
The path part of a `<path>::part1::part2` style collection argument must
be a file, not a directory.

Previously this crashed with an uncool assert "invalid arg".
2020-08-22 11:52:54 +03:00
Bruno Oliveira
d69abff2c7 Merge pull request #7660 from nicoddemus/deprecated-features 2020-08-19 09:04:10 -03:00
Bruno Oliveira
372a094005 PytestDeprecationWarning no longer a hard error 2020-08-19 08:14:28 -03:00
Bruno Oliveira
7605150eaa Move --no-print-logs removal notice to 'Removed Features' 2020-08-19 08:14:28 -03:00
Bruno Oliveira
ef946d557c Remove resultlog plugin 2020-08-19 08:14:28 -03:00
Bruno Oliveira
b32c48ee05 Add bottom changelog deprecation notice 2020-08-19 08:14:28 -03:00
Bruno Oliveira
52b0cc4f19 Remove broken pytest_collect_directory hook 2020-08-19 08:14:25 -03:00
Bruno Oliveira
457d351941 Remove deprecated TerminalReporter.writer property 2020-08-19 08:13:34 -03:00
Bruno Oliveira
345a59dd53 Add note about pytest.collect deprecation 2020-08-19 08:13:06 -03:00
Bruno Oliveira
6ecbd008c4 Change junit_family default to xunit2 2020-08-19 08:13:06 -03:00
Bruno Oliveira
73e06373dc Hard failure when constructing Node subclasses 2020-08-19 08:13:03 -03:00
Bruno Oliveira
c747dc5248 Drop support for positional arguments in @pytest.fixture 2020-08-19 08:11:42 -03:00
Bruno Oliveira
98530184a5 Remove funcargnames compatibility property 2020-08-19 08:11:39 -03:00
Ran Benita
c98525bd21 Merge pull request #7648 from bluetech/pylint-abc2
Only define gethookproxy, isinitpath on Session
2020-08-18 15:45:11 +03:00
Bruno Oliveira
afa4760cb8 Merge pull request #7643 from nicoddemus/issue-7628 2020-08-17 16:58:56 -03:00
Ran Benita
0d5a65091d capture: fix disabled()/global_and_fixture_disabled() enabling capturing when it was disabled
The `CaptureManager.global_and_fixture_disabled()` context manager (and
`CaptureFixture.disabled()` which calls it) did `suspend(); ...;
resume()` but if the capturing was already suspended, the `resume()`
would resume it when it shouldn't.

This caused caused some messages to be swallowed when `--log-cli` is
used because it uses `global_and_fixture_disabled` when capturing is not
necessarily resumed.
2020-08-16 23:21:45 +03:00
Bruno Oliveira
b426bb3443 Refactor Session._parsearg into a separate function for testing 2020-08-15 13:23:55 -03:00
Bruno Oliveira
2213016e40 Fix Module.name from full path without drive letter
Fix #7628
2020-08-15 09:39:14 -03:00
Bruno Oliveira
3f0abcc6a5 Merge pull request #7639 from nicoddemus/issue-7638 2020-08-15 09:17:37 -03:00
Ran Benita
eddd993cf4 Only define gethookproxy, isinitpath on Session
This fixes an issue where pylint complains about missing implementations
of abstract methods in subclasses of `File` which only override
`collect()` (as they should).

It is also cleaner and makes sense, these methods really don't need to
be overridden.

The previous methods defined directly on `FSCollector` and `Package` are
deprecated, to be removed in pytest 7.

See commits e2934c3f8c and
f10ab021e2 for reference.
2020-08-15 13:40:16 +03:00
Bruno Oliveira
f76b162263 Add ref to Python bug 2020-08-14 11:36:07 -03:00
Ran Benita
d426a79a90 Merge pull request #7645 from bluetech/pylint-abc
Don't use NotImplementedError in `@overload`s
2020-08-14 15:33:35 +03:00
Ran Benita
f28af14457 Don't use NotImplementedError in @overloads
We used it as a shortcut for avoiding coverage, but pylint has a special
interpretation of it as an abstract method which we don't want.
2020-08-14 13:54:46 +03:00
Ran Benita
2c5403b951 Merge pull request #7644 from bluetech/changelog-7631
Add changelog for PR #7631
2020-08-14 11:54:31 +03:00
Ran Benita
8056a677b4 Add changelog for PR #7631 2020-08-14 11:02:44 +03:00
Thomas Grainger
02c6e4455c document toml use of filterwarnings (#7611)
and include a demo of toml 'literal strings'

Update doc/en/warnings.rst
Apply suggestion by Ran
Fix linting

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-08-14 10:08:17 +03:00
Bruno Oliveira
10f98e1d2f Merge pull request #7641 from hynek/patch-1
Replace inactive Azure Pipelines badge with GHA
2020-08-13 11:49:45 -03:00
Hynek Schlawack
82181fde3e Replace inactive Azure Pipelines badge with GHA
Currently the badge encourages you to set it up now. :)
2020-08-13 14:18:36 +02:00
Bruno Oliveira
36c8bb492e get_dirs_from_args handles paths with invalid syntax
Fix #7638
2020-08-12 17:20:09 -03:00
Maximilian Cosmo Sitter
15d8293241 Remove faq.rst from docs (#7635) 2020-08-12 14:47:34 -03:00
Ran Benita
4c92584364 Merge pull request #7631 from bluetech/capture-1
capture: add type annotations to CaptureFixture
2020-08-10 18:38:05 +03:00
Ran Benita
acc9310c17 capture: add type annotations to CaptureFixture
It now has a str/bytes type parameter.
2020-08-10 18:14:47 +03:00
Ran Benita
8a66f0a96d capture: overcome a mypy limitation by making CaptureResult a regular class
See the code comment for the rationale.
2020-08-10 18:14:47 +03:00
Bruno Oliveira
bee72e1925 Merge pull request #7629 from samestep/patch-1
Fix typos in Ali Afshar's name
2020-08-07 20:02:26 -03:00
Sam Estep
a27c539a85 Fix typos in Ali Afshar's name
The correct name is visible in the Bitbucket link.
2020-08-07 15:22:10 -07:00
Ran Benita
384b6f6866 Merge pull request #7619 from bluetech/py-to-pathlib
Some py.path -> pathlib conversions
2020-08-07 11:33:21 +03:00
Ran Benita
f8c4e038fd Replace some usages of py.path.local 2020-08-06 18:46:17 +03:00
Ran Benita
70f3ad1c1f config/findpaths: convert from py.path.local to pathlib 2020-08-06 18:46:17 +03:00
Ran Benita
9e55288ba4 pathlib: add absolutepath() as alternative to Path.resolve()
Didn't call it absolute or absolute_path to avoid conflicts with
possible variable names.

Didn't call it abspath to avoid confusion with os.path.abspath.
2020-08-06 18:16:04 +03:00
Ran Benita
e0d0951945 pathlib: add analogues to py.path.local's bestrelpath and common
An equivalent for these py.path.local functions is needed for some
upcoming py.path -> pathlib conversions.
2020-08-06 18:16:04 +03:00
Ran Benita
aa9905d72e Merge pull request #7625 from nicoddemus/pypy3-async-unittest-7624
Fix test_plain_unittest_does_not_support_async on pypy3
2020-08-06 08:31:46 +03:00
Bruno Oliveira
67cb7ef673 Fix test_plain_unittest_does_not_support_async on pypy3
Fix #7624
2020-08-05 15:24:08 -03:00
Rüdiger Busche
a64298ff5e Document registering markers in pyproject.toml (#7622)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-08-05 12:03:27 -03:00
Bruno Oliveira
44cd8a3a86 Demonstrate that plain unittest does not support async tests (#7607)
Co-authored-by: Ran Benita <ran@unusedvar.com>
2020-08-04 19:37:41 -03:00
Ran Benita
2bd0d97fcc Merge pull request #7601 from bluetech/typing-longrepr
typing: resultlog, pytester, longrepr
2020-08-04 23:23:56 +03:00
Ran Benita
fbf251f11d Improve typing of reports' longrepr field 2020-08-04 22:52:24 +03:00
Ran Benita
f0eb82f7d4 pytester: improve type annotations 2020-08-04 22:46:30 +03:00
Ran Benita
62ddf7a0e5 resultlog: add missing type annotations 2020-08-04 22:45:46 +03:00
Ran Benita
303030c141 Merge pull request #7613 from bluetech/typing-warn-unreachable
typing: set warn_unreachable
2020-08-04 22:44:21 +03:00
Bruno Oliveira
0d65e4b454 Merge pull request #7606 from nicoddemus/pre-release-docs
Add docs for releasing major/release candidates
2020-08-04 15:37:19 -03:00
Yutaro Ikeda
84c4b64354 Better document -k partial matching (#7610) 2020-08-04 15:30:08 -03:00
Bruno Oliveira
d688fefecb Merge pull request #7614 from The-Compiler/log-print
Properly remove log_print
2020-08-04 13:39:21 -03:00
Ran Benita
9ab14c6d9c typing: set warn_unreachable
This makes mypy raise an error whenever it detects code which is
statically unreachable, e.g.

    x: int
    if isinstance(x, str):
        ... # Statement is unreachable  [unreachable]

This is really neat and finds quite a few logic and typing bugs.

Sometimes the code is intentionally unreachable in terms of types, e.g.
raising TypeError when a function is given an argument with a wrong
type. In these cases a `type: ignore[unreachable]` is needed, but I
think it's a nice code hint.
2020-08-04 09:59:46 +03:00
Florian Bruhin
1c9b84756f Properly remove log_print
This is a follow up to 3f8200676f which didn't
make it clear that log_print is also removed in the changelog and didn't remove
it from the reference docs.
2020-08-04 08:53:09 +02:00
Ran Benita
0dd5e169d0 Merge pull request #7603 from bluetech/flake8-docstrings
Enforce some pydocstyle lints with flake8-docstrings & docstring fixes in testing/
2020-08-04 08:15:55 +03:00
Ran Benita
9a18b57c7c Enforce some pydocstyle lints with flake8-docstrings
There are some ones we *would* like to enforce, like
    D401 First line should be in imperative mood
but have too many false positives, so I left them out.
2020-08-03 10:21:59 +03:00
Ran Benita
b8471aa527 testing: fix some docstring issues
In preparation for enforcing some docstring lints.
2020-08-03 10:10:43 +03:00
Anthony Sottile
701998bf2c Merge pull request #7598 from nicoddemus/setuptools-scm-pyproject
Configure setuptools_scm using pyproject.toml
2020-08-01 19:17:33 -07:00
Ran Benita
be354b36f3 Merge pull request #7604 from bluetech/typing-disallow-any-generics
typing: set disallow_any_generics
2020-08-01 20:55:45 +03:00
Ran Benita
be656dd4e4 typing: set disallow_any_generics
This prevents referring to a generic type without filling in its generic
type parameters.

The FixtureDef typing might need some more refining in the future.
2020-08-01 20:39:15 +03:00
Bruno Oliveira
d1fa749b83 Add readthedocs config file to use pip for installation 2020-08-01 14:21:36 -03:00
Bruno Oliveira
d7ad55bb2a Add docs for releasing major/release candidates
Fix #7447
2020-08-01 13:51:12 -03:00
Ran Benita
1e9c638468 Merge pull request #7602 from ctb/patch-1
Minor formatting fix in xunit_setup.rst
2020-08-01 18:08:03 +03:00
C. Titus Brown
a2d562d369 Minor formatting fix in xunit_setup.rst
Fixed location of double-backquote for verbatim text.
2020-08-01 07:33:03 -07:00
Ran Benita
49827adcb9 Merge pull request #7510 from bluetech/docstrings
Format docstrings in a consistent style
2020-08-01 17:32:01 +03:00
Ran Benita
cbec0f8c6a CONTRIBUTING: document the docstring style we use 2020-08-01 17:14:38 +03:00
Ran Benita
0242de4f56 Format docstrings in a consistent style 2020-08-01 17:14:37 +03:00
Bruno Oliveira
6882c0368b Merge pull request #7593 from bluetech/typing-no-implicit-reexport
typing: set no_implicit_reexport
2020-08-01 11:03:47 -03:00
Bruno Oliveira
07f7372aff Merge pull request #7586 from nicoddemus/cp-release
Merge pull request #7584 from pytest-dev/release-6.0.1
2020-08-01 11:00:38 -03:00
Anthony Sottile
d5a49100cf Try this maybe? 2020-07-31 21:44:44 -07:00
Bruno Oliveira
4f0793a462 Require setuptools >=42 2020-07-31 18:17:12 -03:00
Bruno Oliveira
09265eb7c7 Configure setuptools_scm using pyproject.toml 2020-07-31 15:46:02 -03:00
Ran Benita
a1ba8dfe2a Merge pull request #7587 from bluetech/rm-more-itertools
Stop using more-itertools
2020-07-31 13:08:34 +03:00
Ran Benita
8d98de8f8a typing: set no_implicit_reexport
In Python, if module A defines a name `name`, and module B does `import
name from A`, then another module C can `import name from B`.

Sometimes it is intentional -- module B is meant to "reexport" `name`.
But sometimes it is just confusion/inconsistency on where `name` should
be imported from.

mypy has a flag `--no-implicit-reexport` which puts some order into
this. A name can only be imported from a module if

1. The module defines the name
2. The module's `__all__` includes the name
3. The module imports the name as `from ... import .. as name`.

This flag is included in mypy's `--strict` flag.

I like this flag, but I realize it is a bit controversial, and in
particular item 3 above is a bit unfriendly to contributors who don't
know about it. So I didn't intend to add it to pytest.

But while investigating issue 7589 I came upon mypy issue 8754 which
causes `--no-implicit-reexport` to leak into installed libraries and
causes some unexpected typing differences *in pytest* if the user uses
this flag.

Since the diff mostly makes sense, let's just conform to it.
2020-07-31 10:09:11 +03:00
Ran Benita
96a48f0c66 Stop using more-itertools
We barely use it; the couple places that do are not really worth the
extra dependency, I think the code is clearer without it.

Also simplifies one (regular) itertools usage.

Also improves a check and an error message in `pytest.raises`.
2020-07-30 20:19:24 +03:00
Bruno Oliveira
e49f1d6f60 Merge pull request #7584 from pytest-dev/release-6.0.1
Prepare release 6.0.1

(cherry picked from commit 022bff27a7)
2020-07-30 09:46:53 -03:00
Ran Benita
645cbc91fc Merge pull request #7581 from bluetech/logging-setlevel-handler-restore
Add missing changelog for issue 7569
2020-07-30 13:41:02 +03:00
Ran Benita
924e466c98 Add missing changelog for issue 7569 2020-07-30 12:38:40 +03:00
Hugo van Kemenade
d756b4a543 Fix typo: remove stray indefinite article from release notes (#7552)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-07-29 12:19:33 -03:00
Mattreex
1e66ed0b1c Warn about --basetemp removing the entire directory (#7555)
Co-authored-by: mattreex <mattreex.9@gail.com>
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2020-07-29 11:58:18 -03:00
Bruno Oliveira
49628786f0 Merge pull request #7575 from nicoddemus/fix-changelog-entries-release-process 2020-07-29 11:56:11 -03:00
Bruno Oliveira
22acbaf393 Minor changes to the release process
As discussed in https://github.com/pytest-dev/pytest/pull/7556
2020-07-29 11:35:27 -03:00
Bruno Oliveira
e691d3ee52 Merge remote-tracking branch 'upstream/6.0.x' into fix-changelog-entries-release-process 2020-07-29 11:27:08 -03:00
Bruno Oliveira
095bf191e2 Merge pull request #7561 from nicoddemus/longreprtext-7559 2020-07-29 09:47:04 -03:00
Bruno Oliveira
cefe064bb0 Merge pull request #7571 from bluetech/logging-setlevel-handler-restore
logging: fix capture handler level not reset on teardown after caplog.set_level()
2020-07-29 09:37:57 -03:00
Bruno Oliveira
d3267bc49d Fix TestReport.longreprtext when TestReport.longrepr is not a string
Fix #7559
2020-07-29 09:31:15 -03:00
Ran Benita
0e0275d8d9 logging: fix capture handler level not reset on teardown after caplog.set_level()
This probably regressed in fcbaab8.
2020-07-29 14:59:29 +03:00
Ran Benita
422685d0bd Merge pull request #7567 from bluetech/pylint-callable-2-space
mark: fix extraneous spaces in dummy type-checking marks
2020-07-29 12:40:21 +03:00
Ran Benita
b473e515bc Merge pull request #7541 from bluetech/py-visit
pathlib: stop using py.path.local.visit(), use os.scandir
2020-07-29 12:04:06 +03:00
Ran Benita
20a3a28815 Merge pull request #7536 from bluetech/junitxml-etree
junitxml: convert from py.xml to xml.etree.ElementTree
2020-07-29 12:01:33 +03:00
Ran Benita
54e08b7230 mark: fix extraneous spaces in dummy type-checking marks 2020-07-29 11:58:54 +03:00
Ran Benita
f9837f953c Merge pull request #7565 from bluetech/pylint-callable-2
mark: fix pylint not-callable error on pytest.mark.parametrize(...), again
2020-07-29 11:49:41 +03:00
Ran Benita
c755840793 pre-commit: extend list of rejected py modules
We now only use `py.path.local`.
2020-07-29 10:52:21 +03:00
Ran Benita
f86e4516eb junitxml: convert from py.xml to xml.etree.ElementTree
Part of the effort to reduce dependency on the py library.

Besides that, py.xml implements its own XML serialization which is
pretty scary.

I tried to keep the code with minimal changes (though it could use some
cleanups). The differences in behavior I have noticed are:

- Attributes in the output are not sorted.

- Some unneeded escaping is no longer performed, for example escaping
  `"` to `&quot;` in a text node.
2020-07-29 10:52:21 +03:00
Ran Benita
1653c49b1b junitxml: simplify bin_xml_escape
1. Remove sys.maxunicode check & comment. Nowadays it is always a
   constant 0x10ffff.
2. Pre-generate the pattern. Possible due to 1.
3. Compile the regex lazily. No reason to pay startup cost for it.
4. Add docstring in particular to explain a subtle point.
2020-07-29 10:52:21 +03:00
Ran Benita
6ea6f0dac8 junitxml: compile a regex lazily
Instead of slowing down startup, and making the code harder to follow,
compile it lazily (it is still cached internally).
2020-07-29 10:52:21 +03:00
hp310780
27a4c6cd6d Fix --help crash on add_ini(.., help='') and improve message on help=None (#7427) 2020-07-29 10:48:38 +03:00
Ran Benita
b36bcd13e9 mark: fix pylint not-callable error on pytest.mark.parametrize(...), again
Apparently the previous fix c1ca42b5c2 didn't work.
Hopefully this time I'm testing this correctly.
2020-07-29 10:39:13 +03:00
Drew Devereux
88cc636c18 Update markers.rst (#7563)
Extra colon to make code block render correctly
2020-07-29 09:10:13 +02:00
Bruno Oliveira
c7216ae0f6 Merge pull request #7557 from nicoddemus/announce-templates 2020-07-28 21:20:26 -03:00
Bruno Oliveira
df09a31646 Merge pull request #7556 from nicoddemus/cherry-pick-release
Merge pull request #7550 from pytest-dev/release-6.0.0
2020-07-28 21:04:26 -03:00
Bruno Oliveira
109b6cb32c Update text and links in announce templates
The links were still pointing to the latest version (instead of stable)
and also took the opportunity to update the text a bit.
2020-07-28 17:29:09 -03:00
Bruno Oliveira
70764bef4f Merge pull request #7550 from pytest-dev/release-6.0.0 2020-07-28 17:01:27 -03:00
Ran Benita
3633b691d8 pathlib: make visit() independent of py.path.local, use os.scandir
`os.scandir()`, introduced in Python 3.5, is much faster than
`os.listdir()`. See https://www.python.org/dev/peps/pep-0471/.

It also has a `DirEntry` which can be used to further reduce syscalls in
some cases.
2020-07-25 00:47:29 +03:00
Ran Benita
c15bb5d3de pathlib: replace py.path.local.visit() with our own function
Part of reducing dependency on `py`. Also enables upcoming improvements.

In cases where there are simpler alternatives (in tests), I used those.

What's left are a couple of uses in `_pytest.main` and `_pytest.python`
and they only have modest requirements, so all of the featureful code
from py is not needed.
2020-07-25 00:26:49 +03:00
210 changed files with 5722 additions and 4552 deletions

View File

@@ -27,3 +27,4 @@ exclude_lines =
^\s*assert False(,|$)
^\s*if TYPE_CHECKING:
^\s*@overload( |$)

View File

@@ -1,10 +1,16 @@
---
name: 🐛 Bug Report
about: Report errors and problems
---
<!--
Thanks for submitting an issue!
Here's a quick checklist for what to provide:
Quick check-list while reporting bugs:
-->
- [ ] a detailed description of the bug or suggestion
- [ ] a detailed description of the bug or problem you are having
- [ ] output of `pip list` from the virtual environment you are using
- [ ] pytest and operating system versions
- [ ] minimal example if possible

View File

@@ -0,0 +1,5 @@
---
name: 🚀 Feature Request
about: Ideas for new features and improvements
---

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: ❓ Support Question
url: https://github.com/pytest-dev/pytest/discussions
about: Use GitHub's new Discussions feature for questions

View File

@@ -41,6 +41,7 @@ jobs:
"docs",
"doctesting",
"plugins",
]
include:
@@ -111,6 +112,11 @@ jobs:
tox_env: "py38-xdist"
use_coverage: true
- name: "plugins"
python: "3.7"
os: ubuntu-latest
tox_env: "plugins"
- name: "docs"
python: "3.7"
os: ubuntu-latest
@@ -131,7 +137,7 @@ jobs:
with:
python-version: ${{ matrix.python }}
- name: Set up Python ${{ matrix.python }} (deadsnakes)
uses: deadsnakes/action@v1.0.0
uses: deadsnakes/action@v2.0.0
if: matrix.python == '3.9-dev'
with:
python-version: ${{ matrix.python }}

View File

@@ -25,7 +25,9 @@ repos:
hooks:
- id: flake8
language_version: python3
additional_dependencies: [flake8-typing-imports==1.9.0]
additional_dependencies:
- flake8-typing-imports==1.9.0
- flake8-docstrings==1.5.0
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.3.0
hooks:
@@ -70,9 +72,11 @@ repos:
_code\.|
builtin\.|
code\.|
io\.(BytesIO|saferepr|TerminalWriter)|
io\.|
path\.local\.sysfind|
process\.|
std\.
std\.|
error\.|
xml\.
)
types: [python]

12
.readthedocs.yml Normal file
View File

@@ -0,0 +1,12 @@
version: 2
python:
version: 3.7
install:
- requirements: doc/en/requirements.txt
- method: pip
path: .
formats:
- epub
- pdf

View File

@@ -151,6 +151,7 @@ Joshua Bronson
Jurko Gospodnetić
Justyna Janczyszyn
Kale Kundert
Kamran Ahmad
Karl O. Pinc
Katarzyna Jachim
Katarzyna Król

View File

@@ -89,6 +89,38 @@ without using a local copy. This can be convenient for small fixes.
The built documentation should be available in ``doc/en/_build/html``,
where 'en' refers to the documentation language.
Pytest has an API reference which in large part is
`generated automatically <https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html>`_
from the docstrings of the documented items. Pytest uses the
`Sphinx docstring format <https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html>`_.
For example:
.. code-block:: python
def my_function(arg: ArgType) -> Foo:
"""Do important stuff.
More detailed info here, in separate paragraphs from the subject line.
Use proper sentences -- start sentences with capital letters and end
with periods.
Can include annotated documentation:
:param short_arg: An argument which determines stuff.
:param long_arg:
A long explanation which spans multiple lines, overflows
like this.
:returns: The result.
:raises ValueError:
Detailed information when this can happen.
.. versionadded:: 6.0
Including types into the annotations above is not necessary when
type-hinting is being used (as in this example).
"""
.. _submitplugin:
Submitting Plugins to pytest-dev
@@ -99,8 +131,6 @@ in repositories living under the ``pytest-dev`` organisations:
- `pytest-dev on GitHub <https://github.com/pytest-dev>`_
- `pytest-dev on Bitbucket <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.
@@ -116,16 +146,17 @@ You can submit your plugin by subscribing to the `pytest-dev mail list
mail pointing to your existing pytest plugin repository which must have
the following:
- PyPI presence with a ``setup.py`` that contains a license, ``pytest-``
- PyPI presence with packaging metadata that contains a ``pytest-``
prefixed name, version number, authors, short and long description.
- a ``tox.ini`` for running tests using `tox <https://tox.readthedocs.io>`_.
- a `tox configuration <https://tox.readthedocs.io/en/latest/config.html#configuration-discovery>`_
for running tests using `tox <https://tox.readthedocs.io>`_.
- a ``README.txt`` describing how to use the plugin and on which
- a ``README`` 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``.
- a ``LICENSE`` file containing the licensing information, with
matching info in its packaging metadata.
- an issue tracker for bug reports and enhancement requests.
@@ -375,6 +406,27 @@ actual latest release). The procedure for this is:
* Delete the PR body, it usually contains a duplicate commit message.
Who does the backporting
~~~~~~~~~~~~~~~~~~~~~~~~
As mentioned above, bugs should first be fixed on ``master`` (except in rare occasions
that a bug only happens in a previous release). So who should do the backport procedure described
above?
1. If the bug was fixed by a core developer, it is the main responsibility of that core developer
to do the backport.
2. However, often the merge is done by another maintainer, in which case it is nice of them to
do the backport procedure if they have the time.
3. For bugs submitted by non-maintainers, it is expected that a core developer will to do
the backport, normally the one that merged the PR on ``master``.
4. If a non-maintainers notices a bug which is fixed on ``master`` but has not been backported
(due to maintainers forgetting to apply the *needs backport* label, or just plain missing it),
they are also welcome to open a PR with the backport. The procedure is simple and really
helps with the maintenance of the project.
All the above are not rules, but merely some guidelines/suggestions on what we should expect
about backports.
Handling stale issues/PRs
-------------------------

View File

@@ -22,8 +22,8 @@
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
:target: https://travis-ci.org/pytest-dev/pytest
.. image:: https://dev.azure.com/pytest-dev/pytest/_apis/build/status/pytest-CI?branchName=master
:target: https://dev.azure.com/pytest-dev/pytest
.. image:: https://github.com/pytest-dev/pytest/workflows/main/badge.svg
:target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Amain
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
@@ -77,21 +77,21 @@ Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` stat
Features
--------
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/assert.html>`_ (no need to remember ``self.assert*`` names);
- Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/assert.html>`_ (no need to remember ``self.assert*`` names)
- `Auto-discovery
<https://docs.pytest.org/en/stable/goodpractices.html#python-test-discovery>`_
of test modules and functions;
of test modules and functions
- `Modular fixtures <https://docs.pytest.org/en/stable/fixture.html>`_ for
managing small or parametrized long-lived test resources;
managing small or parametrized long-lived test resources
- Can run `unittest <https://docs.pytest.org/en/stable/unittest.html>`_ (or trial),
`nose <https://docs.pytest.org/en/stable/nose.html>`_ test suites out of the box;
`nose <https://docs.pytest.org/en/stable/nose.html>`_ test suites out of the box
- Python 3.5+ and PyPy3;
- Python 3.5+ and PyPy3
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
- Rich plugin architecture, with over 850+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
Documentation

View File

@@ -5,37 +5,85 @@ Our current policy for releasing is to aim for a bug-fix release every few weeks
is to get fixes and new features out instead of trying to cram a ton of features into a release and by consequence
taking a lot of time to make a new one.
The git commands assume the following remotes are setup:
* ``origin``: your own fork of the repository.
* ``upstream``: the ``pytest-dev/pytest`` official repository.
Preparing: Automatic Method
~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have developed an automated workflow for releases, that uses GitHub workflows and is triggered
by opening an issue or issuing a comment one.
by opening an issue.
The comment must be in the form::
Bug-fix releases
^^^^^^^^^^^^^^^^
@pytestbot please prepare release from BRANCH
A bug-fix release is always done from a maintenance branch, so for example to release bug-fix
``5.1.2``, open a new issue and add this comment to the body::
Where ``BRANCH`` is ``master`` or one of the maintenance branches.
@pytestbot please prepare release from 5.1.x
For major releases the comment must be in the form::
Where ``5.1.x`` is the maintenance branch for the ``5.1`` series.
@pytestbot please prepare major release from master
The automated workflow will publish a PR for a branch ``release-5.1.2``
and notify it as a comment in the issue.
After that, the workflow should publish a PR and notify that it has done so as a comment
in the original issue.
Minor releases
^^^^^^^^^^^^^^
1. Create a new maintenance branch from ``master``::
git fetch --all
git branch 5.2.x upstream/master
git push upstream 5.2.x
2. Open a new issue and add this comment to the body::
@pytestbot please prepare release from 5.2.x
The automated workflow will publish a PR for a branch ``release-5.2.0`` and
notify it as a comment in the issue.
Major and release candidates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Create a new maintenance branch from ``master``::
git fetch --all
git branch 6.0.x upstream/master
git push upstream 6.0.x
2. For a **major release**, open a new issue and add this comment in the body::
@pytestbot please prepare major release from 6.0.x
For a **release candidate**, the comment must be (TODO: `#7551 <https://github.com/pytest-dev/pytest/issues/7551>`__)::
@pytestbot please prepare release candidate from 6.0.x
The automated workflow will publish a PR for a branch ``release-6.0.0`` and
notify it as a comment in the issue.
At this point on, this follows the same workflow as other maintenance branches: bug-fixes are merged
into ``master`` and ported back to the maintenance branch, even for release candidates.
**A note about release candidates**
During release candidates we can merge small improvements into
the maintenance branch before releasing the final major version, however we must take care
to avoid introducing big changes at this stage.
Preparing: Manual Method
~~~~~~~~~~~~~~~~~~~~~~~~
.. important::
pytest releases must be prepared on **Linux** because the docs and examples expect
to be executed on that platform.
**Important**: pytest releases must be prepared on **Linux** because the docs and examples expect
to be executed on that platform.
To release a version ``MAJOR.MINOR.PATCH``, follow these steps:
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from the
latest ``master`` and push it to the ``pytest-dev/pytest`` repo.
#. For major and minor releases, create a new branch ``MAJOR.MINOR.x`` from
``upstream/master`` and push it to ``upstream``.
#. Create a branch ``release-MAJOR.MINOR.PATCH`` from the ``MAJOR.MINOR.x`` branch.
@@ -56,9 +104,10 @@ Releasing
Both automatic and manual processes described above follow the same steps from this point onward.
#. After all tests pass and the PR has been approved, tag the release commit
in the ``MAJOR.MINOR.x`` branch and push it. This will publish to PyPI::
in the ``release-MAJOR.MINOR.PATCH`` branch and push it. This will publish to PyPI::
git tag MAJOR.MINOR.PATCH
git fetch --all
git tag MAJOR.MINOR.PATCH upstream/release-MAJOR.MINOR.PATCH
git push git@github.com:pytest-dev/pytest.git MAJOR.MINOR.PATCH
Wait for the deploy to complete, then make sure it is `available on PyPI <https://pypi.org/project/pytest>`_.
@@ -69,9 +118,9 @@ Both automatic and manual processes described above follow the same steps from t
git fetch --all --prune
git checkout origin/master -b cherry-pick-release
git cherry-pick --no-commit -m1 origin/MAJOR.MINOR.x
git checkout origin/master -- changelog
git commit # no arguments
git cherry-pick -x -m1 upstream/MAJOR.MINOR.x
#. Open a PR for ``cherry-pick-release`` and merge it once CI passes. No need to wait for approvals if there were no conflicts on the previous step.
#. Send an email announcement with the contents from::

View File

@@ -1,2 +0,0 @@
Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.

View File

@@ -1 +0,0 @@
Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.

View File

@@ -45,7 +45,7 @@ Partner projects, sign up here! (by 22 March)
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?
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:
@@ -63,7 +63,8 @@ Progressive success might look like:
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
.. _nose: nose.html
.. _unittest: unittest.html
.. _assert: assert.html
.. _pycmd: https://bitbucket.org/hpk42/pycmd/overview
.. _`setUp/tearDown methods`: xunit_setup.html

View File

@@ -6,6 +6,9 @@ Release announcements
:maxdepth: 2
release-6.1.0
release-6.0.2
release-6.0.1
release-6.0.0
release-6.0.0rc1
release-5.4.3

View File

@@ -94,7 +94,7 @@ Changes between 2.2.4 and 2.3.0
- pluginmanager.register(...) now raises ValueError if the
plugin has been already registered or the name is taken
- fix issue159: improve http://pytest.org/en/stable/faq.html
- fix issue159: improve https://docs.pytest.org/en/6.0.1/faq.html
especially with respect to the "magic" history, also mention
pytest-django, trial and unittest integration.

View File

@@ -1,7 +1,7 @@
pytest-2.5.1: fixes and new home page styling
===========================================================================
pytest is a mature Python testing tool with more than a 1000 tests
pytest is a mature Python testing tool with more than 1000 tests
against itself, passing on many different interpreters and platforms.
The 2.5.1 release maintains the "zero-reported-bugs" promise by fixing

View File

@@ -1,7 +1,7 @@
pytest-2.5.2: fixes
===========================================================================
pytest is a mature Python testing tool with more than a 1000 tests
pytest is a mature Python testing tool with more than 1000 tests
against itself, passing on many different interpreters and platforms.
The 2.5.2 release fixes a few bugs with two maybe-bugs remaining and

View File

@@ -1,7 +1,7 @@
pytest-2.6.0: shorter tracebacks, new warning system, test runner compat
===========================================================================
pytest is a mature Python testing tool with more than a 1000 tests
pytest is a mature Python testing tool with more than 1000 tests
against itself, passing on many different interpreters and platforms.
The 2.6.0 release should be drop-in backward compatible to 2.5.2 and

View File

@@ -1,7 +1,7 @@
pytest-2.6.1: fixes and new xfail feature
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
The 2.6.1 release is drop-in compatible to 2.5.2 and actually fixes some
regressions introduced with 2.6.0. It also brings a little feature

View File

@@ -1,7 +1,7 @@
pytest-2.6.2: few fixes and cx_freeze support
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is drop-in compatible to 2.5.2 and 2.6.X. It also
brings support for including pytest with cx_freeze or similar

View File

@@ -1,7 +1,7 @@
pytest-2.6.3: fixes and little improvements
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is drop-in compatible to 2.5.2 and 2.6.X.
See below for the changes and see docs at:

View File

@@ -1,7 +1,7 @@
pytest-2.7.0: fixes, features, speed improvements
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.6.X.

View File

@@ -1,7 +1,7 @@
pytest-2.7.1: bug fixes
=======================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.7.0.

View File

@@ -1,7 +1,7 @@
pytest-2.7.2: bug fixes
=======================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.7.1.

View File

@@ -1,7 +1,7 @@
pytest-2.8.2: bug fixes
=======================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.1.

View File

@@ -1,7 +1,7 @@
pytest-2.8.3: bug fixes
=======================
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.2.

View File

@@ -1,7 +1,7 @@
pytest-2.8.4
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.2.

View File

@@ -1,7 +1,7 @@
pytest-2.8.5
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.4.

View File

@@ -1,7 +1,7 @@
pytest-2.8.6
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.5.

View File

@@ -4,7 +4,7 @@ pytest-2.8.7
This is a hotfix release to solve a regression
in the builtin monkeypatch plugin that got introduced in 2.8.6.
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
This release is supposed to be drop-in compatible to 2.8.5.

View File

@@ -1,7 +1,7 @@
pytest-2.9.0
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
See below for the changes and see docs at:

View File

@@ -1,7 +1,7 @@
pytest-2.9.1
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
See below for the changes and see docs at:

View File

@@ -1,7 +1,7 @@
pytest-2.9.2
============
pytest is a mature Python testing tool with more than a 1100 tests
pytest is a mature Python testing tool with more than 1100 tests
against itself, passing on many different interpreters and platforms.
See below for the changes and see docs at:

View File

@@ -3,7 +3,7 @@ pytest-3.0.0
The pytest team is proud to announce the 3.0.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a lot of bugs fixes and improvements, and much of

View File

@@ -3,7 +3,7 @@ pytest-3.1.0
The pytest team is proud to announce the 3.1.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.10.0
The pytest team is proud to announce the 3.10.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.2.0
The pytest team is proud to announce the 3.2.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.3.0
The pytest team is proud to announce the 3.3.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.4.0
The pytest team is proud to announce the 3.4.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.5.0
The pytest team is proud to announce the 3.5.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.6.0
The pytest team is proud to announce the 3.6.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
pytest is a mature Python testing tool with more than 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.7.0
The pytest team is proud to announce the 3.7.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.8.0
The pytest team is proud to announce the 3.8.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-3.9.0
The pytest team is proud to announce the 3.9.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.0.0
The pytest team is proud to announce the 4.0.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.1.0
The pytest team is proud to announce the 4.1.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.2.0
The pytest team is proud to announce the 4.2.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.3.0
The pytest team is proud to announce the 4.3.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.4.0
The pytest team is proud to announce the 4.4.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.5.0
The pytest team is proud to announce the 4.5.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-4.6.0
The pytest team is proud to announce the 4.6.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-5.0.0
The pytest team is proud to announce the 5.0.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-5.1.0
The pytest team is proud to announce the 5.1.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-5.2.0
The pytest team is proud to announce the 5.2.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-5.3.0
The pytest team is proud to announce the 5.3.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged

View File

@@ -3,7 +3,7 @@ pytest-5.4.0
The pytest team is proud to announce the 5.4.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
pytest is a mature Python testing tool with more than 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bug fixes and improvements, so users are encouraged

View File

@@ -0,0 +1,21 @@
pytest-6.0.1
=======================================
pytest 6.0.1 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Bruno Oliveira
* Mattreex
* Ran Benita
* hp310780
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,19 @@
pytest-6.0.2
=======================================
pytest 6.0.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all of the contributors to this release:
* Bruno Oliveira
* Ran Benita
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,44 @@
pytest-6.1.0
=======================================
The pytest team is proud to announce the 6.1.0 release!
This release contains new features, improvements, bug fixes, and breaking changes, so users
are encouraged to take a look at the CHANGELOG carefully:
https://docs.pytest.org/en/stable/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/stable/
As usual, you can upgrade from PyPI via:
pip install -U pytest
Thanks to all of the contributors to this release:
* Anthony Sottile
* Bruno Oliveira
* C. Titus Brown
* Drew Devereux
* Faris A Chugthai
* Florian Bruhin
* Hugo van Kemenade
* Hynek Schlawack
* Joseph Lucas
* Kamran Ahmad
* Mattreex
* Maximilian Cosmo Sitter
* Ran Benita
* Rüdiger Busche
* Sam Estep
* Sorin Sbarnea
* Thomas Grainger
* Vipul Kumar
* Yutaro Ikeda
* hp310780
Happy testing,
The pytest Development Team

View File

@@ -23,7 +23,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
cache.get(key, default)
cache.set(key, value)
Keys must be a ``/`` separated value, where the first part is usually the
Keys must be ``/`` separated strings, 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.
@@ -57,7 +57,8 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
``out`` and ``err`` will be ``byte`` objects.
doctest_namespace [session scope]
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
Fixture that returns a :py:class:`dict` that will be injected into the
namespace of doctests.
pytestconfig [session scope]
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
@@ -89,8 +90,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
automatically XML-encoded.
record_testsuite_property [session scope]
Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.
Record a new ``<property>`` tag as child of the root ``<testsuite>``.
This is suitable to writing global information regarding the entire test
suite, and is compatible with ``xunit2`` JUnit family.
This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:
@@ -102,6 +105,12 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
.. warning::
Currently this fixture **does not work** with the
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
`#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
caplog
Access and control log capturing.
@@ -114,8 +123,10 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
* caplog.clear() -> clear captured records and formatted log output string
monkeypatch
The returned ``monkeypatch`` fixture provides these
helper methods to modify objects, dictionaries or os.environ::
A convenient fixture for monkey-patching.
The fixture provides these methods to modify objects, dictionaries or
os.environ::
monkeypatch.setattr(obj, name, value, raising=True)
monkeypatch.delattr(obj, name, raising=True)
@@ -126,10 +137,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)
All modifications will be undone after the requesting
test function or fixture has finished. The ``raising``
parameter determines if a KeyError or AttributeError
will be raised if the set/deletion operation has no target.
All modifications will be undone after the requesting test function or
fixture has finished. The ``raising`` parameter determines if a KeyError
or AttributeError will be raised if the set/deletion operation has no target.
recwarn
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
@@ -140,30 +150,28 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
tmpdir_factory [session scope]
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
tmp_path_factory [session scope]
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
tmpdir
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a `py.path.local`_
path object.
Return a temporary directory path object which is unique to each test
function invocation, created as a sub directory of the base temporary
directory.
The returned object is a `py.path.local`_ path object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
tmp_path
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a :class:`pathlib.Path`
object.
Return a temporary directory path object which is unique to each test
function invocation, created as a sub directory of the base temporary
directory.
The returned object is a :class:`pathlib.Path` object.
.. note::
in python < 3.6 this is a pathlib2.Path
In python < 3.6 this is a pathlib2.Path.
no tests ran in 0.12s

View File

@@ -264,7 +264,7 @@ the cache and nothing will be printed:
FAILED test_caching.py::test_function - assert 42 == 23
1 failed in 0.12s
See the :fixture:`config.cache fixture <config.cache>` for more details.
See the :fixture:`config.cache fixture <cache>` for more details.
Inspecting Cache content

View File

@@ -28,6 +28,205 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
pytest 6.1.0 (2020-09-26)
=========================
Breaking Changes
----------------
- `#5585 <https://github.com/pytest-dev/pytest/issues/5585>`_: As per our policy, the following features which have been deprecated in the 5.X series are now
removed:
* The ``funcargnames`` read-only property of ``FixtureRequest``, ``Metafunc``, and ``Function`` classes. Use ``fixturenames`` attribute.
* ``@pytest.fixture`` no longer supports positional arguments, pass all arguments by keyword instead.
* Direct construction of ``Node`` subclasses now raise an error, use ``from_parent`` instead.
* The default value for ``junit_family`` has changed to ``xunit2``. If you require the old format, add ``junit_family=xunit1`` to your configuration file.
* The ``TerminalReporter`` no longer has a ``writer`` attribute. Plugin authors may use the public functions of the ``TerminalReporter`` instead of accessing the ``TerminalWriter`` object directly.
* The ``--result-log`` option has been removed. Users are recommended to use the `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin instead.
For more information consult
`Deprecations and Removals <https://docs.pytest.org/en/stable/deprecations.html>`__ in the docs.
Deprecations
------------
- `#6981 <https://github.com/pytest-dev/pytest/issues/6981>`_: The ``pytest.collect`` module is deprecated: all its names can be imported from ``pytest`` directly.
- `#7097 <https://github.com/pytest-dev/pytest/issues/7097>`_: The ``pytest._fillfuncargs`` function is deprecated. This function was kept
for backward compatibility with an older plugin.
It's functionality is not meant to be used directly, but if you must replace
it, use `function._request._fillfixtures()` instead, though note this is not
a public API and may break in the future.
- `#7210 <https://github.com/pytest-dev/pytest/issues/7210>`_: The special ``-k '-expr'`` syntax to ``-k`` is deprecated. Use ``-k 'not expr'``
instead.
The special ``-k 'expr:'`` syntax to ``-k`` is deprecated. Please open an issue
if you use this and want a replacement.
- `#7255 <https://github.com/pytest-dev/pytest/issues/7255>`_: The :func:`pytest_warning_captured <_pytest.hookspec.pytest_warning_captured>` hook is deprecated in favor
of :func:`pytest_warning_recorded <_pytest.hookspec.pytest_warning_recorded>`, and will be removed in a future version.
- `#7648 <https://github.com/pytest-dev/pytest/issues/7648>`_: The ``gethookproxy()`` and ``isinitpath()`` methods of ``FSCollector`` and ``Package`` are deprecated;
use ``self.session.gethookproxy()`` and ``self.session.isinitpath()`` instead.
This should work on all pytest versions.
Features
--------
- `#7667 <https://github.com/pytest-dev/pytest/issues/7667>`_: New ``--durations-min`` command-line flag controls the minimal duration for inclusion in the slowest list of tests shown by ``--durations``. Previously this was hard-coded to ``0.005s``.
Improvements
------------
- `#6681 <https://github.com/pytest-dev/pytest/issues/6681>`_: Internal pytest warnings issued during the early stages of initialization are now properly handled and can filtered through :confval:`filterwarnings` or ``--pythonwarnings/-W``.
This also fixes a number of long standing issues: `#2891 <https://github.com/pytest-dev/pytest/issues/2891>`__, `#7620 <https://github.com/pytest-dev/pytest/issues/7620>`__, `#7426 <https://github.com/pytest-dev/pytest/issues/7426>`__.
- `#7572 <https://github.com/pytest-dev/pytest/issues/7572>`_: When a plugin listed in ``required_plugins`` is missing or an unknown config key is used with ``--strict-config``, a simple error message is now shown instead of a stacktrace.
- `#7685 <https://github.com/pytest-dev/pytest/issues/7685>`_: Added two new attributes :attr:`rootpath <_pytest.config.Config.rootpath>` and :attr:`inipath <_pytest.config.Config.inipath>` to :class:`Config <_pytest.config.Config>`.
These attributes are :class:`pathlib.Path` versions of the existing :attr:`rootdir <_pytest.config.Config.rootdir>` and :attr:`inifile <_pytest.config.Config.inifile>` attributes,
and should be preferred over them when possible.
- `#7780 <https://github.com/pytest-dev/pytest/issues/7780>`_: Public classes which are not designed to be inherited from are now marked `@final <https://docs.python.org/3/library/typing.html#typing.final>`_.
Code which inherits from these classes will trigger a type-checking (e.g. mypy) error, but will still work in runtime.
Currently the ``final`` designation does not appear in the API Reference but hopefully will in the future.
Bug Fixes
---------
- `#1953 <https://github.com/pytest-dev/pytest/issues/1953>`_: Fixed error when overwriting a parametrized fixture, while also reusing the super fixture value.
.. code-block:: python
# conftest.py
import pytest
@pytest.fixture(params=[1, 2])
def foo(request):
return request.param
# test_foo.py
import pytest
@pytest.fixture
def foo(foo):
return foo * 2
- `#4984 <https://github.com/pytest-dev/pytest/issues/4984>`_: Fixed an internal error crash with ``IndexError: list index out of range`` when
collecting a module which starts with a decorated function, the decorator
raises, and assertion rewriting is enabled.
- `#7591 <https://github.com/pytest-dev/pytest/issues/7591>`_: pylint shouldn't complain anymore about unimplemented abstract methods when inheriting from :ref:`File <non-python tests>`.
- `#7628 <https://github.com/pytest-dev/pytest/issues/7628>`_: Fixed test collection when a full path without a drive letter was passed to pytest on Windows (for example ``\projects\tests\test.py`` instead of ``c:\projects\tests\pytest.py``).
- `#7638 <https://github.com/pytest-dev/pytest/issues/7638>`_: Fix handling of command-line options that appear as paths but trigger an OS-level syntax error on Windows, such as the options used internally by ``pytest-xdist``.
- `#7742 <https://github.com/pytest-dev/pytest/issues/7742>`_: Fixed INTERNALERROR when accessing locals / globals with faulty ``exec``.
Improved Documentation
----------------------
- `#1477 <https://github.com/pytest-dev/pytest/issues/1477>`_: Removed faq.rst and its reference in contents.rst.
Trivial/Internal Changes
------------------------
- `#7536 <https://github.com/pytest-dev/pytest/issues/7536>`_: The internal ``junitxml`` plugin has rewritten to use ``xml.etree.ElementTree``.
The order of attributes in XML elements might differ. Some unneeded escaping is
no longer performed.
- `#7587 <https://github.com/pytest-dev/pytest/issues/7587>`_: The dependency on the ``more-itertools`` package has been removed.
- `#7631 <https://github.com/pytest-dev/pytest/issues/7631>`_: The result type of :meth:`capfd.readouterr() <_pytest.capture.CaptureFixture.readouterr>` (and similar) is no longer a namedtuple,
but should behave like one in all respects. This was done for technical reasons.
- `#7671 <https://github.com/pytest-dev/pytest/issues/7671>`_: When collecting tests, pytest finds test classes and functions by examining the
attributes of python objects (modules, classes and instances). To speed up this
process, pytest now ignores builtin attributes (like ``__class__``,
``__delattr__`` and ``__new__``) without consulting the :confval:`python_classes` and
:confval:`python_functions` configuration options and without passing them to plugins
using the :func:`pytest_pycollect_makeitem <_pytest.hookspec.pytest_pycollect_makeitem>` hook.
pytest 6.0.2 (2020-09-04)
=========================
Bug Fixes
---------
- `#7148 <https://github.com/pytest-dev/pytest/issues/7148>`_: Fixed ``--log-cli`` potentially causing unrelated ``print`` output to be swallowed.
- `#7672 <https://github.com/pytest-dev/pytest/issues/7672>`_: Fixed log-capturing level restored incorrectly if ``caplog.set_level`` is called more than once.
- `#7686 <https://github.com/pytest-dev/pytest/issues/7686>`_: Fixed `NotSetType.token` being used as the parameter ID when the parametrization list is empty.
Regressed in pytest 6.0.0.
- `#7707 <https://github.com/pytest-dev/pytest/issues/7707>`_: Fix internal error when handling some exceptions that contain multiple lines or the style uses multiple lines (``--tb=line`` for example).
pytest 6.0.1 (2020-07-30)
=========================
Bug Fixes
---------
- `#7394 <https://github.com/pytest-dev/pytest/issues/7394>`_: Passing an empty ``help`` value to ``Parser.add_option`` is now accepted instead of crashing when running ``pytest --help``.
Passing ``None`` raises a more informative ``TypeError``.
- `#7558 <https://github.com/pytest-dev/pytest/issues/7558>`_: Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
- `#7559 <https://github.com/pytest-dev/pytest/issues/7559>`_: Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
- `#7569 <https://github.com/pytest-dev/pytest/issues/7569>`_: Fix logging capture handler's level not reset on teardown after a call to ``caplog.set_level()``.
pytest 6.0.0 (2020-07-28)
=========================
@@ -192,9 +391,9 @@ Breaking Changes
- `#7224 <https://github.com/pytest-dev/pytest/issues/7224>`_: The `item.catch_log_handler` and `item.catch_log_handlers` attributes, set by the
logging plugin and never meant to be public , are no longer available.
logging plugin and never meant to be public, are no longer available.
The deprecated ``--no-print-logs`` option is removed. Use ``--show-capture`` instead.
The deprecated ``--no-print-logs`` option and ``log_print`` ini option are removed. Use ``--show-capture`` instead.
- `#7226 <https://github.com/pytest-dev/pytest/issues/7226>`_: Removed the unused ``args`` parameter from ``pytest.Function.__init__``.
@@ -7383,7 +7582,7 @@ Bug fixes:
- pluginmanager.register(...) now raises ValueError if the
plugin has been already registered or the name is taken
- fix issue159: improve http://pytest.org/en/stable/faq.html
- fix issue159: improve https://docs.pytest.org/en/6.0.1/faq.html
especially with respect to the "magic" history, also mention
pytest-django, trial and unittest integration.

View File

@@ -38,7 +38,6 @@ Full pytest documentation
customize
example/index
bash-completion
faq
backwards-compatibility
deprecations

View File

@@ -180,10 +180,15 @@ are never merged - the first match wins.
The internal :class:`Config <_pytest.config.Config>` object (accessible via hooks or through the :fixture:`pytestconfig` fixture)
will subsequently carry these attributes:
- ``config.rootdir``: the determined root directory, guaranteed to exist.
- :attr:`config.rootpath <_pytest.config.Config.rootpath>`: the determined root directory, guaranteed to exist.
- ``config.inifile``: the determined ``configfile``, may be ``None`` (it is named ``inifile``
for historical reasons).
- :attr:`config.inipath <_pytest.config.Config.inipath>`: the determined ``configfile``, may be ``None``
(it is named ``inipath`` for historical reasons).
.. versionadded:: 6.1
The ``config.rootpath`` and ``config.inipath`` properties. They are :class:`pathlib.Path`
versions of the older ``config.rootdir`` and ``config.inifile``, which have type
``py.path.local``, and still exist for backward compatibility.
The ``rootdir`` is used as a reference directory for constructing test
addresses ("nodeids") and can be used also by plugins for storing

View File

@@ -16,8 +16,7 @@ Deprecated Features
-------------------
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
:ref:`standard warning filters <warnings>`.
:class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
The ``pytest_warning_captured`` hook
@@ -30,11 +29,19 @@ This hook has an `item` parameter which cannot be serialized by ``pytest-xdist``
Use the ``pytest_warning_recored`` hook instead, which replaces the ``item`` parameter
by a ``nodeid`` parameter.
The ``pytest.collect`` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 6.0
The ``pytest.collect`` module is no longer part of the public API, all its names
should now be imported from ``pytest`` directly instead.
The ``pytest._fillfuncargs`` function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.5
.. deprecated:: 6.0
This function was kept for backward compatibility with an older plugin.
@@ -43,6 +50,11 @@ it, use `function._request._fillfixtures()` instead, though note this is not
a public API and may break in the future.
Removed Features
----------------
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
an appropriate period of deprecation has passed.
``--no-print-logs`` command-line option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -51,45 +63,54 @@ a public API and may break in the future.
.. versionremoved:: 6.0
Option ``--no-print-logs`` is removed. If you used ``--no-print-logs``, please use ``--show-capture`` instead.
The ``--no-print-logs`` option and ``log_print`` ini setting are removed. If
you used them, please use ``--show-capture`` instead.
``--show-capture`` command-line option was added in ``pytest 3.5.0`` and allows to specify how to
A ``--show-capture`` command-line option was added in ``pytest 3.5.0`` which allows to specify how to
display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).
Node Construction changed to ``Node.from_parent``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Result log (``--result-log``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.4
.. deprecated:: 4.0
.. versionremoved:: 6.0
The construction of nodes now should use the named constructor ``from_parent``.
This limitation in api surface intends to enable better/simpler refactoring of the collection tree.
The ``--result-log`` option produces a stream of test reports which can be
analysed at runtime, but it uses a custom format which requires users to implement their own
parser.
This means that instead of :code:`MyItem(name="foo", parent=collector, obj=42)`
one now has to invoke :code:`MyItem.from_parent(collector, name="foo")`.
The `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing
one JSON object per-line, and should cover the same use cases. Please try it out and provide feedback.
Plugins that wish to support older versions of pytest and suppress the warning can use
`hasattr` to check if `from_parent` exists in that version:
The ``pytest-reportlog`` plugin might even be merged into the core
at some point, depending on the plans for the plugins and number of users using it.
.. code-block:: python
``pytest_collect_directory`` hook
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def pytest_pycollect_makeitem(collector, name, obj):
if hasattr(MyItem, "from_parent"):
item = MyItem.from_parent(collector, name="foo")
item.obj = 42
return item
else:
return MyItem(name="foo", parent=collector, obj=42)
.. versionremoved:: 6.0
Note that ``from_parent`` should only be called with keyword arguments for the parameters.
The ``pytest_collect_directory`` has not worked properly for years (it was called
but the results were ignored). Users may consider using :func:`pytest_collection_modifyitems <_pytest.hookspec.pytest_collection_modifyitems>` instead.
TerminalReporter.writer
~~~~~~~~~~~~~~~~~~~~~~~
.. versionremoved:: 6.0
The ``TerminalReporter.writer`` attribute has been deprecated and should no longer be used. This
was inadvertently exposed as part of the public API of that plugin and ties it too much
with ``py.io.TerminalWriter``.
Plugins that used ``TerminalReporter.writer`` directly should instead use ``TerminalReporter``
methods that provide the same functionality.
``junit_family`` default value change to "xunit2"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.2
.. versionchanged:: 6.0
The default value of ``junit_family`` option will change to ``xunit2`` in pytest 6.0, which
is an update of the old ``xunit1`` format and is supported by default in modern tools
@@ -125,11 +146,44 @@ Services known to support the ``xunit2`` format:
* `Jenkins <https://www.jenkins.io/>`__ with the `JUnit <https://plugins.jenkins.io/junit>`__ plugin.
* `Azure Pipelines <https://azure.microsoft.com/en-us/services/devops/pipelines>`__.
Node Construction changed to ``Node.from_parent``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionchanged:: 6.0
The construction of nodes now should use the named constructor ``from_parent``.
This limitation in api surface intends to enable better/simpler refactoring of the collection tree.
This means that instead of :code:`MyItem(name="foo", parent=collector, obj=42)`
one now has to invoke :code:`MyItem.from_parent(collector, name="foo")`.
Plugins that wish to support older versions of pytest and suppress the warning can use
`hasattr` to check if `from_parent` exists in that version:
.. code-block:: python
def pytest_pycollect_makeitem(collector, name, obj):
if hasattr(MyItem, "from_parent"):
item = MyItem.from_parent(collector, name="foo")
item.obj = 42
return item
else:
return MyItem(name="foo", parent=collector, obj=42)
Note that ``from_parent`` should only be called with keyword arguments for the parameters.
``pytest.fixture`` arguments are keyword only
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionremoved:: 6.0
Passing arguments to pytest.fixture() as positional arguments has been removed - pass them by keyword instead.
``funcargnames`` alias for ``fixturenames``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.0
.. versionremoved:: 6.0
The ``FixtureRequest``, ``Metafunc``, and ``Function`` classes track the names of
their associated fixtures, with the aptly-named ``fixturenames`` attribute.
@@ -140,42 +194,6 @@ in places where we or plugin authors must distinguish between fixture names and
names supplied by non-fixture things such as ``pytest.mark.parametrize``.
Result log (``--result-log``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 4.0
The ``--result-log`` option produces a stream of test reports which can be
analysed at runtime, but it uses a custom format which requires users to implement their own
parser.
The `pytest-reportlog <https://github.com/pytest-dev/pytest-reportlog>`__ plugin provides a ``--report-log`` option, a more standard and extensible alternative, producing
one JSON object per-line, and should cover the same use cases. Please try it out and provide feedback.
The plan is remove the ``--result-log`` option in pytest 6.0 if ``pytest-reportlog`` proves satisfactory
to all users and is deemed stable. The ``pytest-reportlog`` plugin might even be merged into the core
at some point, depending on the plans for the plugins and number of users using it.
TerminalReporter.writer
~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.4
The ``TerminalReporter.writer`` attribute has been deprecated and should no longer be used. This
was inadvertently exposed as part of the public API of that plugin and ties it too much
with ``py.io.TerminalWriter``.
Plugins that used ``TerminalReporter.writer`` directly should instead use ``TerminalReporter``
methods that provide the same functionality.
Removed Features
----------------
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
an appropriate period of deprecation has passed.
``pytest.config`` global
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -357,7 +375,7 @@ Metafunc.addcall
.. versionremoved:: 4.0
:meth:`_pytest.python.Metafunc.addcall` was a precursor to the current parametrized mechanism. Users should use
``_pytest.python.Metafunc.addcall`` was a precursor to the current parametrized mechanism. Users should use
:meth:`_pytest.python.Metafunc.parametrize` instead.
Example:
@@ -592,7 +610,7 @@ This has been documented as deprecated for years, but only now we are actually e
.. versionremoved:: 4.0
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
As part of a large :ref:`marker-revamp`, ``_pytest.nodes.Node.get_marker`` is removed. See
:ref:`the documentation <update marker code>` on tips on how to update your code.

View File

@@ -201,6 +201,11 @@ Or to select "http" and "quick" tests:
You can use ``and``, ``or``, ``not`` and parentheses.
In addition to the test's name, ``-k`` also matches the names of the test's parents (usually, the name of the file and class it's in),
attributes set on the test function, markers applied to it or its parents and any :attr:`extra keywords <_pytest.nodes.Node.extra_keyword_matches>`
explicitly added to it or its parents.
Registering markers
-------------------------------------
@@ -280,7 +285,7 @@ its test methods:
This is equivalent to directly applying the decorator to the
two test functions.
To apply marks at the module level, use the :globalvar:`pytestmark` global variable:
To apply marks at the module level, use the :globalvar:`pytestmark` global variable::
import pytest
pytestmark = pytest.mark.webtest

View File

@@ -12,7 +12,7 @@ A basic example for specifying tests in Yaml files
.. _`pytest-yamlwsgi`: http://bitbucket.org/aafshar/pytest-yamlwsgi/src/tip/pytest_yamlwsgi.py
.. _`PyYAML`: https://pypi.org/project/PyYAML/
Here is an example ``conftest.py`` (extracted from Ali Afshnars special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yaml`` files and will execute the yaml-formatted content as custom tests:
Here is an example ``conftest.py`` (extracted from Ali Afshar's special purpose `pytest-yamlwsgi`_ plugin). This ``conftest.py`` will collect ``test*.yaml`` files and will execute the yaml-formatted content as custom tests:
.. include:: nonpython/conftest.py
:literal:

View File

@@ -9,7 +9,8 @@ def pytest_collect_file(parent, path):
class YamlFile(pytest.File):
def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML
# We need a yaml parser, e.g. PyYAML.
import yaml
raw = yaml.safe_load(self.fspath.open())
for name, spec in sorted(raw.items()):
@@ -23,12 +24,12 @@ class YamlItem(pytest.Item):
def runtest(self):
for name, value in sorted(self.spec.items()):
# some custom test execution (dumb example follows)
# Some custom test execution (dumb example follows).
if name != value:
raise YamlException(self, name, value)
def repr_failure(self, excinfo):
""" called when self.runtest() raises an exception. """
"""Called when self.runtest() raises an exception."""
if isinstance(excinfo.value, YamlException):
return "\n".join(
[
@@ -43,4 +44,4 @@ class YamlItem(pytest.Item):
class YamlException(Exception):
""" custom exception for error reporting. """
"""Custom exception for error reporting."""

View File

@@ -313,3 +313,12 @@ interpreter:
collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
collect_ignore_glob = ["*_py2.py"]
Since Pytest 2.6, users can prevent pytest from discovering classes that start
with ``Test`` by setting a boolean ``__test__`` attribute to ``False``.
.. code-block:: python
# Will not be discovered as a test
class TestClass:
__test__ = False

View File

@@ -1,158 +0,0 @@
Some Issues and Questions
==================================
.. note::
This FAQ is here only mostly for historic reasons. Checkout
`pytest Q&A at Stackoverflow <http://stackoverflow.com/search?q=pytest>`_
for many questions and answers related to pytest and/or use
:ref:`contact channels` to get help.
On naming, nosetests, licensing and magic
------------------------------------------------
How does pytest relate to nose and unittest?
+++++++++++++++++++++++++++++++++++++++++++++++++
``pytest`` and nose_ share basic philosophy when it comes
to running and writing Python tests. In fact, you can run many tests
written for nose with ``pytest``. nose_ was originally created
as a clone of ``pytest`` when ``pytest`` was in the ``0.8`` release
cycle. Note that starting with pytest-2.0 support for running unittest
test suites is majorly improved.
how does pytest relate to twisted's trial?
++++++++++++++++++++++++++++++++++++++++++++++
Since some time ``pytest`` has builtin support for supporting tests
written using trial. It does not itself start a reactor, however,
and does not handle Deferreds returned from a test in pytest style.
If you are using trial's unittest.TestCase chances are that you can
just run your tests even if you return Deferreds. In addition,
there also is a dedicated `pytest-twisted
<https://pypi.org/project/pytest-twisted/>`_ plugin which allows you to
return deferreds from pytest-style tests, allowing the use of
:ref:`fixtures <fixtures>` and other features.
how does pytest work with Django?
++++++++++++++++++++++++++++++++++++++++++++++
In 2012, some work is going into the `pytest-django plugin <https://pypi.org/project/pytest-django/>`_. It substitutes the usage of Django's
``manage.py test`` and allows the use of all pytest features_ most of which
are not available from Django directly.
.. _features: features.html
What's this "magic" with pytest? (historic notes)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Around 2007 (version ``0.8``) some people thought that ``pytest``
was using too much "magic". It had been part of the `pylib`_ which
contains a lot of unrelated python library code. Around 2010 there
was a major cleanup refactoring, which removed unused or deprecated code
and resulted in the new ``pytest`` PyPI package which strictly contains
only test-related code. This release also brought a complete pluginification
such that the core is around 300 lines of code and everything else is
implemented in plugins. Thus ``pytest`` today is a small, universally runnable
and customizable testing framework for Python. Note, however, that
``pytest`` uses metaprogramming techniques and reading its source is
thus likely not something for Python beginners.
A second "magic" issue was the assert statement debugging feature.
Nowadays, ``pytest`` explicitly rewrites assert statements in test modules
in order to provide more useful :ref:`assert feedback <assertfeedback>`.
This completely avoids previous issues of confusing assertion-reporting.
It also means, that you can use Python's ``-O`` optimization without losing
assertions in test modules.
You can also turn off all assertion interaction using the
``--assert=plain`` option.
.. _`py namespaces`: index.html
.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py
Why can I use both ``pytest`` and ``py.test`` commands?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pytest used to be part of the py package, which provided several developer
utilities, all starting with ``py.<TAB>``, thus providing nice TAB-completion.
If you install ``pip install pycmd`` you get these tools from a separate
package. Once ``pytest`` became a separate package, the ``py.test`` name was
retained due to avoid a naming conflict with another tool. This conflict was
eventually resolved, and the ``pytest`` command was therefore introduced. In
future versions of pytest, we may deprecate and later remove the ``py.test``
command to avoid perpetuating the confusion.
pytest fixtures, parametrized tests
-------------------------------------------------------
.. _funcargs: funcargs.html
Is using pytest fixtures versus xUnit setup a style question?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
For simple applications and for people experienced with nose_ or
unittest-style test setup using `xUnit style setup`_ probably
feels natural. For larger test suites, parametrized testing
or setup of complex test resources using fixtures_ may feel more natural.
Moreover, fixtures are ideal for writing advanced test support
code (like e.g. the monkeypatch_, the tmpdir_ or capture_ fixtures)
because the support code can register setup/teardown functions
in a managed class/module/function scope.
.. _monkeypatch: monkeypatch.html
.. _tmpdir: tmpdir.html
.. _capture: capture.html
.. _fixtures: fixture.html
.. _`why pytest_pyfuncarg__ methods?`:
.. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration
Can I yield multiple values from a fixture function?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
There are two conceptual reasons why yielding from a factory function
is not possible:
* If multiple factories yielded values there would
be no natural place to determine the combination
policy - in real-world examples some combinations
often should not run.
* Calling factories for obtaining test function arguments
is part of setting up and running a test. At that
point it is not possible to add new test calls to
the test collection anymore.
However, with pytest-2.3 you can use the :ref:`@pytest.fixture` decorator
and specify ``params`` so that all tests depending on the factory-created
resource will run multiple times with different parameters.
You can also use the ``pytest_generate_tests`` hook to
implement the `parametrization scheme of your choice`_. See also
:ref:`paramexamples` for more examples.
.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
pytest interaction with other packages
---------------------------------------------------
Issues with pytest, multiprocess and setuptools?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
On Windows the multiprocess package will instantiate sub processes
by pickling and thus implicitly re-import a lot of local modules.
Unfortunately, setuptools-0.6.11 does not ``if __name__=='__main__'``
protect its generated command line script. This leads to infinite
recursion when running a test that instantiates Processes.
As of mid-2013, there shouldn't be a problem anymore when you
use the standard setuptools (note that distribute has been merged
back into setuptools which is now shipped directly with virtualenv).
.. _nose: https://nose.readthedocs.io/en/latest/
.. _pylib: https://py.readthedocs.io/en/latest/
.. _`xUnit style setup`: xunit_setup.html

View File

@@ -121,7 +121,7 @@ Fixtures as Function arguments
Test functions can receive fixture objects by naming them as an input
argument. For each argument name, a fixture function with that name provides
the fixture object. Fixture functions are registered by marking them with
:py:func:`@pytest.fixture <_pytest.python.fixture>`. Let's look at a simple
:py:func:`@pytest.fixture <pytest.fixture>`. Let's look at a simple
self-contained test module containing a fixture and a test function
using it:
@@ -144,7 +144,7 @@ using it:
assert 0 # for demo purposes
Here, the ``test_ehlo`` needs the ``smtp_connection`` fixture value. pytest
will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>`
will discover and call the :py:func:`@pytest.fixture <pytest.fixture>`
marked ``smtp_connection`` fixture function. Running the test looks like this:
.. code-block:: pytest
@@ -252,7 +252,7 @@ Scope: sharing fixtures across classes, modules, packages or session
Fixtures requiring network access depend on connectivity and are
usually time-expensive to create. Extending the previous example, we
can add a ``scope="module"`` parameter to the
:py:func:`@pytest.fixture <_pytest.python.fixture>` invocation
:py:func:`@pytest.fixture <pytest.fixture>` invocation
to cause the decorated ``smtp_connection`` fixture function to only be invoked
once per test *module* (the default is to invoke once per test *function*).
Multiple test functions in a test module will thus
@@ -592,7 +592,7 @@ will not be executed.
Fixtures can introspect the requesting test context
-------------------------------------------------------------
Fixture functions can accept the :py:class:`request <FixtureRequest>` object
Fixture functions can accept the :py:class:`request <_pytest.fixtures.FixtureRequest>` object
to introspect the "requesting" test function, class or module context.
Further extending the previous ``smtp_connection`` fixture example, let's
read an optional server URL from the test module which uses our fixture:
@@ -664,7 +664,7 @@ from the module namespace.
Using markers to pass data to fixtures
-------------------------------------------------------------
Using the :py:class:`request <FixtureRequest>` object, a fixture can also access
Using the :py:class:`request <_pytest.fixtures.FixtureRequest>` object, a fixture can also access
markers which are applied to a test function. This can be useful to pass data
into a fixture from a test:
@@ -775,7 +775,7 @@ through the special :py:class:`request <FixtureRequest>` object:
smtp_connection.close()
The main change is the declaration of ``params`` with
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
:py:func:`@pytest.fixture <pytest.fixture>`, a list of values
for each of which the fixture function will execute and can access
a value via ``request.param``. No test function code needs to change.
So let's just do another run:
@@ -1136,8 +1136,8 @@ and teared down after every test that used it.
.. _`usefixtures`:
Using fixtures from classes, modules or projects
----------------------------------------------------------------------
Use fixtures in classes and modules with ``usefixtures``
--------------------------------------------------------
.. regendoc:wipe
@@ -1531,3 +1531,37 @@ Given the tests file structure is:
In the example above, a parametrized fixture is overridden with a non-parametrized version, and
a non-parametrized fixture is overridden with a parametrized version for certain test module.
The same applies for the test folder level obviously.
Using fixtures from other projects
----------------------------------
Usually projects that provide pytest support will use :ref:`entry points <setuptools entry points>`,
so just installing those projects into an environment will make those fixtures available for use.
In case you want to use fixtures from a project that does not use entry points, you can
define :globalvar:`pytest_plugins` in your top ``conftest.py`` file to register that module
as a plugin.
Suppose you have some fixtures in ``mylibrary.fixtures`` and you want to reuse them into your
``app/tests`` directory.
All you need to do is to define :globalvar:`pytest_plugins` in ``app/tests/conftest.py``
pointing to that module.
.. code-block:: python
pytest_plugins = "mylibrary.fixtures"
This effectively registers ``mylibrary.fixtures`` as a plugin, making all its fixtures and
hooks available to tests in ``app/tests``.
.. note::
Sometimes users will *import* fixtures from other projects for use, however this is not
recommended: importing fixtures into a module will register them in pytest
as *defined* in that module.
This has minor consequences, such as appearing multiple times in ``pytest --help``,
but it is not **recommended** because this behavior might change/stop working
in future versions.

View File

@@ -51,7 +51,7 @@ There are several limitations and difficulties with this approach:
performs parametrization at the places where the resource
is used. Moreover, you need to modify the factory to use an
``extrakey`` parameter containing ``request.param`` to the
:py:func:`~python.Request.cached_setup` call.
``Request.cached_setup`` call.
3. Multiple parametrized session-scoped resources will be active
at the same time, making it hard for them to affect global state
@@ -113,7 +113,7 @@ This new way of parametrizing funcarg factories should in many cases
allow to re-use already written factories because effectively
``request.param`` was already used when test functions/classes were
parametrized via
:py:func:`~_pytest.python.Metafunc.parametrize(indirect=True)` calls.
:py:func:`metafunc.parametrize(indirect=True) <_pytest.python.Metafunc.parametrize>` calls.
Of course it's perfectly fine to combine parametrization and scoping:

View File

@@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash
$ pytest --version
pytest 6.0.0
pytest 6.1.0
.. _`simpletest`:

View File

@@ -112,7 +112,7 @@ More details can be found in the `original PR <https://github.com/pytest-dev/pyt
.. note::
in a future major release of pytest we will introduce class based markers,
at which point markers will no longer be limited to instances of :py:class:`Mark`.
at which point markers will no longer be limited to instances of :py:class:`~_pytest.mark.Mark`.
cache plugin integrated into the core

View File

@@ -1,5 +1,11 @@
:orphan:
.. sidebar:: Next Open Trainings
- `Professional testing with Python <https://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, via Python Academy, February 1-3 2021, Leipzig (Germany) and remote.
Also see `previous talks and blogposts <talks.html>`_.
.. _features:
pytest: helps you write better programs
@@ -55,17 +61,17 @@ See :ref:`Getting Started <getstarted>` for more examples.
Features
--------
- Detailed info on failing :ref:`assert statements <assert>` (no need to remember ``self.assert*`` names);
- Detailed info on failing :ref:`assert statements <assert>` (no need to remember ``self.assert*`` names)
- :ref:`Auto-discovery <test discovery>` of test modules and functions;
- :ref:`Auto-discovery <test discovery>` of test modules and functions
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources;
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box;
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
- Python 3.5+ and PyPy 3;
- Python 3.5+ and PyPy 3
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community
Documentation

View File

@@ -43,7 +43,17 @@ You can register custom marks in your ``pytest.ini`` file like this:
slow: marks tests as slow (deselect with '-m "not slow"')
serial
Note that everything after the ``:`` is an optional description.
or in your ``pyproject.toml`` file like this:
.. code-block:: toml
[tool.pytest.ini_options]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"serial",
]
Note that everything past the ``:`` after the mark name is an optional description.
Alternatively, you can register new markers programmatically in a
:ref:`pytest_configure <initialization-hooks>` hook:
@@ -66,7 +76,7 @@ Raising errors on unknown marks
Unregistered marks applied with the ``@pytest.mark.name_of_the_mark`` decorator
will always emit a warning in order to avoid silently doing something
surprising due to mis-typed names. As described in the previous section, you can disable
surprising due to mistyped names. As described in the previous section, you can disable
the warning for custom marks by registering them in your ``pytest.ini`` file or
using a custom ``pytest_configure`` hook.

View File

@@ -33,25 +33,25 @@ Consider the following scenarios:
1. Modifying the behavior of a function or the property of a class for a test e.g.
there is an API call or database connection you will not make for a test but you know
what the expected output should be. Use :py:meth:`monkeypatch.setattr` to patch the
what the expected output should be. Use :py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` to patch the
function or property with your desired testing behavior. This can include your own functions.
Use :py:meth:`monkeypatch.delattr` to remove the function or property for the test.
Use :py:meth:`monkeypatch.delattr <MonkeyPatch.delattr>` to remove the function or property for the test.
2. Modifying the values of dictionaries e.g. you have a global configuration that
you want to modify for certain test cases. Use :py:meth:`monkeypatch.setitem` to patch the
dictionary for the test. :py:meth:`monkeypatch.delitem` can be used to remove items.
you want to modify for certain test cases. Use :py:meth:`monkeypatch.setitem <MonkeyPatch.setitem>` to patch the
dictionary for the test. :py:meth:`monkeypatch.delitem <MonkeyPatch.delitem>` can be used to remove items.
3. Modifying environment variables for a test e.g. to test program behavior if an
environment variable is missing, or to set multiple values to a known variable.
:py:meth:`monkeypatch.setenv` and :py:meth:`monkeypatch.delenv` can be used for
:py:meth:`monkeypatch.setenv <MonkeyPatch.setenv>` and :py:meth:`monkeypatch.delenv <MonkeyPatch.delenv>` can be used for
these patches.
4. Use ``monkeypatch.setenv("PATH", value, prepend=os.pathsep)`` to modify ``$PATH``, and
:py:meth:`monkeypatch.chdir` to change the context of the current working directory
:py:meth:`monkeypatch.chdir <MonkeyPatch.chdir>` to change the context of the current working directory
during a test.
5. Use :py:meth:`monkeypatch.syspath_prepend` to modify ``sys.path`` which will also
call :py:meth:`pkg_resources.fixup_namespace_packages` and :py:meth:`importlib.invalidate_caches`.
5. Use :py:meth:`monkeypatch.syspath_prepend <MonkeyPatch.syspath_prepend>` to modify ``sys.path`` which will also
call ``pkg_resources.fixup_namespace_packages`` and :py:func:`importlib.invalidate_caches`.
See the `monkeypatch blog post`_ for some introduction material
and a discussion of its motivation.
@@ -66,10 +66,10 @@ testing, you do not want your test to depend on the running user. ``monkeypatch`
can be used to patch functions dependent on the user to always return a
specific value.
In this example, :py:meth:`monkeypatch.setattr` is used to patch ``Path.home``
In this example, :py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` is used to patch ``Path.home``
so that the known testing path ``Path("/abc")`` is always used when the test is run.
This removes any dependency on the running user for testing purposes.
:py:meth:`monkeypatch.setattr` must be called before the function which will use
:py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` must be called before the function which will use
the patched function is called.
After the test function finishes the ``Path.home`` modification will be undone.
@@ -102,7 +102,7 @@ After the test function finishes the ``Path.home`` modification will be undone.
Monkeypatching returned objects: building mock classes
------------------------------------------------------
:py:meth:`monkeypatch.setattr` can be used in conjunction with classes to mock returned
:py:meth:`monkeypatch.setattr <MonkeyPatch.setattr>` can be used in conjunction with classes to mock returned
objects from functions instead of values.
Imagine a simple function to take an API url and return the json response.
@@ -330,7 +330,7 @@ This behavior can be moved into ``fixture`` structures and shared across tests:
Monkeypatching dictionaries
---------------------------
:py:meth:`monkeypatch.setitem` can be used to safely set the values of dictionaries
:py:meth:`monkeypatch.setitem <MonkeyPatch.setitem>` can be used to safely set the values of dictionaries
to specific values during tests. Take this simplified connection string example:
.. code-block:: python
@@ -367,7 +367,7 @@ For testing purposes we can patch the ``DEFAULT_CONFIG`` dictionary to specific
result = app.create_connection_string()
assert result == expected
You can use the :py:meth:`monkeypatch.delitem` to remove values.
You can use the :py:meth:`monkeypatch.delitem <MonkeyPatch.delitem>` to remove values.
.. code-block:: python

View File

@@ -182,7 +182,7 @@ Mark a test function as using the given fixture names.
.. py:function:: pytest.mark.usefixtures(*names)
:param args: the names of the fixture to use, as strings
:param args: The names of the fixture to use, as strings.
.. note::
@@ -209,8 +209,10 @@ Marks a test function as *expected to fail*.
Condition for marking the test function as xfail (``True/False`` or a
:ref:`condition string <string conditions>`). If a bool, you also have
to specify ``reason`` (see :ref:`condition string <string conditions>`).
:keyword str reason: Reason why the test function is marked as xfail.
:keyword Exception raises: Exception subclass expected to be raised by the test function; other exceptions will fail the test.
:keyword str reason:
Reason why the test function is marked as xfail.
:keyword Type[Exception] raises:
Exception subclass expected to be raised by the test function; other exceptions will fail the test.
:keyword bool run:
If the test function should actually be executed. If ``False``, the function will always xfail and will
not be executed (useful if a function is segfaulting).
@@ -224,7 +226,7 @@ Marks a test function as *expected to fail*.
a new release of a library fixes a known bug).
custom marks
Custom marks
~~~~~~~~~~~~
Marks are created dynamically using the factory object ``pytest.mark`` and applied as a decorator.
@@ -238,7 +240,7 @@ For example:
...
Will create and attach a :class:`Mark <_pytest.mark.structures.Mark>` object to the collected
:class:`Item <_pytest.nodes.Item>`, which can then be accessed by fixtures or hooks with
:class:`Item <pytest.Item>`, which can then be accessed by fixtures or hooks with
:meth:`Node.iter_markers <_pytest.nodes.Node.iter_markers>`. The ``mark`` object will have the following attributes:
.. code-block:: python
@@ -473,7 +475,7 @@ caplog
.. autofunction:: _pytest.logging.caplog()
:no-auto-options:
This returns a :class:`_pytest.logging.LogCaptureFixture` instance.
Returns a :class:`_pytest.logging.LogCaptureFixture` instance.
.. autoclass:: _pytest.logging.LogCaptureFixture
:members:
@@ -491,7 +493,7 @@ monkeypatch
.. autofunction:: _pytest.monkeypatch.monkeypatch()
:no-auto-options:
This returns a :class:`MonkeyPatch` instance.
Returns a :class:`MonkeyPatch` instance.
.. autoclass:: _pytest.monkeypatch.MonkeyPatch
:members:
@@ -537,14 +539,11 @@ recwarn
.. autofunction:: recwarn()
:no-auto-options:
.. autoclass:: _pytest.recwarn.WarningsRecorder()
.. autoclass:: WarningsRecorder()
:members:
Each recorded warning is an instance of :class:`warnings.WarningMessage`.
.. note::
:class:`RecordedWarning` was changed from a plain class to a namedtuple in pytest 3.1
.. note::
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
differently; see :ref:`ensuring_function_triggers`.
@@ -654,7 +653,6 @@ Collection hooks
.. autofunction:: pytest_collection
.. autofunction:: pytest_ignore_collect
.. autofunction:: pytest_collect_directory
.. autofunction:: pytest_collect_file
.. autofunction:: pytest_pycollect_makemodule
@@ -675,7 +673,7 @@ items, delete or otherwise amend the test items:
Test running (runtest) hooks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>` object.
All runtest related hooks receive a :py:class:`pytest.Item <pytest.Item>` object.
.. autofunction:: pytest_runtestloop
.. autofunction:: pytest_runtest_protocol
@@ -687,8 +685,8 @@ All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>`
.. autofunction:: pytest_runtest_makereport
For deeper understanding you may look at the default implementation of
these hooks in :py:mod:`_pytest.runner` and maybe also
in :py:mod:`_pytest.pdb` which interacts with :py:mod:`_pytest.capture`
these hooks in ``_pytest.runner`` and maybe also
in ``_pytest.pdb`` which interacts with ``_pytest.capture``
and its input/output capturing in order to immediately drop
into interactive debugging when a test failure occurs.
@@ -751,14 +749,14 @@ CallInfo
Class
~~~~~
.. autoclass:: _pytest.python.Class()
.. autoclass:: pytest.Class()
:members:
:show-inheritance:
Collector
~~~~~~~~~
.. autoclass:: _pytest.nodes.Collector()
.. autoclass:: pytest.Collector()
:members:
:show-inheritance:
@@ -783,12 +781,19 @@ ExceptionInfo
:members:
pytest.ExitCode
~~~~~~~~~~~~~~~
ExitCode
~~~~~~~~
.. autoclass:: _pytest.config.ExitCode
.. autoclass:: pytest.ExitCode
:members:
File
~~~~
.. autoclass:: pytest.File()
:members:
:show-inheritance:
FixtureDef
~~~~~~~~~~
@@ -807,14 +812,14 @@ FSCollector
Function
~~~~~~~~
.. autoclass:: _pytest.python.Function()
.. autoclass:: pytest.Function()
:members:
:show-inheritance:
Item
~~~~
.. autoclass:: _pytest.nodes.Item()
.. autoclass:: pytest.Item()
:members:
:show-inheritance:
@@ -848,7 +853,7 @@ Metafunc
Module
~~~~~~
.. autoclass:: _pytest.python.Module()
.. autoclass:: pytest.Module()
:members:
:show-inheritance:
@@ -864,12 +869,6 @@ Parser
.. autoclass:: _pytest.config.argparsing.Parser()
:members:
PluginManager
~~~~~~~~~~~~~
.. autoclass:: pluggy.PluginManager()
:members:
PytestPluginManager
~~~~~~~~~~~~~~~~~~~
@@ -877,12 +876,13 @@ PytestPluginManager
.. autoclass:: _pytest.config.PytestPluginManager()
:members:
:undoc-members:
:inherited-members:
:show-inheritance:
Session
~~~~~~~
.. autoclass:: _pytest.main.Session()
.. autoclass:: pytest.Session()
:members:
:show-inheritance:
@@ -1024,7 +1024,7 @@ When set (regardless of value), pytest will use color in terminal output.
Exceptions
----------
.. autoclass:: _pytest.config.UsageError()
.. autoclass:: pytest.UsageError()
:show-inheritance:
.. _`warnings ref`:
@@ -1466,20 +1466,6 @@ passed multiple times. The expected format is ``name=value``. For example::
For more information, see :ref:`logging`.
.. confval:: log_print
If set to ``False``, will disable displaying captured logging messages for failed tests.
.. code-block:: ini
[pytest]
log_print = False
For more information, see :ref:`logging`.
.. confval:: markers
When the ``--strict-markers`` or ``--strict`` command-line arguments are used,
@@ -1666,3 +1652,296 @@ passed multiple times. The expected format is ``name=value``. For example::
[pytest]
xfail_strict = True
.. _`command-line-flags`:
Command-line Flags
------------------
All the command-line flags can be obtained by running ``pytest --help``::
$ pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:
file_or_dir
general:
-k EXPRESSION 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 their parent classes.
Example: -k 'test_method or test_other' matches all
test functions and classes whose name contains
'test_method' or 'test_other', while -k 'not
test_method' matches those that don't contain
'test_method' in their names. -k 'not test_method
and not test_other' will eliminate the matches.
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. The
matching is case-insensitive.
-m MARKEXPR only run tests matching given mark expression.
For example: -m 'mark1 and not mark2'.
--markers show markers (builtin, plugin and per-project ones).
-x, --exitfirst exit instantly on first error or failed test.
--fixtures, --funcargs
show available fixtures, sorted by plugin appearance
(fixtures with leading '_' are only shown with '-v')
--fixtures-per-test show fixtures per test
--pdb start the interactive Python debugger on errors or
KeyboardInterrupt.
--pdbcls=modulename:classname
start a custom interactive Python debugger on
errors. For example:
--pdbcls=IPython.terminal.debugger:TerminalPdb
--trace Immediately break when running each test.
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
-s shortcut for --capture=no.
--runxfail report the results of xfail tests as if they were
not marked
--lf, --last-failed rerun only the tests that failed at the last run (or
all if none failed)
--ff, --failed-first run all tests, but run the last failures first.
This may re-order tests and thus lead to repeated
fixture setup/teardown.
--nf, --new-first run tests from new files first, then the rest of the
tests sorted by file mtime
--cache-show=[CACHESHOW]
show cache contents, don't perform collection or
tests. Optional argument: glob (default: '*').
--cache-clear remove all cache contents at start of test run.
--lfnf={all,none}, --last-failed-no-failures={all,none}
which tests to run with no previously (known)
failures.
--sw, --stepwise exit on test failure and continue from last failing
test next time
--stepwise-skip ignore the first failing test but stop on the next
failing test
reporting:
--durations=N show N slowest setup/test durations (N=0 for all).
--durations-min=N Minimal duration in seconds for inclusion in slowest
list. Default 0.005
-v, --verbose increase verbosity.
--no-header disable header
--no-summary disable summary
-q, --quiet decrease verbosity.
--verbosity=VERBOSE set verbosity. Default is 0.
-r chars show extra test summary info as specified by chars:
(f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed,
(p)assed, (P)assed with output, (a)ll except passed
(p/P), or (A)ll. (w)arnings are enabled by default
(see --disable-warnings), 'N' can be used to reset
the list. (default: 'fE').
--disable-warnings, --disable-pytest-warnings
disable warnings summary
-l, --showlocals show locals in tracebacks (disabled by default).
--tb=style traceback print mode
(auto/long/short/line/native/no).
--show-capture={no,stdout,stderr,log,all}
Controls how captured stdout/stderr/log is shown on
failed tests. Default is 'all'.
--full-trace don't cut any tracebacks (default is to cut).
--color=color color terminal output (yes/no/auto).
--code-highlight={yes,no}
Whether code should be highlighted (only if --color
is also enabled)
--pastebin=mode send failed|all info to bpaste.net pastebin service.
--junit-xml=path create junit-xml style report file at given path.
--junit-prefix=str prepend prefix to classnames in junit-xml output
pytest-warnings:
-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGS
set which warnings to report, see -W option of
python itself.
--maxfail=num exit after first num failures or errors.
--strict-config any warnings encountered while parsing the `pytest`
section of the configuration file raise errors.
--strict-markers, --strict
markers not registered in the `markers` section of
the configuration file raise errors.
-c file load configuration from `file` instead of trying to
locate one of the implicit configuration files.
--continue-on-collection-errors
Force test execution even if collection errors
occur.
--rootdir=ROOTDIR Define root directory for tests. Can be relative
path: 'root_dir', './root_dir',
'root_dir/another_dir/'; absolute path:
'/home/user/root_dir'; path with variables:
'$HOME/root_dir'.
collection:
--collect-only, --co only collect tests, don't execute them.
--pyargs try to interpret all arguments as python packages.
--ignore=path ignore path during collection (multi-allowed).
--ignore-glob=path ignore path pattern during collection (multi-
allowed).
--deselect=nodeid_prefix
deselect item (via node id prefix) during collection
(multi-allowed).
--confcutdir=dir only load conftest.py's relative to specified dir.
--noconftest Don't load any conftest.py files.
--keep-duplicates Keep duplicate tests.
--collect-in-virtualenv
Don't ignore tests in a local virtualenv directory
--import-mode={prepend,append,importlib}
prepend/append to sys.path when importing test
modules and conftest files, default is to prepend.
--doctest-modules run doctests in all .py modules
--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}
choose another output format for diffs on doctest
failure
--doctest-glob=pat doctests file matching pattern, default: test*.txt
--doctest-ignore-import-errors
ignore doctest ImportErrors
--doctest-continue-on-failure
for a given doctest, continue to run after the first
failure
test session debugging and configuration:
--basetemp=dir base temporary directory for this test run.(warning:
this directory is removed if it exists)
-V, --version display pytest version and information about
plugins.When given twice, also display information
about plugins.
-h, --help show help message and configuration info
-p name early-load given plugin module name or entry point
(multi-allowed).
To avoid loading of plugins, use the `no:` prefix,
e.g. `no:doctest`.
--trace-config trace considerations of conftest.py files.
--debug store internal tracing debug information in
'pytestdebug.log'.
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
override ini option with "option=value" style, e.g.
`-o xfail_strict=True -o cache_dir=cache`.
--assert=MODE Control assertion debugging tools.
'plain' performs no assertion debugging.
'rewrite' (the default) rewrites assert statements
in test modules on import to provide assert
expression information.
--setup-only only setup fixtures, do not execute tests.
--setup-show show setup of fixtures while executing tests.
--setup-plan show what fixtures and tests would be executed but
don't execute anything.
logging:
--log-level=LEVEL level of messages to catch/display.
Not set by default, so it depends on the root/parent
log handler's effective level, where it is "WARNING"
by default.
--log-format=LOG_FORMAT
log format as used by the logging module.
--log-date-format=LOG_DATE_FORMAT
log date format as used by the logging module.
--log-cli-level=LOG_CLI_LEVEL
cli logging level.
--log-cli-format=LOG_CLI_FORMAT
log format as used by the logging module.
--log-cli-date-format=LOG_CLI_DATE_FORMAT
log date format as used by the logging module.
--log-file=LOG_FILE path to a file when logging will be written to.
--log-file-level=LOG_FILE_LEVEL
log file logging level.
--log-file-format=LOG_FILE_FORMAT
log format as used by the logging module.
--log-file-date-format=LOG_FILE_DATE_FORMAT
log date format as used by the logging module.
--log-auto-indent=LOG_AUTO_INDENT
Auto-indent multiline messages passed to the logging
module. Accepts true|on, false|off or an integer.
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:
markers (linelist): markers for test functions
empty_parameter_set_mark (string):
default marker for empty parametersets
norecursedirs (args): directory patterns to avoid for recursion
testpaths (args): directories to search for tests when no files or
directories are given in the command line.
filterwarnings (linelist):
Each line specifies a pattern for
warnings.filterwarnings. Processed after
-W/--pythonwarnings.
usefixtures (args): list of default fixtures to be used with this
project
python_files (args): glob-style file patterns for Python test module
discovery
python_classes (args):
prefixes or glob names for Python test class
discovery
python_functions (args):
prefixes or glob names for Python test function and
method discovery
disable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):
disable string escape non-ascii characters, might
cause unwanted side effects(use at your own risk)
console_output_style (string):
console output: "classic", or with additional
progress information ("progress" (percentage) |
"count").
xfail_strict (bool): default for the strict parameter of xfail markers
when not given explicitly (default: False)
enable_assertion_pass_hook (bool):
Enables the pytest_assertion_pass hook.Make sure to
delete any previously generated pyc cache files.
junit_suite_name (string):
Test suite name for JUnit report
junit_logging (string):
Write captured log messages to JUnit report: one of
no|log|system-out|system-err|out-err|all
junit_log_passing_tests (bool):
Capture log information for passing tests to JUnit
report:
junit_duration_report (string):
Duration time to report: one of total|call
junit_family (string):
Emit XML for schema: one of legacy|xunit1|xunit2
doctest_optionflags (args):
option flags for doctests
doctest_encoding (string):
encoding used for doctest files
cache_dir (string): cache directory path.
log_level (string): default value for --log-level
log_format (string): default value for --log-format
log_date_format (string):
default value for --log-date-format
log_cli (bool): enable log display during test run (also known as
"live logging").
log_cli_level (string):
default value for --log-cli-level
log_cli_format (string):
default value for --log-cli-format
log_cli_date_format (string):
default value for --log-cli-date-format
log_file (string): default value for --log-file
log_file_level (string):
default value for --log-file-level
log_file_format (string):
default value for --log-file-format
log_file_date_format (string):
default value for --log-file-date-format
log_auto_indent (string):
default value for --log-auto-indent
faulthandler_timeout (string):
Dump the traceback of all threads if a test takes
more than TIMEOUT seconds to finish.
addopts (args): extra command line options
minversion (string): minimally required pytest version
required_plugins (args):
plugins that must be present for pytest to run
environment variables:
PYTEST_ADDOPTS extra command line options
PYTEST_PLUGINS comma-separated plugins to load during startup
PYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loading
PYTEST_DEBUG set to enable debug tracing of pytest's internals
to see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading '_' are only shown with the '-v' option

View File

@@ -2,13 +2,6 @@
Talks and Tutorials
==========================
.. sidebar:: Next Open Trainings
- `Free 1h webinar: "pytest: Test Driven Development für Python" <https://mylearning.ch/kurse/online-kurse/tech-webinar/>`_ (German), online, August 18 2020.
- `"pytest: Test Driven Development (nicht nur) für Python" <https://workshoptage.ch/workshops/2020/pytest-test-driven-development-nicht-nur-fuer-python/>`_ (German) at the `CH Open Workshoptage <https://workshoptage.ch/>`_, September 8 2020, HSLU Campus Rotkreuz (ZG), Switzerland.
.. _`funcargs`: funcargs.html
Books
---------------------------------------------
@@ -21,6 +14,16 @@ Books
Talks and blog postings
---------------------------------------------
- Webinar: `pytest: Test Driven Development für Python (German) <https://bruhin.software/ins-pytest/>`_, Florian Bruhin, via mylearning.ch, 2020
- Webinar: `Simplify Your Tests with Fixtures <https://blog.jetbrains.com/pycharm/2020/08/webinar-recording-simplify-your-tests-with-fixtures-with-oliver-bestwalter/>`_, Oliver Bestwalter, via JetBrains, 2020
- Training: `Introduction to pytest - simple, rapid and fun testing with Python <https://www.youtube.com/watch?v=CMuSn9cofbI>`_, Florian Bruhin, PyConDE 2019
- Abridged metaprogramming classics - this episode: pytest, Oliver Bestwalter, PyConDE 2019 (`repository <https://github.com/obestwalter/abridged-meta-programming-classics>`__, `recording <https://www.youtube.com/watch?v=zHpeMTJsBRk&feature=youtu.be>`__)
- Testing PySide/PyQt code easily using the pytest framework, Florian Bruhin, Qt World Summit 2019 (`slides <https://bruhin.software/talks/qtws19.pdf>`__, `recording <https://www.youtube.com/watch?v=zdsBS5BXGqQ>`__)
- `pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyBCN June 2019 <https://www.slideshare.net/AndreuVallbonaPlazas/pybcn-pytest-recomendaciones-paquetes-bsicos-para-testing-en-python-y-django>`_.
- pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyconES 2017 (`slides in english <http://talks.apsl.io/testing-pycones-2017/>`_, `video in spanish <https://www.youtube.com/watch?v=K20GeR-lXDk>`_)
@@ -52,8 +55,6 @@ Talks and blog postings
- `pytest: helps you write better Django apps, Andreas Pelme, DjangoCon
Europe 2014 <https://www.youtube.com/watch?v=aaArYVh6XSM>`_.
- :ref:`fixtures`
- `Testing Django Applications with pytest, Andreas Pelme, EuroPython
2013 <https://www.youtube.com/watch?v=aUf8Fkb7TaY>`_.

View File

@@ -192,8 +192,13 @@ You can override the default temporary directory setting like this:
pytest --basetemp=mydir
When distributing tests on the local machine, ``pytest`` takes care to
configure a basetemp directory for the sub processes such that all temporary
.. warning::
The contents of ``mydir`` will be completely removed, so make sure to use a directory
for that purpose only.
When distributing tests on the local machine using ``pytest-xdist``, care is taken to
automatically configure a basetemp directory for the sub processes such that all temporary
data lands below a single per-test run basetemp directory.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html

View File

@@ -33,7 +33,7 @@ Running ``pytest`` can result in six different exit codes:
:Exit code 4: pytest command line usage error
:Exit code 5: No tests were collected
They are represented by the :class:`_pytest.config.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using:
They are represented by the :class:`pytest.ExitCode` enum. The exit codes being a part of the public API can be imported and accessed directly using:
.. code-block:: python
@@ -57,6 +57,8 @@ Getting help on version, option names, environment variables
pytest -h | --help # show help on command line and config file options
The full command-line flags can be found in the :ref:`reference <command-line-flags>`.
.. _maxfail:
Stopping after the first (or N) failures
@@ -426,14 +428,15 @@ Pytest supports the use of ``breakpoint()`` with the following behaviours:
Profiling test execution duration
-------------------------------------
.. versionchanged:: 6.0
To get a list of the slowest 10 test durations:
To get a list of the slowest 10 test durations over 1.0s long:
.. code-block:: bash
pytest --durations=10
pytest --durations=10 --durations-min=1.0
By default, pytest will not show test durations that are too small (<0.01s) unless ``-vv`` is passed on the command-line.
By default, pytest will not show test durations that are too small (<0.005s) unless ``-vv`` is passed on the command-line.
.. _faulthandler:

View File

@@ -68,16 +68,30 @@ them into errors:
FAILED test_show_warnings.py::test_one - UserWarning: api v1, should use ...
1 failed in 0.12s
The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
For example, the configuration below will ignore all user warnings, but will transform
The same option can be set in the ``pytest.ini`` or ``pyproject.toml`` file using the
``filterwarnings`` ini option. For example, the configuration below will ignore all
user warnings and specific deprecation warnings matching a regex, but will transform
all other warnings into errors.
.. code-block:: ini
# pytest.ini
[pytest]
filterwarnings =
error
ignore::UserWarning
ignore:function ham\(\) is deprecated:DeprecationWarning
.. code-block:: toml
# pyproject.toml
[tool.pytest.ini_options]
filterwarnings = [
"error",
"ignore::UserWarning",
# note the use of single quote below to denote "raw" strings in TOML
'ignore:function ham\(\) is deprecated:DeprecationWarning',
]
When a warning matches more than one option in the list, the action for the last matching option
@@ -353,7 +367,7 @@ warnings, or index into it to get a particular recorded warning.
.. currentmodule:: _pytest.warnings
Full API: :class:`WarningsRecorder`.
Full API: :class:`~_pytest.recwarn.WarningsRecorder`.
.. _custom_failure_messages:

View File

@@ -404,7 +404,7 @@ return a result object, with which we can assert the tests' outcomes.
result.assert_outcomes(passed=4)
additionally it is possible to copy examples for an example folder before running pytest on it
Additionally it is possible to copy examples for an example folder before running pytest on it.
.. code-block:: ini
@@ -614,6 +614,11 @@ among each other.
Declaring new hooks
------------------------
.. note::
This is a quick overview on how to add new hooks and how they work in general, but a more complete
overview can be found in `the pluggy documentation <https://pluggy.readthedocs.io/en/latest/>`__.
.. currentmodule:: _pytest.hookspec
Plugins and ``conftest.py`` files may declare new hooks that can then be
@@ -627,7 +632,7 @@ Hooks are usually declared as do-nothing functions that contain only
documentation describing when the hook will be called and what return values
are expected. The names of the functions must start with `pytest_` otherwise pytest won't recognize them.
Here's an example. Let's assume this code is in the ``hooks.py`` module.
Here's an example. Let's assume this code is in the ``sample_hook.py`` module.
.. code-block:: python
@@ -643,10 +648,10 @@ class or module can then be passed to the ``pluginmanager`` using the ``pytest_a
.. code-block:: python
def pytest_addhooks(pluginmanager):
""" This example assumes the hooks are grouped in the 'hooks' module. """
from my_app.tests import hooks
""" This example assumes the hooks are grouped in the 'sample_hook' module. """
from my_app.tests import sample_hook
pluginmanager.add_hookspecs(hooks)
pluginmanager.add_hookspecs(sample_hook)
For a real world example, see `newhooks.py`_ from `xdist <https://github.com/pytest-dev/pytest-xdist>`_.

View File

@@ -12,7 +12,7 @@ fixtures (setup and teardown test state) on a per-module/class/function basis.
.. note::
While these setup/teardown methods are simple and familiar to those
coming from a ``unittest`` or nose ``background``, you may also consider
coming from a ``unittest`` or ``nose`` background, you may also consider
using pytest's more powerful :ref:`fixture mechanism
<fixture>` which leverages the concept of dependency injection, allowing
for a more modular and more scalable approach for managing test state,

View File

@@ -1,6 +1,6 @@
import json
from pathlib import Path
import py
import requests
issues_url = "https://api.github.com/repos/pytest-dev/pytest/issues"
@@ -31,12 +31,12 @@ def get_issues():
def main(args):
cachefile = py.path.local(args.cache)
cachefile = Path(args.cache)
if not cachefile.exists() or args.refresh:
issues = get_issues()
cachefile.write(json.dumps(issues))
cachefile.write_text(json.dumps(issues), "utf-8")
else:
issues = json.loads(cachefile.read())
issues = json.loads(cachefile.read_text("utf-8"))
open_issues = [x for x in issues if x["state"] == "open"]

View File

@@ -1,16 +1,19 @@
[build-system]
requires = [
# sync with setup.py until we discard non-pep-517/518
"setuptools>=40.0",
"setuptools-scm",
"setuptools>=42.0",
"setuptools-scm[toml]>=3.4",
"wheel",
]
build-backend = "setuptools.build_meta"
[tool.setuptools_scm]
write_to = "src/_pytest/_version.py"
[tool.pytest.ini_options]
minversion = "2.0"
addopts = "-rfEX -p pytester --strict-markers"
python_files = ["test_*.py", "*_test.py", "testing/*/*.py"]
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
python_classes = ["Test", "Acceptance"]
python_functions = ["test"]
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".

View File

@@ -2,8 +2,8 @@
This script is part of the pytest release process which is triggered by comments
in issues.
This script is started by the `release-on-comment.yml` workflow, which is triggered by two comment
related events:
This script is started by the `release-on-comment.yml` workflow, which always executes on
`master` and is triggered by two comment related events:
* https://help.github.com/en/actions/reference/events-that-trigger-workflows#issue-comment-event-issue_comment
* https://help.github.com/en/actions/reference/events-that-trigger-workflows#issues-event-issues
@@ -30,7 +30,7 @@ import argparse
import json
import os
import re
import sys
import traceback
from pathlib import Path
from subprocess import CalledProcessError
from subprocess import check_call
@@ -94,7 +94,6 @@ def print_and_exit(msg) -> None:
def trigger_release(payload_path: Path, token: str) -> None:
error_contents = "" # to be used to store error output in case any command fails
payload, base_branch, is_major = validate_and_get_issue_comment_payload(
payload_path
)
@@ -119,6 +118,7 @@ def trigger_release(payload_path: Path, token: str) -> None:
issue.create_comment(str(e))
print_and_exit(f"{Fore.RED}{e}")
error_contents = ""
try:
print(f"Version: {Fore.CYAN}{version}")
@@ -146,11 +146,12 @@ def trigger_release(payload_path: Path, token: str) -> None:
print(f"Branch {Fore.CYAN}{release_branch}{Fore.RESET} created.")
# important to use tox here because we have changed branches, so dependencies
# might have changed as well
cmdline = ["tox", "-e", "release", "--", version, "--skip-check-links"]
print("Running", " ".join(cmdline))
run(
[sys.executable, "scripts/release.py", version, "--skip-check-links"],
text=True,
check=True,
capture_output=True,
cmdline, text=True, check=True, capture_output=True,
)
oauth_url = f"https://{token}:x-oauth-basic@github.com/{SLUG}.git"
@@ -178,43 +179,31 @@ def trigger_release(payload_path: Path, token: str) -> None:
)
print(f"Notified in original comment {Fore.CYAN}{comment.url}{Fore.RESET}.")
print(f"{Fore.GREEN}Success.")
except CalledProcessError as e:
error_contents = e.output
except Exception as e:
error_contents = str(e)
link = f"https://github.com/{SLUG}/actions/runs/{os.environ['GITHUB_RUN_ID']}"
issue.create_comment(
dedent(
f"""
Sorry, the request to prepare release `{version}` from {base_branch} failed with:
```
{e}
```
See: {link}.
"""
)
)
print_and_exit(f"{Fore.RED}{e}")
error_contents = f"CalledProcessError\noutput:\n{e.output}\nstderr:\n{e.stderr}"
except Exception:
error_contents = f"Exception:\n{traceback.format_exc()}"
if error_contents:
link = f"https://github.com/{SLUG}/actions/runs/{os.environ['GITHUB_RUN_ID']}"
issue.create_comment(
dedent(
f"""
Sorry, the request to prepare release `{version}` from {base_branch} failed with:
```
{error_contents}
```
See: {link}.
"""
)
msg = ERROR_COMMENT.format(
version=version, base_branch=base_branch, contents=error_contents, link=link
)
issue.create_comment(msg)
print_and_exit(f"{Fore.RED}{error_contents}")
else:
print(f"{Fore.GREEN}Success.")
ERROR_COMMENT = """\
The request to prepare release `{version}` from {base_branch} failed with:
```
{contents}
```
See: {link}.
"""
def find_next_version(base_branch: str, is_major: bool) -> str:

View File

@@ -3,23 +3,20 @@ pytest-{version}
The pytest team is proud to announce the {version} release!
pytest is a mature Python testing tool with more than a 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains new features, improvements, bug fixes, and breaking changes, so users
are encouraged to take a look at the CHANGELOG carefully:
This release contains a number of bug fixes and improvements, so users are encouraged
to take a look at the CHANGELOG:
https://docs.pytest.org/en/latest/changelog.html
https://docs.pytest.org/en/stable/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/latest/
https://docs.pytest.org/en/stable/
As usual, you can upgrade from PyPI via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
Thanks to all of the contributors to this release:
{contributors}

View File

@@ -7,9 +7,9 @@ This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all who contributed to this release, among them:
Thanks to all of the contributors to this release:
{contributors}

View File

@@ -1,6 +1,4 @@
"""
Invoke development tasks.
"""
"""Invoke development tasks."""
import argparse
import os
from pathlib import Path

View File

@@ -42,7 +42,6 @@ packages =
install_requires =
attrs>=17.4.0
iniconfig
more-itertools>=4.0.0
packaging
pluggy>=0.12,<1.0
py>=1.8.2
@@ -97,10 +96,13 @@ formats = sdist.tgz,bdist_wheel
[mypy]
mypy_path = src
check_untyped_defs = True
disallow_any_generics = True
ignore_missing_imports = True
no_implicit_optional = True
show_error_codes = True
strict_equality = True
warn_redundant_casts = True
warn_return_any = True
warn_unreachable = True
warn_unused_configs = True
no_implicit_reexport = True

View File

@@ -1,9 +1,4 @@
from setuptools import setup
def main():
setup(use_scm_version={"write_to": "src/_pytest/_version.py"})
if __name__ == "__main__":
main()
setup()

View File

@@ -1,7 +1,8 @@
"""allow bash-completion for argparse with argcomplete if installed
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
"""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.
this does not need special code).
Function try_argcomplete(parser) should be called directly before
the call to ArgumentParser.parse_args().
@@ -10,8 +11,7 @@ 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
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
@@ -20,35 +20,43 @@ attribute points to will not be used).
SPEEDUP
=======
The generic argcomplete script for bash-completion
(/etc/bash_completion.d/python-argcomplete.sh )
(/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
marked with PYTHON_ARGCOMPLETE_OK.
INSTALL/DEBUGGING
=================
To include this support in another application that has setup.py generated
scripts:
- add the line:
- Add the line:
# PYTHON_ARGCOMPLETE_OK
near the top of the main python entry point
- include in the file calling parse_args():
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()
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
- Switch on argcomplete debugging with (also helpful when doing custom
completers):
export _ARC_DEBUG=1
- run:
- 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:
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).
@@ -63,13 +71,13 @@ from typing import Optional
class FastFilesCompleter:
"Fast file completer class"
"""Fast file completer class."""
def __init__(self, directories: bool = True) -> None:
self.directories = directories
def __call__(self, prefix: str, **kwargs: Any) -> List[str]:
"""only called on non option completions"""
# Only called on non option completions.
if os.path.sep in prefix[1:]:
prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
else:
@@ -77,7 +85,7 @@ class FastFilesCompleter:
completion = []
globbed = []
if "*" not in prefix and "?" not in prefix:
# we are on unix, otherwise no bash
# We are on unix, otherwise no bash.
if not prefix or prefix[-1] == os.path.sep:
globbed.extend(glob(prefix + ".*"))
prefix += "*"
@@ -85,7 +93,7 @@ class FastFilesCompleter:
for x in sorted(globbed):
if os.path.isdir(x):
x += "/"
# append stripping the prefix (like bash, not like compgen)
# Append stripping the prefix (like bash, not like compgen).
completion.append(x[prefix_dir:])
return completion

View File

@@ -4,9 +4,9 @@ from .code import ExceptionInfo
from .code import filter_traceback
from .code import Frame
from .code import getfslineno
from .code import getrawcode
from .code import Traceback
from .code import TracebackEntry
from .source import getrawcode
from .source import Source
__all__ = [

View File

@@ -38,9 +38,11 @@ from _pytest._io import TerminalWriter
from _pytest._io.saferepr import safeformat
from _pytest._io.saferepr import saferepr
from _pytest.compat import ATTRS_EQ_FIELD
from _pytest.compat import final
from _pytest.compat import get_real_func
from _pytest.compat import overload
from _pytest.compat import TYPE_CHECKING
from _pytest.pathlib import Path
if TYPE_CHECKING:
from typing import Type
@@ -71,9 +73,8 @@ class Code:
@property
def path(self) -> Union[py.path.local, str]:
"""Return a path object pointing to source code (or a str in case
of OSError / non-existing file).
"""
"""Return a path object pointing to source code, or an ``str`` in
case of ``OSError`` / non-existing file."""
if not self.raw.co_filename:
return ""
try:
@@ -246,10 +247,20 @@ class TracebackEntry:
Mostly for internal use.
"""
f = self.frame
tbh = f.f_locals.get(
"__tracebackhide__", f.f_globals.get("__tracebackhide__", False)
tbh = (
False
) # type: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]]
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
# in normal cases, f_locals and f_globals are dictionaries
# however via `exec(...)` / `eval(...)` they can be other types
# (even incorrect types!).
# as such, we suppress all exceptions while accessing __tracebackhide__
try:
tbh = maybe_ns_dct["__tracebackhide__"]
except Exception:
pass
else:
break
if tbh and callable(tbh):
return tbh(None if self._excinfo is None else self._excinfo())
return tbh
@@ -334,11 +345,11 @@ class Traceback(List[TracebackEntry]):
@overload
def __getitem__(self, key: int) -> TracebackEntry:
raise NotImplementedError()
...
@overload # noqa: F811
def __getitem__(self, key: slice) -> "Traceback": # noqa: F811
raise NotImplementedError()
...
def __getitem__( # noqa: F811
self, key: Union[int, slice]
@@ -404,6 +415,7 @@ co_equal = compile(
_E = TypeVar("_E", bound=BaseException, covariant=True)
@final
@attr.s(repr=False)
class ExceptionInfo(Generic[_E]):
"""Wraps sys.exc_info() objects and offers help for navigating the traceback."""
@@ -420,15 +432,16 @@ class ExceptionInfo(Generic[_E]):
exc_info: Tuple["Type[_E]", "_E", TracebackType],
exprinfo: Optional[str] = None,
) -> "ExceptionInfo[_E]":
"""Returns an ExceptionInfo for an existing exc_info tuple.
"""Return an ExceptionInfo for an existing exc_info tuple.
.. warning::
Experimental API
:param exprinfo: a text string helping to determine if we should
strip ``AssertionError`` from the output, defaults
to the exception message/``__str__()``
:param exprinfo:
A text string helping to determine if we should strip
``AssertionError`` from the output. Defaults to the exception
message/``__str__()``.
"""
_striptext = ""
if exprinfo is None and isinstance(exc_info[1], AssertionError):
@@ -444,15 +457,16 @@ class ExceptionInfo(Generic[_E]):
def from_current(
cls, exprinfo: Optional[str] = None
) -> "ExceptionInfo[BaseException]":
"""Returns an ExceptionInfo matching the current traceback.
"""Return an ExceptionInfo matching the current traceback.
.. warning::
Experimental API
:param exprinfo: a text string helping to determine if we should
strip ``AssertionError`` from the output, defaults
to the exception message/``__str__()``
:param exprinfo:
A text string helping to determine if we should strip
``AssertionError`` from the output. Defaults to the exception
message/``__str__()``.
"""
tup = sys.exc_info()
assert tup[0] is not None, "no current exception"
@@ -467,7 +481,7 @@ class ExceptionInfo(Generic[_E]):
return cls(None)
def fill_unfilled(self, exc_info: Tuple["Type[_E]", _E, TracebackType]) -> None:
"""fill an unfilled ExceptionInfo created with for_later()"""
"""Fill an unfilled ExceptionInfo created with ``for_later()``."""
assert self._excinfo is None, "ExceptionInfo was already filled"
self._excinfo = exc_info
@@ -568,7 +582,8 @@ class ExceptionInfo(Generic[_E]):
Show locals per traceback entry.
Ignored if ``style=="native"``.
:param str style: long|short|no|native|value traceback style
:param str style:
long|short|no|native|value traceback style.
:param bool abspath:
If paths should be changed to absolute or left unchanged.
@@ -583,7 +598,8 @@ class ExceptionInfo(Generic[_E]):
:param bool truncate_locals:
With ``showlocals==True``, make sure locals can be safely represented as strings.
:param bool chain: if chained exceptions in Python 3 should be shown.
:param bool chain:
If chained exceptions in Python 3 should be shown.
.. versionchanged:: 3.9
@@ -610,7 +626,7 @@ class ExceptionInfo(Generic[_E]):
)
return fmt.repr_excinfo(self)
def match(self, regexp: "Union[str, Pattern]") -> "Literal[True]":
def match(self, regexp: "Union[str, Pattern[str]]") -> "Literal[True]":
"""Check whether the regular expression `regexp` matches the string
representation of the exception using :func:`python:re.search`.
@@ -643,7 +659,7 @@ class FormattedExcinfo:
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
def _getindent(self, source: "Source") -> int:
# figure out indent for given source
# Figure out indent for the given source.
try:
s = str(source.getstatement(len(source) - 1))
except KeyboardInterrupt:
@@ -673,9 +689,9 @@ class FormattedExcinfo:
def get_source(
self,
source: "Source",
source: Optional["Source"],
line_index: int = -1,
excinfo: Optional[ExceptionInfo] = None,
excinfo: Optional[ExceptionInfo[BaseException]] = None,
short: bool = False,
) -> List[str]:
"""Return formatted and marked up source lines."""
@@ -700,11 +716,14 @@ class FormattedExcinfo:
return lines
def get_exconly(
self, excinfo: ExceptionInfo, indent: int = 4, markall: bool = False
self,
excinfo: ExceptionInfo[BaseException],
indent: int = 4,
markall: bool = False,
) -> List[str]:
lines = []
indentstr = " " * indent
# get the real exception information out
# Get the real exception information out.
exlines = excinfo.exconly(tryshort=True).split("\n")
failindent = self.fail_marker + indentstr[1:]
for line in exlines:
@@ -730,8 +749,7 @@ class FormattedExcinfo:
str_repr = saferepr(value)
else:
str_repr = safeformat(value)
# if len(str_repr) < 70 or not isinstance(value,
# (list, tuple, dict)):
# if len(str_repr) < 70 or not isinstance(value, (list, tuple, dict)):
lines.append("{:<10} = {}".format(name, str_repr))
# else:
# self._line("%-10s =\\" % (name,))
@@ -741,7 +759,9 @@ class FormattedExcinfo:
return None
def repr_traceback_entry(
self, entry: TracebackEntry, excinfo: Optional[ExceptionInfo] = None
self,
entry: TracebackEntry,
excinfo: Optional[ExceptionInfo[BaseException]] = None,
) -> "ReprEntry":
lines = [] # type: List[str]
style = entry._repr_style if entry._repr_style is not None else self.style
@@ -783,7 +803,7 @@ class FormattedExcinfo:
path = np
return path
def repr_traceback(self, excinfo: ExceptionInfo) -> "ReprTraceback":
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback":
traceback = excinfo.traceback
if self.tbfilter:
traceback = traceback.filter()
@@ -809,16 +829,17 @@ class FormattedExcinfo:
def _truncate_recursive_traceback(
self, traceback: Traceback
) -> Tuple[Traceback, Optional[str]]:
"""
Truncate the given recursive traceback trying to find the starting point
of the recursion.
"""Truncate the given recursive traceback trying to find the starting
point of the recursion.
The detection is done by going through each traceback entry and finding the
point in which the locals of the frame are equal to the locals of a previous frame (see ``recursionindex()``.
The detection is done by going through each traceback entry and
finding the point in which the locals of the frame are equal to the
locals of a previous frame (see ``recursionindex()``).
Handle the situation where the recursion process might raise an exception (for example
comparing numpy arrays using equality raises a TypeError), in which case we do our best to
warn the user of the error and show a limited traceback.
Handle the situation where the recursion process might raise an
exception (for example comparing numpy arrays using equality raises a
TypeError), in which case we do our best to warn the user of the
error and show a limited traceback.
"""
try:
recursionindex = traceback.recursionindex()
@@ -847,12 +868,14 @@ class FormattedExcinfo:
return traceback, extraline
def repr_excinfo(self, excinfo: ExceptionInfo) -> "ExceptionChainRepr":
def repr_excinfo(
self, excinfo: ExceptionInfo[BaseException]
) -> "ExceptionChainRepr":
repr_chain = (
[]
) # type: List[Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]]]
e = excinfo.value
excinfo_ = excinfo # type: Optional[ExceptionInfo]
e = excinfo.value # type: Optional[BaseException]
excinfo_ = excinfo # type: Optional[ExceptionInfo[BaseException]]
descr = None
seen = set() # type: Set[int]
while e is not None and id(e) not in seen:
@@ -863,8 +886,8 @@ class FormattedExcinfo:
excinfo_._getreprcrash() if self.style != "value" else None
) # type: Optional[ReprFileLocation]
else:
# fallback to native repr if the exception doesn't have a traceback:
# ExceptionInfo objects require a full traceback to work
# Fallback to native repr if the exception doesn't have a traceback:
# ExceptionInfo objects require a full traceback to work.
reprtraceback = ReprTracebackNative(
traceback.format_exception(type(e), e, None)
)
@@ -915,7 +938,7 @@ class TerminalRepr:
# This class is abstract -- only subclasses are instantiated.
@attr.s(**{ATTRS_EQ_FIELD: False}) # type: ignore
class ExceptionRepr(TerminalRepr):
# Provided by in subclasses.
# Provided by subclasses.
reprcrash = None # type: Optional[ReprFileLocation]
reprtraceback = None # type: ReprTraceback
@@ -942,7 +965,7 @@ class ExceptionChainRepr(ExceptionRepr):
def __attrs_post_init__(self) -> None:
super().__attrs_post_init__()
# reprcrash and reprtraceback of the outermost (the newest) exception
# in the chain
# in the chain.
self.reprtraceback = self.chain[-1][0]
self.reprcrash = self.chain[-1][1]
@@ -974,7 +997,7 @@ class ReprTraceback(TerminalRepr):
entrysep = "_ "
def toterminal(self, tw: TerminalWriter) -> None:
# the entries might have different styles
# The entries might have different styles.
for i, entry in enumerate(self.reprentries):
if entry.style == "long":
tw.line("")
@@ -1017,7 +1040,7 @@ class ReprEntry(TerminalRepr):
style = attr.ib(type="_TracebackStyle")
def _write_entry_lines(self, tw: TerminalWriter) -> None:
"""Writes the source code portions of a list of traceback entries with syntax highlighting.
"""Write the source code portions of a list of traceback entries with syntax highlighting.
Usually entries are lines like these:
@@ -1038,25 +1061,21 @@ class ReprEntry(TerminalRepr):
# such as "> assert 0"
fail_marker = "{} ".format(FormattedExcinfo.fail_marker)
indent_size = len(fail_marker)
indents = []
source_lines = []
failure_lines = []
seeing_failures = False
for line in self.lines:
is_source_line = not line.startswith(fail_marker)
if is_source_line:
assert not seeing_failures, (
"Unexpected failure lines between source lines:\n"
+ "\n".join(self.lines)
)
indents = [] # type: List[str]
source_lines = [] # type: List[str]
failure_lines = [] # type: List[str]
for index, line in enumerate(self.lines):
is_failure_line = line.startswith(fail_marker)
if is_failure_line:
# from this point on all lines are considered part of the failure
failure_lines.extend(self.lines[index:])
break
else:
if self.style == "value":
source_lines.append(line)
else:
indents.append(line[:indent_size])
source_lines.append(line[indent_size:])
else:
seeing_failures = True
failure_lines.append(line)
tw._write_source(source_lines, indents)
@@ -1099,8 +1118,8 @@ class ReprFileLocation(TerminalRepr):
message = attr.ib(type=str)
def toterminal(self, tw: TerminalWriter) -> None:
# filename and lineno output for each entry,
# using an output format that most editors understand
# Filename and lineno output for each entry, using an output format
# that most editors understand.
msg = self.message
i = msg.find("\n")
if i != -1:
@@ -1175,17 +1194,17 @@ def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]:
return code.path, code.firstlineno
# relative paths that we use to filter traceback entries from appearing to the user;
# see filter_traceback
# Relative paths that we use to filter traceback entries from appearing to the user;
# see filter_traceback.
# note: if we need to add more paths than what we have now we should probably use a list
# for better maintenance
# for better maintenance.
_PLUGGY_DIR = py.path.local(pluggy.__file__.rstrip("oc"))
_PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc"))
# pluggy is either a package or a single module depending on the version
if _PLUGGY_DIR.basename == "__init__.py":
_PLUGGY_DIR = _PLUGGY_DIR.dirpath()
_PYTEST_DIR = py.path.local(_pytest.__file__).dirpath()
_PY_DIR = py.path.local(py.__file__).dirpath()
if _PLUGGY_DIR.name == "__init__.py":
_PLUGGY_DIR = _PLUGGY_DIR.parent
_PYTEST_DIR = Path(_pytest.__file__).parent
_PY_DIR = Path(py.__file__).parent
def filter_traceback(entry: TracebackEntry) -> bool:
@@ -1197,15 +1216,23 @@ def filter_traceback(entry: TracebackEntry) -> bool:
* internal traceback from pytest or its internal libraries, py and pluggy.
"""
# entry.path might sometimes return a str object when the entry
# points to dynamically generated code
# see https://bitbucket.org/pytest-dev/py/issues/71
# points to dynamically generated code.
# See https://bitbucket.org/pytest-dev/py/issues/71.
raw_filename = entry.frame.code.raw.co_filename
is_generated = "<" in raw_filename and ">" in raw_filename
if is_generated:
return False
# entry.path might point to a non-existing file, in which case it will
# also return a str object. see #1133
p = py.path.local(entry.path)
return (
not p.relto(_PLUGGY_DIR) and not p.relto(_PYTEST_DIR) and not p.relto(_PY_DIR)
)
# also return a str object. See #1133.
p = Path(entry.path)
parents = p.parents
if _PLUGGY_DIR in parents:
return False
if _PYTEST_DIR in parents:
return False
if _PY_DIR in parents:
return False
return True

View File

@@ -44,11 +44,11 @@ class Source:
@overload
def __getitem__(self, key: int) -> str:
raise NotImplementedError()
...
@overload # noqa: F811
def __getitem__(self, key: slice) -> "Source": # noqa: F811
raise NotImplementedError()
...
def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: # noqa: F811
if isinstance(key, int):
@@ -67,9 +67,7 @@ class Source:
return len(self.lines)
def strip(self) -> "Source":
""" return new source object with trailing
and leading blank lines removed.
"""
"""Return new Source object with trailing and leading blank lines removed."""
start, end = 0, len(self)
while start < end and not self.lines[start].strip():
start += 1
@@ -80,31 +78,28 @@ class Source:
return source
def indent(self, indent: str = " " * 4) -> "Source":
""" return a copy of the source object with
all lines indented by the given indent-string.
"""
"""Return a copy of the source object with all lines indented by the
given indent-string."""
newsource = Source()
newsource.lines = [(indent + line) for line in self.lines]
return newsource
def getstatement(self, lineno: int) -> "Source":
""" return Source statement which contains the
given linenumber (counted from 0).
"""
"""Return Source statement which contains the given linenumber
(counted from 0)."""
start, end = self.getstatementrange(lineno)
return self[start:end]
def getstatementrange(self, lineno: int) -> Tuple[int, int]:
""" return (start, end) tuple which spans the minimal
statement region which containing the given lineno.
"""
"""Return (start, end) tuple which spans the minimal statement region
which containing the given lineno."""
if not (0 <= lineno < len(self)):
raise IndexError("lineno out of range")
ast, start, end = getstatementrange_ast(lineno, self)
return start, end
def deindent(self) -> "Source":
"""return a new source object deindented."""
"""Return a new Source object deindented."""
newsource = Source()
newsource.lines[:] = deindent(self.lines)
return newsource
@@ -129,7 +124,7 @@ def findsource(obj) -> Tuple[Optional[Source], int]:
def getrawcode(obj, trycall: bool = True):
""" return code object for given function. """
"""Return code object for given function."""
try:
return obj.__code__
except AttributeError:
@@ -148,8 +143,8 @@ def deindent(lines: Iterable[str]) -> List[str]:
def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]:
# flatten all statements and except handlers into one lineno-list
# AST's line numbers start indexing at 1
# Flatten all statements and except handlers into one lineno-list.
# AST's line numbers start indexing at 1.
values = [] # type: List[int]
for x in ast.walk(node):
if isinstance(x, (ast.stmt, ast.ExceptHandler)):
@@ -157,7 +152,7 @@ def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[i
for name in ("finalbody", "orelse"):
val = getattr(x, name, None) # type: Optional[List[ast.stmt]]
if val:
# treat the finally/orelse part as its own statement
# Treat the finally/orelse part as its own statement.
values.append(val[0].lineno - 1 - 1)
values.sort()
insert_index = bisect_right(values, lineno)
@@ -178,13 +173,13 @@ def getstatementrange_ast(
if astnode is None:
content = str(source)
# See #4260:
# don't produce duplicate warnings when compiling source to find ast
# Don't produce duplicate warnings when compiling source to find AST.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
astnode = ast.parse(content, "source", "exec")
start, end = get_statement_startend2(lineno, astnode)
# we need to correct the end:
# We need to correct the end:
# - ast-parsing strips comments
# - there might be empty lines
# - we might have lesser indented code blocks at the end
@@ -192,10 +187,10 @@ def getstatementrange_ast(
end = len(source.lines)
if end > start + 1:
# make sure we don't span differently indented code blocks
# by using the BlockFinder helper used which inspect.getsource() uses itself
# Make sure we don't span differently indented code blocks
# by using the BlockFinder helper used which inspect.getsource() uses itself.
block_finder = inspect.BlockFinder()
# if we start with an indented line, put blockfinder to "started" mode
# If we start with an indented line, put blockfinder to "started" mode.
block_finder.started = source.lines[start][0].isspace()
it = ((x + "\n") for x in source.lines[start:end])
try:
@@ -206,7 +201,7 @@ def getstatementrange_ast(
except Exception:
pass
# the end might still point to a comment or empty line, correct it
# The end might still point to a comment or empty line, correct it.
while end:
line = source.lines[end - 1].lstrip()
if line.startswith("#") or not line:

View File

@@ -36,9 +36,8 @@ def _ellipsize(s: str, maxsize: int) -> str:
class SafeRepr(reprlib.Repr):
"""subclass of repr.Repr that limits the resulting size of repr()
and includes information on exceptions raised during the call.
"""
"""repr.Repr that limits the resulting size of repr() and includes
information on exceptions raised during the call."""
def __init__(self, maxsize: int) -> None:
super().__init__()
@@ -65,7 +64,8 @@ class SafeRepr(reprlib.Repr):
def safeformat(obj: object) -> str:
"""return a pretty printed string for the given object.
"""Return a pretty printed string for the given object.
Failing __repr__ functions of user instances will be represented
with a short exception info.
"""
@@ -76,11 +76,14 @@ def safeformat(obj: object) -> str:
def saferepr(obj: object, maxsize: int = 240) -> str:
"""return a size-limited safe repr-string for the given object.
"""Return a size-limited safe repr-string for the given object.
Failing __repr__ functions of user instances will be represented
with a short exception info and 'saferepr' generally takes
care to never raise exceptions itself. This function is a wrapper
around the Repr/reprlib functionality of the standard 2.6 lib.
care to never raise exceptions itself.
This function is a wrapper around the Repr/reprlib functionality of the
standard 2.6 lib.
"""
return SafeRepr(maxsize).repr(obj)

View File

@@ -7,6 +7,7 @@ from typing import Sequence
from typing import TextIO
from .wcwidth import wcswidth
from _pytest.compat import final
# This code was initially copied from py 1.8.1, file _io/terminalwriter.py.
@@ -36,6 +37,7 @@ def should_do_markup(file: TextIO) -> bool:
)
@final
class TerminalWriter:
_esctable = dict(
black=30,
@@ -111,13 +113,13 @@ class TerminalWriter:
) -> None:
if fullwidth is None:
fullwidth = self.fullwidth
# the goal is to have the line be as long as possible
# under the condition that len(line) <= fullwidth
# The goal is to have the line be as long as possible
# under the condition that len(line) <= fullwidth.
if sys.platform == "win32":
# if we print in the last column on windows we are on a
# If we print in the last column on windows we are on a
# new line but there is no way to verify/neutralize this
# (we may not know the exact line width)
# so let's be defensive to avoid empty lines in the output
# (we may not know the exact line width).
# So let's be defensive to avoid empty lines in the output.
fullwidth -= 1
if title is not None:
# we want 2 + 2*len(fill) + len(title) <= fullwidth
@@ -131,9 +133,9 @@ class TerminalWriter:
# we want len(sepchar)*N <= fullwidth
# i.e. N <= fullwidth // len(sepchar)
line = sepchar * (fullwidth // len(sepchar))
# in some situations there is room for an extra sepchar at the right,
# In some situations there is room for an extra sepchar at the right,
# in particular if we consider that with a sepchar like "_ " the
# trailing space is not important at the end of the line
# trailing space is not important at the end of the line.
if len(line) + len(sepchar.rstrip()) <= fullwidth:
line += sepchar.rstrip()

View File

@@ -1,6 +1,4 @@
"""
support for presenting detailed information in failing assertions.
"""
"""Support for presenting detailed information in failing assertions."""
import sys
from typing import Any
from typing import Generator
@@ -55,11 +53,11 @@ def register_assert_rewrite(*names: str) -> None:
actually imported, usually in your __init__.py if you are a plugin
using a package.
:raise TypeError: if the given module names are not strings.
:raises TypeError: If the given module names are not strings.
"""
for name in names:
if not isinstance(name, str):
msg = "expected module names as *args, got {0} instead"
msg = "expected module names as *args, got {0} instead" # type: ignore[unreachable]
raise TypeError(msg.format(repr(names)))
for hook in sys.meta_path:
if isinstance(hook, rewrite.AssertionRewritingHook):
@@ -105,9 +103,9 @@ def install_importhook(config: Config) -> rewrite.AssertionRewritingHook:
def pytest_collection(session: "Session") -> None:
# this hook is only called when test modules are collected
# This hook is only called when test modules are collected
# so for example not in the master process of pytest-xdist
# (which does not collect test modules)
# (which does not collect test modules).
assertstate = session.config._store.get(assertstate_key, None)
if assertstate:
if assertstate.hook is not None:
@@ -116,18 +114,17 @@ def pytest_collection(session: "Session") -> None:
@hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]:
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks.
The rewrite module will use util._reprcompare if
it exists to use custom reporting via the
pytest_assertrepr_compare hook. This sets up this custom
The rewrite module 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.
"""
ihook = item.ihook
def callbinrepr(op, left: object, right: object) -> Optional[str]:
"""Call the pytest_assertrepr_compare hook and prepare the result
"""Call the pytest_assertrepr_compare hook and prepare the result.
This uses the first result from the hook and then ensures the
following:

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