Commit Graph

255 Commits

Author SHA1 Message Date
Ronny Pfannschmidt a550db4b6c drop internal py.path.local objects from hook calls 2021-03-20 21:50:40 +01:00
Ran Benita e515264eb1 Remove yet more unnecessary py.path uses 2021-03-18 10:23:48 +02:00
Ran Benita f0c7043138 Remove/replace some more unnecessary uses of py.path 2021-03-15 10:39:44 +02:00
Ronny Pfannschmidt 77cb110258 drop usage of py.path.local calls
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2021-03-06 21:32:03 +01:00
Ronny Pfannschmidt 22dad53a24 implement Node.path as pathlib.Path
* reorganize lastfailed node sort

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2021-03-06 21:32:03 +01:00
Alexandros Tzannes 19a2f7425d
Merge pull request #8399 from atzannes/master
closes #8394

Generated fixture names for unittest/xunit/nose should start with underscore
2021-03-04 22:45:57 +02:00
Simon K 22c0dace3b
change istestfunction to callable() (#8374) 2021-02-25 20:32:27 +00:00
Florian Bruhin 54a154c86f Allow Class.from_parent to forward custom parameters to the constructor
Similarly to #7143, at work we have a project with a custom pytest.Class
subclass, adding an additional argument to the constructor.

All from_parent implementations in pytest accept and forward *kw, except
Class (before this change) and DoctestItem - since I'm not familiar with
doctest support, I've left the latter as-is.
2021-02-23 18:00:56 +01:00
Ronny Pfannschmidt 325d701f6e
Merge pull request #8248 from RonnyPfannschmidt/mixin-mro-position
alter the PyObjMixin to carry over typing information from Node
2021-02-07 18:44:44 +01:00
Ran Benita afea190797 Remove some no longer needed type-ignores 2021-01-29 20:40:43 +02:00
Ronny Pfannschmidt a9e43152bc alter the PyObjMixin to carry over typing information from Node
as PyObjMixin is always supposed to be mixed in the mro
before nodes.Node the behavior doesn't change,
but all the typing information carry over to help mypy.

extracted from #8037
2021-01-17 14:36:28 +01:00
Ran Benita 2ff88098a7 python: inline a simple method
I don't think it adds much value!
2021-01-01 23:23:08 +02:00
pre-commit-ci[bot] ee03e31831
[pre-commit.ci] pre-commit autoupdate (#8201)
* [pre-commit.ci] pre-commit autoupdate

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* manual fixes after configuration update

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Anthony Sottile <asottile@umich.edu>
2020-12-30 11:56:09 +02:00
Ran Benita bd76042344 python: export pytest.Metafunc for typing purposes
The type cannot be constructed directly, but is exported for use in type
annotations, since it is reachable through existing public API.
2020-12-26 21:05:02 +02:00
Ran Benita ca4effc822 Convert most of the collection code from py.path to pathlib 2020-12-22 21:09:36 +02:00
Ran Benita 92ba96b061 code: convert from py.path to pathlib 2020-12-22 21:08:25 +02:00
antonblr 196b173c8a address comments 2020-12-18 12:36:20 -08:00
antonblr 15156e94c4 tests: Migrate to pytester - final update 2020-12-18 11:02:38 -08:00
Ran Benita 592b32bd69 hookspec: add pathlib.Path alternatives to py.path.local parameters in hooks
As part of the ongoing migration for py.path to pathlib, make sure all
hooks which take a py.path.local also take an equivalent pathlib.Path.
2020-12-15 00:34:23 +02:00
Ran Benita ed658d6829 Some py.path.local -> pathlib.Path
- Some conftest related functions
- _confcutdir
- Allow arbitrary os.PathLike[str] in gethookproxy.
2020-12-12 17:33:28 +02:00
Ran Benita f1e6fdcddb Export types of builtin fixture for type annotations
In order to allow users to type annotate fixtures they request, the
types need to be imported from the `pytest` namespace. They are/were
always available to import from the `_pytest` namespace, but that is
not guaranteed to be stable.

These types are only exported for the purpose of typing. Specifically,
the following are *not* public:

- Construction (`__init__`)
- Subclassing
- staticmethods and classmethods

We try to combat them being used anyway by:

- Marking the classes as `@final` when possible (already done).

- Not documenting private stuff in the API Reference.

- Using `_`-prefixed names or marking as `:meta private:` for private
  stuff.

- Adding a keyword-only `_ispytest=False` to private constructors,
  warning if False, and changing pytest itself to pass True. In the
  future it will (hopefully) become a hard error.

Hopefully that will be enough.
2020-11-13 11:25:09 +02:00
Ran Benita a95da7a425
Merge pull request #7980 from bluetech/code-changes
code: a few minor improvements
2020-11-01 09:51:39 +02:00
Bruno Oliveira 569c091769 Add FunctionDefinition to the reference docs
Fix #7968
2020-10-31 08:45:34 -03:00
Ran Benita 531416cc5a code: simplify Code construction 2020-10-31 12:40:25 +02:00
Ran Benita 50114d4731 python: fix quadratic behavior in collection of items using xunit fixtures
Since commit 0f918b1a9d pytest uses auto-generated autouse
pytest fixtures for the xunit fixtures
{setup,teardown}_{module,class,method,function}. All of these fixtures
were given the same name.

Unfortunately, pytest fixture lookup for a name works by grabbing all of
the fixtures globally declared with a name and filtering to only those
which match the specific node. So each xunit-using item iterates over a
list (of fixturedefs) of a size of all previous same-xunit-using items,
i.e. quadratic.

Fixing this properly to use a better data structure is likely to take
some effort, but we can avoid the immediate problem by just using
a different name for each item's autouse fixture, so it only matches
itself.

A benchmark is added to demonstrate the issue. It is still way too slow
after the fix and possibly still quadratic, but for a different reason
which is another matter.

Running --collect-only, before (snipped):

         202533232 function calls (201902604 primitive calls) in 86.379 seconds

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   85.688   85.688 main.py:320(pytest_collection)
        1    0.000    0.000   85.688   85.688 main.py:567(perform_collect)
80557/556    0.021    0.000   85.050    0.153 {method 'extend' of 'list' objects}
85001/15001  0.166    0.000   85.045    0.006 main.py:785(genitems)
    10002    0.050    0.000   84.219    0.008 runner.py:455(collect_one_node)
    10002    0.049    0.000   83.763    0.008 runner.py:340(pytest_make_collect_report)
    10002    0.079    0.000   83.668    0.008 runner.py:298(from_call)
    10002    0.019    0.000   83.541    0.008 runner.py:341(<lambda>)
     5001    0.184    0.000   81.922    0.016 python.py:412(collect)
     5000    0.020    0.000   81.072    0.016 python.py:842(collect)
    30003    0.118    0.000   78.478    0.003 python.py:218(pytest_pycollect_makeitem)
    30000    0.190    0.000   77.957    0.003 python.py:450(_genfunctions)
    40001    0.081    0.000   76.664    0.002 nodes.py:183(from_parent)
    30000    0.087    0.000   76.629    0.003 python.py:1595(from_parent)
    40002    0.092    0.000   76.583    0.002 nodes.py:102(_create)
    30000    0.305    0.000   76.404    0.003 python.py:1533(__init__)
    15000    0.132    0.000   74.765    0.005 fixtures.py:1439(getfixtureinfo)
    15000    0.165    0.000   73.664    0.005 fixtures.py:1492(getfixtureclosure)
    15000    0.044    0.000   57.584    0.004 fixtures.py:1653(getfixturedefs)
    30000   18.840    0.001   57.540    0.002 fixtures.py:1668(_matchfactories)
 37507500   31.352    0.000   38.700    0.000 nodes.py:76(ischildnode)
    15000   10.464    0.001   15.806    0.001 fixtures.py:1479(_getautousenames)
112930587/112910019   7.333    0.000    7.339    0.000 {built-in method builtins.len}

After:

         51890333 function calls (51259706 primitive calls) in 27.306 seconds

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   26.783   26.783 main.py:320(pytest_collection)
        1    0.000    0.000   26.783   26.783 main.py:567(perform_collect)
80557/556    0.020    0.000   26.108    0.047 {method 'extend' of 'list' objects}
85001/15001  0.151    0.000   26.103    0.002 main.py:785(genitems)
    10002    0.047    0.000   25.324    0.003 runner.py:455(collect_one_node)
    10002    0.045    0.000   24.888    0.002 runner.py:340(pytest_make_collect_report)
    10002    0.069    0.000   24.805    0.002 runner.py:298(from_call)
    10002    0.017    0.000   24.690    0.002 runner.py:341(<lambda>)
     5001    0.168    0.000   23.150    0.005 python.py:412(collect)
     5000    0.019    0.000   22.223    0.004 python.py:858(collect)
    30003    0.101    0.000   19.818    0.001 python.py:218(pytest_pycollect_makeitem)
    30000    0.161    0.000   19.368    0.001 python.py:450(_genfunctions)
    30000    0.302    0.000   18.236    0.001 python.py:1611(from_parent)
    40001    0.084    0.000   18.051    0.000 nodes.py:183(from_parent)
    40002    0.116    0.000   17.967    0.000 nodes.py:102(_create)
    30000    0.308    0.000   17.770    0.001 python.py:1549(__init__)
    15000    0.117    0.000   16.111    0.001 fixtures.py:1439(getfixtureinfo)
    15000    0.134    0.000   15.135    0.001 fixtures.py:1492(getfixtureclosure)
    15000    9.320    0.001   14.738    0.001 fixtures.py:1479(_getautousenames)
2020-10-23 22:36:23 +03:00
Anthony Sottile 33d119f71a py36+: com2ann 2020-10-05 18:33:17 -07:00
Anthony Sottile 66bd44c13a py36+: pyupgrade: py36+ 2020-10-03 12:46:54 -07:00
Anthony Sottile f295b0267d py36+: update the target version of black to py36 2020-10-03 08:17:22 -07:00
Anthony Sottile bfadd4060e py36+: from typing import Type: no longer need guard 2020-10-02 19:50:10 -07:00
Anthony Sottile 2c7b7d8f66
Merge pull request #7836 from asottile/py36_typing_X
py36+: replace typing.X with X
2020-10-02 19:47:42 -07:00
Anthony Sottile cf220b92a2 py36+: replace typing.X with X 2020-10-02 15:05:13 -07:00
Anthony Sottile a238d1f37d py36+: remove TYPE_CHECKING from _pytest.compat
automated with:

```bash
git grep -l 'from .* import TYPE_CHECKING' |
    xargs reorder-python-imports \
        --application-directories .:src \
        --remove-import 'from _pytest.compat import TYPE_CHECKING' \
        --add-import 'from typing import TYPE_CHECKING'
```
2020-10-02 15:03:24 -07: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
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 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 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
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
Ran Benita c1f975668e main: couple of code simplifications 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
Bruno Oliveira 98530184a5 Remove funcargnames compatibility property 2020-08-19 08:11:39 -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
Ran Benita f8c4e038fd Replace some usages of py.path.local 2020-08-06 18:46:17 +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
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
Ran Benita 0242de4f56 Format docstrings in a consistent style 2020-08-01 17:14:37 +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 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
Ran Benita bc17034a67 Fix typing of params ids callable form
The previous typing had an object passed to the user, which they can't
do anything with without asserting, which is inconvenient. Change it to
Any instead.

Note that what comes *back* to pytest (the return value) should be an
`object`, because we want to handle arbitrary objects without assuming
anything about them.
2020-07-14 14:53:42 +03:00