Skip to content

remote: fix remote default call with no arguments #2821

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

Merged
merged 6 commits into from
Nov 26, 2019
Merged

remote: fix remote default call with no arguments #2821

merged 6 commits into from
Nov 26, 2019

Conversation

kaiogu
Copy link
Contributor

@kaiogu kaiogu commented Nov 20, 2019

remote default command with no arguments now returns default remote instead of
setting default remote to None.

Fixes #2813

  • ❗ Have you followed the guidelines in the Contributing to DVC list?

  • 📖 Check this box if this PR does not require documentation updates, or if it does and you have created a separate PR in dvc.org with such updates (or at least opened an issue about it in that repo). Please link below to your PR (or issue) in the dvc.org repo.

  • ❌ Have you checked DeepSource, CodeClimate, and other sanity checks below? We consider their findings recommendatory and don't expect everything to be addresses. Please review them carefully and fix those that actually improve code or fix bugs.

Thank you for the contribution - we'll try to review it as soon as possible. 🙏

remote default command with no arguments now returns default remote instead of
setting default remote to None.

Fixes #2813
@kaiogu
Copy link
Contributor Author

kaiogu commented Nov 20, 2019

Noticed too late that this probably breaks --unset option, I'll fix it.

@shcheklein shcheklein requested review from a user and pared November 20, 2019 18:35
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the pull request! Could you please add a test for this?

The rest looks good to me)

@ghost
Copy link

ghost commented Nov 21, 2019

@kaiogu, adding some more guidance, the test would be under tests/func/test_remote.py.
We have some legacy tests written with unittest but we are slowly moving to pytest, so please, write it with pytest on mind 😅

You can take a look at other tests to get an idea of how we usually test stuff. In general, there's
a main method that we use to invoke CLI commands. In this case, we are trying to test when dvc remote default is called. Also, to intercept the logs you can use the caplog fixture.
There's another fixture to work with a DVC initialized repository: dvc_repo.

So the test would be something like:

def test_show_default(dvc_repo, caplog):
    assert main(["remote", "default", "foo"]) == 0
    assert main(["remote", "default"]) == 0
    assert "foo" in caplog.text

It uses a DVC repository and run the commands dvc remote default foo and then dvc remote default (making sure that the exit code is 0), finally, it tests weather there was foo (the name of the remote) in the output from the logger.

@pared
Copy link
Contributor

pared commented Nov 21, 2019

LGTM, we can merge after the test is written.

@kaiogu
Copy link
Contributor Author

kaiogu commented Nov 22, 2019

Hi @pared, thanks for the info! I could write a test over the weekend if this isn't that time critical. I've got no experience wit pytest (or unittest) but would be willing to learn.

@pared
Copy link
Contributor

pared commented Nov 22, 2019

@kaiogu please take your time, if you need our help, feel free to write here, or message us directly on our discord :)

@kaiogu
Copy link
Contributor Author

kaiogu commented Nov 25, 2019

@pared @MrOutis This last commit passes the test on my machine but doesn't on Travis CI because Travis seems to be writing to the caplog also. Can I call caplog.clear() on the beginning of the test, or would the solution given by mroutis be preferred (in instead of ==)?

@efiop efiop requested a review from a user November 26, 2019 06:51
@ghost
Copy link

ghost commented Nov 26, 2019

@kaiogu, it is better to use in :)

@@ -145,6 +145,12 @@ def test(self):
self.assertEqual(default, None)


def test_show_default(caplog):
Copy link
Contributor

@efiop efiop Nov 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to remove

Suggested change
def test_show_default(caplog):
def test_show_default(dvc_repo, caplog):

as it makes the test run in the repo itself instead of in the test env. I think you've removed it because DS was complaining, but it was wrong there 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right. 😄 Some tool said something about prepending the argument with unused or something like that, but I can't find the message anymore. So should I just keep the argument and let the build fail?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kaiogu Yes, DS will probably fail, but the tests themselves (run on travis) won't, so we are fine 🙂

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill accept after this dvc_repo is reintroduced. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pared Done :)

@efiop
Copy link
Contributor

efiop commented Nov 26, 2019

@MrOutis Or we could call caplog.clear() after dvc remote add, right? And then we could use a more strict assert "foo" == caplog.text. Or am I missing something?

@kaiogu
Copy link
Contributor Author

kaiogu commented Nov 26, 2019

So I checked again and if I run the test exactly as recommended in the contributions guidelines it fails on my end to.

@efiop caplog.text returns a str of all log messages, with the logger name, level and message for each. To get only the actual message, caplog.record_tuples seems to be needed for equality checking. It returns a list of log tuples like [(logger_name, log_level, message)]. So I could check for stricter equality only if I compare somethingin a way similar to my last commit: assert "foo" == caplog.record_tuples[0][2].

The above does not work in the test environment though. I tried wrapping the body of the test with with caplog.at_level(logging.INFO): but that doesn't work as there seem to be some test-time-only messages also populating the caplog at that logging level.

Just doing the solution proposed by @MrOutis works, but I'd change foo to something less common to avoid accidentaly passing the test if there is a random "foo" in the log. This solution is ready to push.

Alternatively, the recommendation in the python logging docs is to actually use print statements instead of logging in the call to remote default with no args. This output I could capture with the capsys fixture of pytest, it could check for equality, and wouldn't reside in the same "space" as the actual logging messages. I think this would be the best solution overall, but I can implement what you decide. This might entail some reworking of other parts of the code to keep consistency.

def test_show_default(caplog):
assert main(["remote", "default", "foo"]) == 0
assert main(["remote", "default"]) == 0
assert "foo" == caplog.record_tuples[0][2]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using caplog.records[0].message?
Seems more readable than record_tuples :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obsolete after efiop comment

@efiop
Copy link
Contributor

efiop commented Nov 26, 2019

@kaiogu You are absolutely right about print, we should use it. I've recommended logger.info through inertion, as we have a log&print mess in our code(we even have a separate issue to make things use print instead of info where appropriate). Indeed, let's use print here instead. And indeed, in that case the test would be able to simply use capsys(as in other our tests). So we only need to change:
logger.info("{}".format(name)) -> print(name) and assert "foo" == caplog.record_tuples[0][2] -> assert capsys.readouterr().out == "foo\n" . I'm sure that is going to work and won't require any additional adjustments in other tests 🙂

Turns out that the argument was needed after all
Python logging recommends using print instead of logging for ordinary
output of command line program.

Also changed the test to reflect this.
Copy link
Contributor

@efiop efiop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect! Thank you so much! 🙏

@efiop efiop merged commit a1cc2e6 into iterative:master Nov 26, 2019
@kaiogu
Copy link
Contributor Author

kaiogu commented Nov 26, 2019

Thank you for the guidance! Happy to contribute! 😄

@efiop
Copy link
Contributor

efiop commented Nov 27, 2019

@kaiogu 0.71.0 is out, please upgrade and give it a try 🙂 Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

remote default with no argument removes default
3 participants