-
Notifications
You must be signed in to change notification settings - Fork 452
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
Fix "ValueError: relative path can't be expressed as a file URI" #7764
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from unittest.mock import Mock, patch | ||
|
||
import pytest | ||
from PyQt5.QtWidgets import QFileDialog | ||
|
||
from tribler.gui.tribler_window import TriblerWindow | ||
|
||
|
||
# pylint: disable=redefined-outer-name | ||
@pytest.fixture | ||
def tribler_window(): | ||
""" Create mocked TriblerWindow instance""" | ||
with patch('tribler.gui.tribler_window.TriblerWindow.__init__', Mock(return_value=None)): | ||
window = TriblerWindow(Mock(), Mock(), Mock(), Mock()) | ||
window.pending_uri_requests = [] | ||
return window | ||
|
||
|
||
def test_on_add_torrent_browse_file(tribler_window: TriblerWindow): | ||
""" Test that the on_add_torrent_browse_file method works correctly""" | ||
tribler_window.raise_window = Mock() | ||
tribler_window.process_uri_request = Mock() | ||
|
||
with patch.object(QFileDialog, 'getOpenFileNames', Mock(return_value=['.'])) as patched_getOpenFileNames: | ||
tribler_window.on_add_torrent_browse_file() | ||
|
||
assert tribler_window.raise_window.called | ||
assert patched_getOpenFileNames.called | ||
assert tribler_window.process_uri_request.called |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,15 +83,13 @@ | |
from tribler.gui.utilities import ( | ||
connect, | ||
create_api_key, | ||
disconnect, | ||
format_api_key, | ||
get_font_path, | ||
get_gui_setting, | ||
get_image_path, | ||
get_ui_file_path, | ||
is_dir_writable, | ||
set_api_key, | ||
show_message_box, | ||
tr, | ||
) | ||
from tribler.gui.widgets.instanttooltipstyle import InstantTooltipStyle | ||
|
@@ -681,13 +679,16 @@ def on_create_torrent_updates(self, update_dict): | |
|
||
def on_add_torrent_browse_file(self, *_): | ||
self.raise_window() # For the case when the action is triggered by tray icon | ||
filenames = QFileDialog.getOpenFileNames( | ||
filenames, *_ = QFileDialog.getOpenFileNames( | ||
self, tr("Please select the .torrent file"), QDir.homePath(), tr("Torrent files%s") % " (*.torrent)" | ||
) | ||
if len(filenames[0]) > 0: | ||
for filename in filenames[0]: | ||
self.pending_uri_requests.append(Path(filename).as_uri()) | ||
self.process_uri_request() | ||
if not filenames: | ||
return | ||
|
||
for filename in filenames: | ||
uri = Path(filename).resolve().as_uri() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any harm in using resolve() here but I wonder if this will fix the issue since the expected file is .torrent files which should exist as it is selected using the file dialog. The reproduction using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing the test from the original to the following produces the same reproducibility. def test_on_add_torrent_browse_file(tribler_window: TriblerWindow):
""" Test that the on_add_torrent_browse_file method works correctly"""
tribler_window.raise_window = Mock()
tribler_window.process_uri_request = Mock()
with patch.object(QFileDialog, 'getOpenFileNames', Mock(return_value=['./any.torrent'])) as patched_getOpenFileNames:
tribler_window.on_add_torrent_browse_file()
assert tribler_window.raise_window.called
assert patched_getOpenFileNames.called
assert tribler_window.process_uri_request.called |
||
self.pending_uri_requests.append(uri) | ||
self.process_uri_request() | ||
|
||
def start_download_from_uri(self, uri): | ||
uri = uri.decode('utf-8') if isinstance(uri, bytes) else uri | ||
|
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.
Suggestion to adhere to our Pylint rules:
That aside: please make sure the tests pass and re-request my review.
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 for the suggestion. From my point of view, for this particular case (for
test_*.py
files), it is preferable to use the following construction:Example 1
Instead of the suggestion by pylint:
Example 2
Pylint is aimed at helping developers but not to be blindly obeyed. In many cases, pylint does a great job. However, in this particular case (from my point of view), the suggestion doesn't protect us from any error and does not make the code better. Instead, it makes the code more polluted as it requires unnecessary syntax complication.
I tried both approaches with Tribler, and based on my experience, Example 1 is as correct as Example 2, but it looks better and requires less time to write and correct, which saves developers' time.
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.
In some cases, linters produce style violations, which are a matter of taste. However - in this case - Pylint correctly flags name shadowing. You can find more information in the
pytest
documentation: https://docs.pytest.org/en/stable/reference/reference.html#pytest-fixture (along with other methods to avoid name shadowing).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.
Agreed, but in this case, name shadowing is not a developer's mistake but a way how fixtures are implemented in
pytest
. There is nothing wrong with this fixture definition.Related:
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 is indeed the way it is implemented in
pytest
and I'm not saying that it is the developer's mistake or fault (though I guess a developer can be faulted for not reading the docs to some extent). For example,pytest
also rewrites the source code of test files and reinjects them intosys.modules
, which is also dubious practice (and one we should not repeat).Agreed in general, disagreed for the fixture definition in this PR. The
pytest
docs themselves tell you what is wrong:Now
pytest
may be wrong aboutpytest
butpytest
seems like a trustworthy source forpytest
information to me.Just to repeat - myself and the docs - adding a "name" is not the only way to resolve this. Secondarily, this has nothing to do with Pylint, other than that it will also tell you the same thing. I like the idea of adding
pylint-pytest
though.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.
@egbertbouman @xoriole please, share your opinion 🙏
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.
@qstokkink, no-no, I think I understand you. But in test
test_2
, there is no shadowing.And yes, someone in the future could introduce mistakes (arithmetic, logical, or even related to shadowing) to
test_2
, which has nothing in common with the shadowing mentioned in the original pylint warning.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.
@drew2a Judging from your comment, I still do not think that you do understand. There is one specific type of situation that can happen solely due to the construction that causes name shadowing (in
test_1
). Not multiple as you just said. I gave an instance of this type of situation in the example above (#7764 (comment)).The shadowing warning you get for
test_1
causes trouble fortest_2
, which will not get a warning. It (test_2
) will pass, even though it can and should fail.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.
@qstokkink, with all due respect, it's not shadowing that causes the potential problem; it's just a badly written test that caused the problem.
Here's a slightly changed example that "has problems due to shadowing." It still has them, even without any shadowing:
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.
@drew2a Yes, thank you, that is indeed the core issue: if
something
is now made into afixture
, which uses aname
argument, exactly this type of error cannot happen.