Skip to content

doc: more docs for from_parent #6680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions doc/en/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Below is a complete list of all pytest features which are considered deprecated.
Option ``--no-print-logs`` is deprecated and meant to be removed in a future release. If you use ``--no-print-logs``, please try out ``--show-capture`` and
provide feedback.

``--show-capture`` command-line option was added in ``pytest 3.5.0` and allows to specify how to
``--show-capture`` command-line option was added in ``pytest 3.5.0`` and allows to specify how to
display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).


Expand All @@ -39,9 +39,28 @@ Node Construction changed to ``Node.from_parent``

.. deprecated:: 5.4

The construction of nodes new should use the named constructor ``from_parent``.
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit strange to me... how are users supposed to write their constructors?

class MyItem(Node):

    def __init__(self, parent, name):
        super().__init__(parent=parent, name=name)
        self.obj = None


# constructed like this:
item = MyItem.from_parent(collector, name="foo")
item.obj = 42

Or are they supposed to override from_parent?

class MyItem(Node):

    def __init__(self, parent, name, obj):
        super().__init__(parent=parent, name=name)
        self.obj = obj

    @classmethod
    def from_parent(cls, parent, name, obj):
        return super().from_parent(parent=parent, name=name, obj=obj) 

# constructed like this:
item = MyItem.from_parent(collector, name="foo", obj=42)

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for initially users will have to override both, we will eventually migrate to a model where they only override from_parent

Copy link
Member

@nicoddemus nicoddemus Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for initially users will have to override both

So I assume you mean the latter sample, right?

we will eventually migrate to a model where they only override from_parent

But how is that possible (to only override from_parent)? Users still need to define their attributes somewhere.

How to you see this playing out in the future?

Also why users even need to implement from_parent at all, given that the framework doesn't call that function? Seems weird to have as prerequisite to override __init__ (which is usually OK in frameworks) and then from_parent, which pytest won't call at all: the user is responsible for creating nodes on the impl of the appropriate hooks (pytest_pycollect_makeitem).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update the suggestion to go for attr.s directly, and implementing their own from_parent class?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, I realize this won't work with attr.s because of the superclass relationship.

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.



``junit_family`` default value change to "xunit2"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
5 changes: 4 additions & 1 deletion src/_pytest/deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@

NODE_USE_FROM_PARENT = UnformattedWarning(
PytestDeprecationWarning,
"direct construction of {name} has been deprecated, please use {name}.from_parent",
"Direct construction of {name} has been deprecated, please use {name}.from_parent.\n"
"See "
"https://docs.pytest.org/en/latest/deprecations.html#node-construction-changed-to-node-from-parent"
" for more details.",
)

JUNIT_XML_DEFAULT_FAMILY = PytestDeprecationWarning(
Expand Down
2 changes: 1 addition & 1 deletion testing/deprecated_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class MockConfig:
ms = MockConfig()
with pytest.warns(
DeprecationWarning,
match="direct construction of .* has been deprecated, please use .*.from_parent",
match="Direct construction of .* has been deprecated, please use .*.from_parent.*",
) as w:
nodes.Node(name="test", config=ms, session=ms, nodeid="None")
assert w[0].lineno == inspect.currentframe().f_lineno - 1
Expand Down