-
Notifications
You must be signed in to change notification settings - Fork 95
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
Extract an interface from TargetRegistry to allow wider testing support for IsEnabled #1490
Conversation
…tion of the interface
That renaming is done now - since the argument type change is a backward incompatible change, we might as well. If the old methods are ever depended on externally (I doubt it), it is easy to put them up again as a quick fix. This PR is now clean to the standard as if this was aiming to be merged. Since (1) this is not a small PR, (2) I probably wouldn't have the bandwidth to follow it through, and (3) I don't want to rush it, I will close this PR later today. I will remove the branch too, but I believe they can be restored later from the PR. Comments are very welcome any time (before or after me closing the PR). |
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.
LGTM
I have a few comments / questions. I apologize for the extremely long delay in my review. @kitchoi if you do not currently have the bandwidth to go through with this PR, I am happy to talk with Rahul about best next steps to take for how we can get this pushed through. I think it will provide a very nice improvement for the UITester
😃, thank you!
) | ||
|
||
|
||
class DynamicTargetRegistry(AbstractTargetRegistry): |
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.
Naming things is hard. I don't necessarily dislike this name, but there are ways I can think about it that make it confusing.
For instance, the register_interaction
and register_location
methods are only defined on TargetRegistry
but not on the abc, or this class.
In that sense, the normal TargetRegistry
is dynamic as the interactions and locations it supports can change throughout the lifetime of the registry instance. This class is more fixed in that sense.
However, as you mention this DynamicTargetRegistry
is "A registry to support targets with dynamic checks." so in that sense the name is appropriate.
Not really a suggested change here, just 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.
Naming things is hard indeed. I see your point, the word "dynamic" could well be used to describe 'TargetRegistry', in a different way. I couldn't think of a better name at the moment. Suggestions welcome!
@@ -288,7 +292,7 @@ def get_location_doc(self, target_class, locator_class): | |||
If the given locator and target types are not supported. | |||
""" | |||
self._location_registry.get_value( | |||
target_class=target_class, | |||
target_class=target.__class__, | |||
key=locator_class, | |||
) | |||
# This maybe configurable in the future via register_location |
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.
😄
These changes all make a lot of sense to me. The only methods we expect users to call are really register_interaction
and register_location
, for which the api has remained unchanged.
Everything else (ie. all the get_*
methods), I agree, are likely to not have been used externally, and really shouldn't be.
It may be slightly confusing (or surprising I guess?) that these other TargetRegistry
methods now typically take a target
itself rather than a target_class
as an argument, but register_interaction
and register_location
still take a target_class
, however I think that is perfectly okay. It makes sense that registering an interaction or location is a general act, that applies to all instances of a particular class.
target_class=target.__class__, | ||
locator_class=locator_class, | ||
supported=[], | ||
) |
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.
Not for this PR, but will we want to add a section to the documentation about DynamicTargetRegsitry
? This is in a privately named module so I assume you were thinking not / we don't expect users to mess with it.
As far as users wanting to extend UITester functionality, I feel like I could imagine scenarios where it would be useful to work with an additional DynamicTargetRegistry
rather than a TargetRegistry
to append to the default registries already provided on a UITester. For example right now, if this went in and say hypothetically we never put in an IsVisible
implementation along with this. A downstream user may want to do something like that?
However, I can also see an argument for this only being used internally, and keeping the means of extending UITester functionality exactly as it is now.
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 I started out keeping this internal, but I am totally open to exposing this publicly if it is useful downstream. With this made public, then we need to think harder about the name...
interaction_class=interaction.__class__, | ||
supported=list(self._get_interactions(target)), | ||
) | ||
return self.interaction_to_handler[interaction.__class__] |
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 understand the switch from target_class
to target
, but does interaction_class
need to be interaction
here (we only use interaction.__class__
? or is that just to be consistent?
e.g. in _get_interaction_doc
we use the interaction_class
I don't think there is any problem with having it be interaction
. Just want to check I am not missing anything
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.
You are right, this was done to be consistent. I should have explained this earlier. Thanks for flagging it.
(For _get_interaction_doc
or get_location_doc
we can't really do instances there because the documentation is associated with the type.)
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.
Thank you @aaronayres35 for the review.
if you do not currently have the bandwidth to go through with this PR, I am happy to talk with Rahul about best next steps to take for how we can get this pushed through.
As much as I'd like to go through with this, I am wary of holding things up because of the lack of bandwidth. Though I do feel a responsibility here. Should I aim at addressing the review comments by the end of next week, and if I fail (not surprising, but I will aim not to), others can take over from then on?
interaction_class=interaction.__class__, | ||
supported=list(self._get_interactions(target)), | ||
) | ||
return self.interaction_to_handler[interaction.__class__] |
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.
You are right, this was done to be consistent. I should have explained this earlier. Thanks for flagging it.
(For _get_interaction_doc
or get_location_doc
we can't really do instances there because the documentation is associated with the type.)
) | ||
|
||
|
||
class DynamicTargetRegistry(AbstractTargetRegistry): |
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.
Naming things is hard indeed. I see your point, the word "dynamic" could well be used to describe 'TargetRegistry', in a different way. I couldn't think of a better name at the moment. Suggestions welcome!
target_class=target.__class__, | ||
locator_class=locator_class, | ||
supported=[], | ||
) |
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 I started out keeping this internal, but I am totally open to exposing this publicly if it is useful downstream. With this made public, then we need to think harder about the name...
That sounds perfectly reasonable to me. Again, if you don't have the bandwidth, don't worry about it at all. I am more than happy to take up this PR / work with Rahul to get it pushed through |
@aaronayres35 I hope I have addressed all the comments. I have also updated the class docstring of |
Still LGTM, thank you for the detailed doc strings - they are very helpful!
That makes sense, I agree |
Thank you. |
This
is a draftPRtoshows implementations and API thatwouldsolve #1418.Narrow goal:
IsEnabled
check on any QWidget or wx.WindowWider goal:
Changes:
get_*
methods on the currentTargetRegistry
are extracted to an interface,AbstractTargetRegistry
. Any objects that implement the interface can be a registry given toUIWrapper
.get_*
methods that used to require the type ofUIWrapper._target
is now changed to just an instance. While this adds requirements on the information required by a registry,UIWrapper._target
is always an instance so that information is almost always available.DynamicTargetRegistry
is added. Both the existingTargetRegistry
and the newDynamicTargetRegistry
implement the interface.UITester
now extends the given custom registries with more than one built-in registries. One of the those built-in registries is aDynamicTargetRegistry
. On Qt, such registry supports querying forQWidget.isEnabled()
. On wx, such registry supportswx.Window.IsEnabled()
. With thatget_default_registry
is changed toget_default_registries
to return a list instead of a single registry.IsEnabled
forButtonEditor
is replaced by the more general registry.Note:
TargetRegistry.get_*
is strictly speaking a change to the public API. However I believe these methods are only called byUIWrapper
and is hardly useful otherwise, so it is unlikely to break downstream code. We should probably rename the methods to mark them as internal though.IsVisible
after the changes in this PR (Add 'IsVisible` query class for UI Tester #1291)testing
package... that abstract base class was killed early to defer decisions on generalizing an interface. With a concrete use case, the resulting interface here is different from that old one. I'm glad to have avoided early generalization/abstraction.With regret, I will be closing this PR (without merging) once it is good enough to be kept for future reference. This was due to my lack of availability and I would not want to keep a PR open unless I know I can commit to follow through with it. I hope that this PR, as a record, helps solving #1418 in the future.I will be pushing a few more changes before I close it.Comments are very welcome any time!