Added a new :class:`pytest.Directory` base collection node, which all collector nodes for filesystem directories are expected to subclass. This is analogous to the existing :class:`pytest.File` for file nodes.
Changed :class:`pytest.Package` to be a subclass of :class:`pytest.Directory`.
A Package
represents a filesystem directory which is a Python package,
i.e. contains an __init__.py
file.
:class:`pytest.Package` now only collects files in its own directory; previously it collected recursively. Sub-directories are collected as sub-collector nodes, thus creating a collection tree which mirrors the filesystem hierarchy.
Added a new :class:`pytest.Dir` concrete collection node, a subclass of :class:`pytest.Directory`.
This node represents a filesystem directory, which is not a :class:`pytest.Package`,
i.e. does not contain an __init__.py
file.
Similarly to Package
, it only collects the files in its own directory,
while collecting sub-directories as sub-collector nodes.
Added a new hook 🪝`pytest_collect_directory`, which is called by filesystem-traversing collector nodes, such as :class:`pytest.Session`, :class:`pytest.Dir` and :class:`pytest.Package`, to create a collector node for a sub-directory. It is expected to return a subclass of :class:`pytest.Directory`. This hook allows plugins to :ref:`customize the collection of directories <custom directory collectors>`.
:class:`pytest.Session` now only collects the initial arguments, without recursing into directories. This work is now done by the :func:`recursive expansion process <pytest.Collector.collect>` of directory collector nodes.
:attr:`session.name <pytest.Session.name>` is now ""
; previously it was the rootdir directory name.
This matches :attr:`session.nodeid <_pytest.nodes.Node.nodeid>` which has always been "".
Files and directories are now collected in alphabetical order jointly, unless changed by a plugin. Previously, files were collected before directories.
The collection tree now contains directories/packages up to the :ref:`rootdir <rootdir>`, for initial arguments that are found within the rootdir. For files outside the rootdir, only the immediate directory/package is collected (this is discouraged).
As an example, given the following filesystem tree:
myroot/ pytest.ini top/ ├── aaa │ └── test_aaa.py ├── test_a.py ├── test_b │ ├── __init__.py │ └── test_b.py ├── test_c.py └── zzz ├── __init__.py └── test_zzz.py
the collection tree, as shown by pytest --collect-only top/ but with the otherwise-hidden :class:`~pytest.Session` node added for clarity, is now the following:
<Session> <Dir myroot> <Dir top> <Dir aaa> <Module test_aaa.py> <Function test_it> <Module test_a.py> <Function test_it> <Package test_b> <Module test_b.py> <Function test_it> <Module test_c.py> <Function test_it> <Package zzz> <Module test_zzz.py> <Function test_it>
Previously, it was:
<Session> <Module top/test_a.py> <Function test_it> <Module top/test_c.py> <Function test_it> <Module top/aaa/test_aaa.py> <Function test_it> <Package test_b> <Module test_b.py> <Function test_it> <Package zzz> <Module test_zzz.py> <Function test_it>