-
Notifications
You must be signed in to change notification settings - Fork 450
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
Add check on infohash key existing #5910
Conversation
@@ -132,6 +132,9 @@ def _on_selection_changed(self, selected, deselected): | |||
class HealthCheckerMixin: | |||
def check_torrent_health(self, data_item, forced=False): | |||
# TODO: stop triggering multiple checks over a single infohash by e.g. selection and click signals | |||
if 'infohash' not in data_item: |
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.
As I understand it, channels have infohashes as well as regular torrents, but we probably don't want to show health information for channels in this view.
In other similar places, there is a check if data_item['type'] != REGULAR_TORRENT
. I think we need to use a similar check here as well.
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.
Checking infohash is a more reliable approach if we look at the change as a "bugfix".
But your suggestion is the more in "triblertablecontrollers' style". And your approach is more correct if we look at the change as a "triblertablecontrollers fix".
I've implemented your suggestion (still not sure that this is the best version of the bugfix).
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 is indeed more correct to check for the entry type, not for its attributes. In this way, we catch the errors in the application logic, though at the cost of the thing crashing for the user.
94fe4b1
to
88985ee
Compare
@@ -287,7 +293,7 @@ def add_menu_item(self, menu, name, item_index, callback): | |||
def selection_can_be_added_to_channel(self): | |||
for row in self.table_view.selectionModel().selectedRows(): | |||
data_item = row.model().data_items[row.row()] | |||
if 'type' in data_item and data_item['type'] in (REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_NODE): | |||
if dict_has(data_item, 'type', REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_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.
Actually, I don't like this new dict_has
function. In my opinion, it makes code much harder to understand.
- Previously the code did not require additional context to understand what is going on. Now I need to look at the
dict_has
source to understand the details of its logic. - In the previous code it was clear to me that
data_item
is adict
instance (or, at least, some objects with the Mapping interface). Now the code will not break ifdata_item
is, for example,None
. So, if I need to extend this function in the future, I need to spend time to answer the question "can data_item be anything other than dict", whereas in the previous version it was obvious. - The new version is not significantly shorter. If the goal is to achieve brevity it was possible to write instead:
if data_item.get('type') in (REGULAR_TORRENT, CHANNEL_TORRENT, COLLECTION_NODE):
...
So I propose to roll back this change and remove the dict_has
function.
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.
Python is a dynamically typed language but it is strongly typed. The expressionfoo[bar]
generates KeyError
exception when it is incorrectly assumed that foo
should be a mapping and bar
is a required item of this mapping, and it is a good thing. It is like a programmer explicitly adds some assertions to its code which will guarantee that errors will raise fast and not be propagated to different places. When we add unnecessary checks if foo
or if bar in foo
we essentially convert strongly typed language to a weakly typed one.
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.
Previously the code did not require additional context to understand what is going on. Now I need to look at the dict_has source to understand the details of its logic.
Yes, and this is ok. You need to understand once what this function does, and then relax for all other occurrences.
dict_has
just extract a pattern that was used in this file three times
Now the code will not break if data_item is, for example, None
Yes, and this is great. No excuses for crash on the user side.
The new version is not significantly shorter.
Yes, but shortnesses is doubtful purpose. The new version reduces the number of repetitions (of a pattern itself and of key's value, inside the pattern). Therefore it decreases the chance to make a mistake.
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.
dict_has just extract a pattern that was used in this file three times
Not all patterns probably should be extracted. a + b * c
is better than addmul(a, b, c)
Yes, and this is great. No excuses for crash on the user side.
If we a sure that, say, something can never be None
, adding unnecessary handling for None
leads to less clear code, as from now it says to the future reader: there are some obscure cases when this variable really can be None
.
Yes, and this is ok. You need to understand once what this function does, and then relax for all other occurrences.
Many developers need to do it, and even a single developer does not remember all details of all the small functions that he reads in the entire codebase and needs to read it again.
Actually, this specific case is small enough to turn it into the bikeshedding, but the general pattern looks a bit like a code obfuscation to me.
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 agree with @kozlovsky . Python is not C++: Python programmers are used to some idiomatic ways to do simple stuff like checking dict
attributes, etc. Python is not about inventing your own sub-language as C++ does. Python is about making the code immediately readable to anyone.
So, replacing an explicit one-liner with an implicit one-liner goes against the Zen of Python
import this
😉
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.
Dijkstra would say that exceptions in reports can be used to show the presence of bugs, but never to show their absence :)
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.
So, every release must look as stable as possible, even if it means hiding defects, right?
Probably it is better to just answer "yes" on your question.
But I would say, if a release doesn't look stable, you shouldn't publish it. Taking into account, that "obscure cases" always will be presented... we need to make release stable with the margin of safety.
(in my humble view)
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
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.
Dijkstra would say that exceptions in reports can be used to show the presence of bugs, but never to show their absence :)
Of course. Yet exceptions is almost the only kind of feedback and support that we get from our userbase. Because, you know, we can't do telemetry.
@@ -422,3 +422,9 @@ def disconnect(signal: pyqtSignal, callback: Callable): | |||
|
|||
class CreationTraceback(Exception): | |||
pass | |||
|
|||
|
|||
def dict_has(d, key, *values_or): |
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.
Still think it is better to inline code without a function, but it is more important to have this fix in the release.
How about changing the function signature to
def dict_item_is_any_of(d, key, values):
Just a suggestion, as the values_or
argument name requires to look at the function signature to understand the meaning of multiple values.
Kudos, SonarCloud Quality Gate passed! |
This PR resolves #5909 by adding a check on the existing of
infohash
key.The root cause of the issue is too general an inaccurate design of
ContentTableViewController
.My proposal: to schedule a refactoring for
ContentTableViewController
.