-
Notifications
You must be signed in to change notification settings - Fork 24
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
[WIP] Add a feedback dialog box #93
Conversation
Codecov Report
@@ Coverage Diff @@
## master #93 +/- ##
=========================================
Coverage ? 40.51%
=========================================
Files ? 240
Lines ? 8912
Branches ? 1158
=========================================
Hits ? 3611
Misses ? 5155
Partials ? 146 Continue to review full report at Codecov.
|
This is an intern project. I'll be reviewing and guiding the work. |
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've given some feedback, some nit-picky some fairly important.
Other points:
- this is a replacement for/improvement upon
apptools.logging.agent
so you need to think what should be done with that code. Either this should replace it, or you should remove that code as part of this PR (which breaks backwards compatibility, but I think that's OK). Following the naming of that package (eg.QualityAgent
rather thanFeedback
) may be a good idea. - this PR is totally dependent on Slack and it's API, but that is just one of the possible channels that we might want to use to solicit user feedback, depending on the needs of our clients. Also there is a high likelihood that Slack's API will change or go away or cost money over the course of years and we don't want to have to re-write a quality agent a 4th (or 5th or 6th time). At a minimum we should be able to support e-mail delivery of feedback in the future; and being able to send to a generic RESTful endpoint woudl also make sense. Think about architecting this so that Slack is just one possible delivery layer, even if you don't implement anything else just yet. This would mean rather than having a
send
function you have an abstract base class which has an abstractsend
method and which can take a feedback message object; concrete subclasses will format it and send it as appropriate for that delivery mechanism. Users of your code can then implement as desired. - it would be nice to have a screenshot of the view as part of the PR.
Other than that, basically looks OK, and pretty good for a first shot at a TraitsUI interface.
|
||
""" | ||
|
||
first_name = Str(msg_meta=True) |
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.
Please give a comment for all trait definitions, eg. #: The first name of the user.
A secondary comment is that it's probably easier to have just one name field unless there is some compelling reason to split it.
|
||
# Send message. | ||
response = client.files_upload( | ||
channels=self.channels, |
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.
Nitpick: indentation.
Please run flake8 (or equivalent) over your code.
|
||
except slack.errors.SlackApiError as error: | ||
|
||
print( |
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.
Don't use print, instead use logging
. Standard procedure for logging in a library like this is to have at the top of the file a
import logging
logger = logging.getLogger(__name__)
and then here you would use logger.error
and/or logger.exception
to record the error.
|
||
except aiohttp.client_exceptions.ClientConnectorError as error: | ||
|
||
print('Message not sent.') |
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.
Same comment here about logging.
|
||
else: | ||
|
||
print('Message sent successfully!') |
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.
And here, but this would be logger.info
.
#: Main body of the feedback message. | ||
description = Str(msg_meta=True) | ||
|
||
#: The target slack channel that the bot will post to, must start with #. |
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.
"Channels" and "tokens" are not part of the concept of a "message". They are part of the concept of a (particular) delivery system and so should be factored out into their own class (see main review comment).
msg = Str | ||
|
||
#: The screenshot pixel data in raw bytes. Note that RGB[A] ordering is assumed. | ||
img_bytes = Bytes |
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.
Use a numpy
array (ie. image = Array(shape=(None, None, 3))
for an RGB image, (None, None, 4)
for RGBA). It is easy to convert to a Pillow Image
from an array, and you don't need to store auxiliary information like the height and width.
You are using Chaco and/or Enable here, so numpy is already a dependency.
And one more thing - this PR doesn't add a feedback menu item, it provides a feedback dialog. You might want to update the title of the PR. Adding a menu item is a secondary thing and can be part of a second PR, if needed. |
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.
Here's a first round of comments. I'll generate more as I mess around with it.
#: The screenshot height in pixels. | ||
img_h = Int | ||
|
||
@on_trait_change('+msg_meta') |
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.
For this it makes more sense to use a Property
instead of a trait-change handler.
plugin can be used in their application. | ||
""" | ||
|
||
from PyQt4.QtGui import QPixmap |
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.
Please import from pyface.qt.QtGui
so this is more portable.
@@ -0,0 +1,468 @@ | |||
""" |
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.
Please simplify this as much as possible and move it into examples
.
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.
It's already here: https://github.com/enthought/ets-examples/blob/master/snippets/validating_dialog.py
It shouldn't be in this at all, I think.
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 meant just the menu item code. It would be good to have bare-bones example that holds the invocation sequence of the dialog.
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.
Oh - I see it now. Yep, I agree.
@corranwebster, @cfarrow: Thanks for the feedback! I'll be pushing changes today. |
@siddhantwahal I did not get a notification when you sent that. Sorry about that. I'll try to review soon. |
@cfarrow No worries! I'm not totally finished making changes. I'll comment here and ping you on slack when it's ready for review. |
Sounds good. (I got that notification. 😄) |
@cfarrow I'm think I'm done with most of the big changes. The only thing remaining is a README. I'm not sure if my approach to testing is right (I |
Ok. I'll take a look today or tomorrow. |
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.
Things are looking good. I have another round of comments to consider.
@@ -0,0 +1,96 @@ | |||
""" |
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 better placed in /examples/feedback
instead of apptools/feedback/examples
.
return img_array | ||
|
||
|
||
def initiate_feedback_dialog_(control, token, channels): |
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.
Why the trailing _
? If it's for the sake of avoiding name conflict in the example, it is not necessary. (Let's talk in person if it's not clear why.)
#: 3D numpy array to hold three channel (RGB) screenshot pixel data. | ||
img_data = Array(shape=(None, None, 3), dtype='uint8', required=True) | ||
|
||
# FIXME: Not sure if this the right way to go about initiating a |
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.
The right way to do this would be
compressed_img_buf = Instance(io.BytesIO, args=())
.
The args=
part says what to use when initializing the type (io.BytesIO
).
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.
(That said, this works. I've never seen it done this way before.)
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.
Upon closer inspection, this is only used by the send
method. It's probably best to not make it a trait and create the buffer as needed inside of send
.
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 moved it out assuming that it would reduce time spent in the send
function. Some more experiments revealed that while time spent in send
is reduced (1.57s to 1.5s), the difference is barely noticeable by the user, so now it's back in. (Note to self: time everything)
token = Str(required=True) | ||
|
||
#: The final message that gets posted to Slack. | ||
msg = Property(Str, depends_on='msg_meta') |
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 believe this should be depends_on='+msg_meta'
. It would be good to make this consistent with the syntax in the view.
from apptools.feedback.feedbackbot.model import FeedbackMessage | ||
|
||
|
||
class TestFeedbackMessage(unittest.TestCase, UnittestTools): |
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 are essentially testing traits. It would be better to test the logic in the send
method. This can be done by mocking slack.WebClient.files_upload
and checking that the right information is passed.
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.
One minor nit.
examples/feedback/example.py
Outdated
|
||
|
||
# View for the example app. The feedbackbot module provides a helper function | ||
# `initiate_feedback_dialog_` that launches the feedback dialog box. To include |
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.
Nit: this still has the trailing underscore.
This is close to finished. There still the comment about |
@corran, what is your opinion about the logging stuff ?(See the comment above.) |
I'm in favor of merging it because it is usable as-is. There are concerns about the logging code which has a similar intent, but is constructed completely differently. |
I expected to see changes to CI build settings as there are additional dependencies on With that, I am not sure this can be merged as-is. |
Once the feature is merged and released, it will be part of a published public API and refactoring will be more constrained. Just the fact a feature is live and published demands maintenance. For apptools release 5.0, we spent a lot of time discussing whether various subpackages can be removed, and when we cannot be sure, they are kept, we flake8-them, migrate tests from nose to unittest, update setup.py for their (optional) dependencies, add documentation etc. etc. If this feature is gaining enough traction, let's make sure it is tested on CI and maybe flag the API as provisional. If there are not enough traction, we can also consider tagging the commit to persist it on the git repo instead of merging. If interest arises again, we can continue the efforts from there. This issue may be related: #137 |
This PR needs some changes to ensure the added tests are exercised on CI. |
I'm not super-keen. We can fix the CI issue, but I also think there are some opportunities to rethink the design. In particular, I'd like to see the notification mechanism (Slack in this case) better separated from the dialog and screenshot stuff. It's a really interesting PR as a proof of concept, and yes, maybe worth an |
Thank you @mdickinson. Agree to what you said. If no one wants to advocate the otherwise, I will close and tag this PR in about a week time (I will try to remember). |
I have now tagged the last commit as Closing. |
This PR adds a
Feedback/Bugs
dialog box to apptools. This dialog box allows the client-user to quickly report bugs or request features. Messages are sent directly to the developer team's slack channel.Files:
feedbackbot/model.py
: Logic for the client-user interface.feedbackbot/view.py
: Client-user side GUIfeedbackbot/utils.py
: Some helpful functions.feedbackbot/tests
: Unit tests.examples/example.py
: An example of how the developer-user, i.e., a developer who wishes to integrate this menu item in their app, would go about doing so.To-do list:
ImageTrait
instead of relying on utility functions to do conversions