-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Factor out own_markers into a property
#7052
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
Conversation
This makes it a bit more easier to follow, especially with the removed hack of setting it only based on `_ALLOW_MARKERS` property. This was triggered based on wondering why setting `_obj` directly would not set the marks.
own_markers and keywords into propertiesown_markers into a property
bluetech
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't tried to understand this yet, but some initial comments.
|
|
||
| #: the marker objects belonging to this node | ||
| self.own_markers = [] # type: List[Mark] | ||
| #: The (manually added) marks belonging to this node (start, end). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "start", "end" mean? (=> would be good to explain in the comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bluetech
It keeps two list for prepended/appended marks - with the ones from the object inbetween. This might not be needed really, but is needed for the current behavior (fixing it for changed objs etc though).
Having two separate lists might be good, but also not really needed maybe (given that the single list can be typed "enough" already).
Any suggestions for a better/clearer comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having two separate lists might be good, but also not really needed maybe
Yes, looking a bit more I can see either way.
Any suggestions for a better/clearer comment?
First I think the name _own_markers is a little misleading now: the established meaning of own_markers (which can't be changed due to backward compat) includes the manually-added marks (add_marker()) but also the marks directly applied to the object (@pytest.mark.foo). But after this change, _own_markers only contains the add_marker() ones.
So maybe _manually_added_markers?
As regards to the comment, maybe something like this?
Marks that are manually added to this node with `add_marker()`.
These marks are included in the node's `own_markers`. Marks in the first item are prepended,
and marks in the second item are appended.
|
|
||
| @property | ||
| def own_markers(self) -> List[Mark]: | ||
| """The marker objects belonging to this node.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize the property name can't be changed but why "markers" rather than "marks"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another critical detail i just realized, changing own_markers from a real object to a transient temporal property is breaking api change that breaks users that change own_markers directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would extend the comment here. Suggestion (but please verify what I write!):
The marks directly belonging to this node.
This includes marks manually added with `add_marker()`, and marks directly applied
to the object (using `@pytest.mark.foo` decorations for example). It does not include
marks inherited from parent nodes (for example, a mark applied to a class node is not
included in a method's `own_markers`).
Would also add a note about modifying it, depending on the answer to the next question.
BTW, is there actually any significance to the the order or marks?
changing own_markers from a real object to a transient temporal property is breaking api change
Do you think changing own_markers directly is something that should be supported, or deprecated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is significance to the order of marks in the sense, that they apply in the order they are declared/applied
this is important for details like selection of correct messages/failures
in retrospect i believe exposing own_markers was a mistake, however right now its public and mutable
src/_pytest/python.py
Outdated
|
|
||
|
|
||
| class PyobjMixin: | ||
| class PyobjMixin(nodes.Node): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not a good idea in general -- it makes it look like PyobjMixin is an actual Node.
TBH I'd prefer to get rid of PyobjMixin entirely (and this looks like a positive step towards that), but in my typing branch I solved it like this for now:
bluetech@a34e7ff#diff-88cb3736bed2f144d42f07ccbeb97eb0R280-R291
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not a good idea in general -- it makes it look like
PyobjMixinis an actualNode.
Agreed!
TBH I'd prefer to get rid of
PyobjMixinentirely (and this looks like a positive step towards that), but in my typing branch I solved it like this for now:bluetech@a34e7ff#diff-88cb3736bed2f144d42f07ccbeb97eb0R280-R291
Thanks - took that approach here also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note however that it should be parent: PyobjMixin with PyobjMixin really (since it assumes that parent has obj), which does not work without subclassing Node (Definition of "parent" in base class "PyobjMixin" is incompatible with definition in base class "Node"). And using parent: Optional[Union["Node", "PyobjMixin"]] = None, with Node results in Item "PyobjMixin" of "Union[Node, PyobjMixin]" has no attribute "config" etc.
So I think that subclassing Node here is the best approach for now.
Despite its name it is a base/intermediate class for all "python" nodes/collectors after all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note however that it should be parent: PyobjMixin with PyobjMixin really
I guess such constraints on parent can be added once the from_parent work is completed? For now however I'm not sure they're valid. It's definitely an issue that typing expose.
Despite its name it is a base/intermediate class for all "python" nodes/collectors after all.
Maybe changing it to a common base for all "python" nodes makes sense, I am not sure. One problem with that is that it breaks the clear Item/Collector split, since both types will derive from it. And might confuse MRO/from_parent a lot too...
Anyway, as long as it is a mixin and written as a mixin, IMO it is better not to derive from Node. And we should strive to eliminate it as such :)
RonnyPfannschmidt
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replacing a bad hack planned for drop without coordination with a different thing that looks worse
for stuff like that please coordinate first
The test is not including keywords for now (in the end, #359)
| "session", | ||
| } | ||
|
|
||
| # Changing the "obj" updates marks and keywords (lazily). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"keywords" being updated is not done here yet (but in blueyed#359 already). Could test the current behavior here for now.
|
The refactoring as is, is not acceptable, please pick comprehensible internal names and explain the rationale or drop it |
Before:
Diff Coverage
Diff: eb00182...HEAD, staged and unstaged changes
-------------
src/_pytest/mark/structures.py (0.0%): Missing lines 274
src/_pytest/nodes.py (100%)
src/_pytest/python.py (72.2%): Missing lines 290,301,1518-1520
testing/test_mark.py (61.5%): Missing lines 967,981,984,989,992-993,995,997-1000,1014-1015,1017-1018
-------------
Total: 63 lines
Missing: 21 lines
Coverage: 66%
After:
Diff Coverage
Diff: eb00182...HEAD, staged and unstaged changes
-------------
src/_pytest/mark/structures.py (100%)
src/_pytest/nodes.py (100%)
src/_pytest/python.py (95.7%): Missing lines 1519
testing/test_mark.py (64.1%): Missing lines 967,984,989,992-993,995,997-1000,1014-1015,1017-1018
-------------
Total: 72 lines
Missing: 15 lines
Coverage: 79%
6fe2599 to
4a89494
Compare
|
|
||
| #: the marker objects belonging to this node | ||
| self.own_markers = [] # type: List[Mark] | ||
| #: The (manually added) marks belonging to this node (start, end). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having two separate lists might be good, but also not really needed maybe
Yes, looking a bit more I can see either way.
Any suggestions for a better/clearer comment?
First I think the name _own_markers is a little misleading now: the established meaning of own_markers (which can't be changed due to backward compat) includes the manually-added marks (add_marker()) but also the marks directly applied to the object (@pytest.mark.foo). But after this change, _own_markers only contains the add_marker() ones.
So maybe _manually_added_markers?
As regards to the comment, maybe something like this?
Marks that are manually added to this node with `add_marker()`.
These marks are included in the node's `own_markers`. Marks in the first item are prepended,
and marks in the second item are appended.
|
|
||
| @property | ||
| def own_markers(self) -> List[Mark]: | ||
| """The marker objects belonging to this node.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would extend the comment here. Suggestion (but please verify what I write!):
The marks directly belonging to this node.
This includes marks manually added with `add_marker()`, and marks directly applied
to the object (using `@pytest.mark.foo` decorations for example). It does not include
marks inherited from parent nodes (for example, a mark applied to a class node is not
included in a method's `own_markers`).
Would also add a note about modifying it, depending on the answer to the next question.
BTW, is there actually any significance to the the order or marks?
changing own_markers from a real object to a transient temporal property is breaking api change
Do you think changing own_markers directly is something that should be supported, or deprecated?
| @property | ||
| def own_markers(self) -> List[Mark]: | ||
| if self._obj_markers is None: | ||
| self._obj_markers = get_unpacked_marks(self.obj) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be too expensive to do this eagerly (when obj is set/changed) as opposed to lazily as in here?
|
|
||
| @property | ||
| def own_markers(self) -> List[Mark]: | ||
| # Do not include markers from obj, coming from Class already. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess storing a mark directly on an instance (instance.pytestmark = [...]) is not supported/will be ignored?
|
closing as unresolved |
Follow-up might be to do this for
keywordsalso: blueyed#359