Skip to content

Make uninstall less verbose#4493

Merged
dstufft merged 6 commits intopypa:masterfrom
pradyunsg:nicer-uninstall
May 19, 2017
Merged

Make uninstall less verbose#4493
dstufft merged 6 commits intopypa:masterfrom
pradyunsg:nicer-uninstall

Conversation

@pradyunsg
Copy link
Copy Markdown
Member

Closes #4229

@pradyunsg
Copy link
Copy Markdown
Member Author

pradyunsg commented May 17, 2017

This change makes pip uninstall spew less paths when run without any flags.

$ .tox/py35/bin/pip uninstall nose
Uninstalling nose-1.3.7:
  /home/pradyunsg/code/pip/.tox/py35/bin/nosetests
  /home/pradyunsg/code/pip/.tox/py35/bin/nosetests-3.4
  /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/*
  /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/*
  /home/pradyunsg/code/pip/.tox/py35/man/man1/nosetests.1
Proceed (y/n)? y
  Successfully uninstalled nose-1.3.7

The listing of all the files (as currently given by pip uninstall) can still be gotten through the use of --verbose.

# I manually inserted the [snip] to prevent an overly long message
$ .tox/py35/bin/pip uninstall --verbose nose
Uninstalling nose-1.3.7:
  /home/pradyunsg/code/pip/.tox/py35/bin/nosetests
  /home/pradyunsg/code/pip/.tox/py35/bin/nosetests-3.4
  /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/DESCRIPTION.rst
  [snip]
  /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/usage.txt
  /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/util.py
  /home/pradyunsg/code/pip/.tox/py35/man/man1/nosetests.1
Proceed (y/n)? y
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/bin/nosetests
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/bin/nosetests-3.4
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/DESCRIPTION.rst
  [snip]
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/usage.txt
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/util.py
  Removing file or directory /home/pradyunsg/code/pip/.tox/py35/man/man1/nosetests.1
  Successfully uninstalled nose-1.3.7

(edited to add descriptions to the runs)

@pfmoore
Copy link
Copy Markdown
Member

pfmoore commented May 17, 2017

Your comment is a bit confusing. I assume the first output is the new shorter version, and the one with --verbose is the same as the current default output?

One question - if there's something in /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose that won't be deleted by pip (for example, something the user added manually) then would the abbreviated output still show /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/*? That's wrong, but it seems like that's what the code does.

I know it's an extremely unlikely case, so I'm not going to make a major issue out of it if no-one else thinks it's important, but I don't like the thought that we say we're going to delete nose/* and then don't do so.

@pradyunsg
Copy link
Copy Markdown
Member Author

I assume the first output is the new shorter version, and the one with --verbose is the same as the current default output?

Yeah... That is the output of uninstall command from this PR. Without --verbose, the output is shortened. --verbose matches the current output. (I'll edit and make it more clear)

if there's something in /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose that won't be deleted by pip (for example, something the user added manually) then would the abbreviated output still show /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/*?

It would still show it and not delete that file... I didn't think of that. I thought along the lines of what folders does a package "own" all files of, how to determine those paths and came up with this.

I don't like the thought that we say we're going to delete nose/* and then don't do so

Same but then, how do you think we should show the output then? I can't come up with something terse yet clean way of displaying this situation.

@pfmoore
Copy link
Copy Markdown
Member

pfmoore commented May 18, 2017

I think that's the problem here. There isn't a clean way to display that. Also there's the __pycache__ files to consider. IIRC, pip deletes them even though they aren't in the package's RECORD, but doesn't list them in the output of uninstall.

I don't have a good solution here. For a completely quiet uninstall, there's the -y option. If the user doesn't use that they get told what's going to happen and asked if they are OK with going ahead, so I think we need to make sure we don't mislead them about what they are agreeing to.

I guess we could add a section after the file list if there are any unexpected files, just before the "Are you sure?" prompt:

The following files appear to have been added manually and will not be deleted:
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/user-supplied.txt
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/RECORD.backup

But I suspect it'll be significantly more complex to collect that information. What do you think?

Comment thread pip/req/req_uninstall.py Outdated
new_paths = []
for path in paths:
if path.endswith("__init__.py"):
new_paths.append(path[:-12] + os.path.sep + "*")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

os.path.dirname would be cleaner :o

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Indeed.

Comment thread pip/req/req_uninstall.py
path[len(shortpath.rstrip("*").rstrip(sep))] == sep
for shortpath in short_paths
)
if not should_add:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we should "just" enhance compact to detect the case where it has:
['a/b/toto.py', 'a/b/tutu.py'] and 'a/b' only contains the two files, then it should only keep 'a/b'
This should produce a much more compact output in most cases.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's what I did initially but these same paths are being used to delete files and I didn't want to modify this logic because of that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That sounds reasonable. If there are still cases where it's not compact enough, we can review those to work out what additional improvements are practical and safe. (We may need to special-case __pycache__, although https://github.com/pypa/pip/blob/master/pip/req/req_uninstall.py#L115 might cover it)

Copy link
Copy Markdown
Member Author

@pradyunsg pradyunsg May 18, 2017

Choose a reason for hiding this comment

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

@pfmoore I added checks to filter out for .pyc files locally in the non-verbose mode.

@pradyunsg
Copy link
Copy Markdown
Member Author

I'm gonna grab lunch now.

I think I'll just refactor out the user interaction/output code into a separate function. And do all the processing for what to show within that.

@pradyunsg
Copy link
Copy Markdown
Member Author

But I suspect it'll be significantly more complex to collect that information. What do you think?

I think it looks good.

@pradyunsg
Copy link
Copy Markdown
Member Author

pradyunsg commented May 18, 2017

Non-Verbose mode output now mentions which files would not be removed.

$ ./.tox/py35/bin/pip uninstall nose
Uninstalling nose-1.3.7:
  Would remove:
    /home/pradyunsg/code/pip/.tox/py35/bin/nosetests
    /home/pradyunsg/code/pip/.tox/py35/bin/nosetests-3.4
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/*
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/*
    /home/pradyunsg/code/pip/.tox/py35/man/man1/nosetests.1
  Would not remove (might be manually added):
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/foo.txt
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/foo/myawesome.txt
Proceed (y/n)? n

Verbose mode output stays the same.

$ ./.tox/py35/bin/pip uninstall nose --verbose
Uninstalling nose-1.3.7:
  Would remove:
    /home/pradyunsg/code/pip/.tox/py35/bin/nosetests
    /home/pradyunsg/code/pip/.tox/py35/bin/nosetests-3.4
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/DESCRIPTION.rst
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose-1.3.7.dist-info/INSTALLER
    [snip]
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/tools/__pycache__/nontrivial.cpython-35.pyc
    [snip]
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/usage.txt
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/util.py
    /home/pradyunsg/code/pip/.tox/py35/man/man1/nosetests.1
Proceed (y/n)? n

@pradyunsg
Copy link
Copy Markdown
Member Author

pradyunsg commented May 18, 2017

@pfmoore @xavfernandez Do any of you think it'll be useful to add which files would not be removed to the verbose output?

I think it'll be useful there. :)

@pradyunsg
Copy link
Copy Markdown
Member Author

IIRC, pip deletes them even though they aren't in the package's RECORD, but doesn't list them in the output of uninstall.

pip does list them in the output.

If the user doesn't use that they get told what's going to happen and asked if they are OK with going ahead, so I think we need to make sure we don't mislead them about what they are agreeing to.

I think that doing what we said we would - uninstall the package - is what we do. If the user uses -y maybe we can logger.warn them about it?

@pradyunsg
Copy link
Copy Markdown
Member Author

I think it'll be useful there. :)

Now, after a sleep cycle, I don't think so. :/

@pfmoore
Copy link
Copy Markdown
Member

pfmoore commented May 19, 2017

I think that doing what we said we would - uninstall the package - is what we do.

What I'm getting at is that if the user doesn't specify -y or -v then we say something like

Would remove:
[...]
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/*
[...]
Proceed (y/n)?

If the user says to proceed then they are entitled to assume that the whole of /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/ will be gone. But if there's a file in there that isn't deleted by pip, we're violating that expectation.

With the addition of the extra information

  Would not remove (might be manually added):
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/foo.txt
    /home/pradyunsg/code/pip/.tox/py35/lib/python3.5/site-packages/nose/foo/myawesome.txt

it's fine, because we've explicitly said that we're going to leave some files behind.

I'm perfectly OK with the fact that if the user specified -y we just do the uninstall. I can't offhand remember if we list the files in that case, but if we do the new abbreviated form is fine - we don't need to do anything special to cover the -y case.

@pradyunsg
Copy link
Copy Markdown
Member Author

I can't offhand remember if we list the files in that case

Files are not listed if you specify -y.

What I'm getting at is that if the user doesn't specify -y or -v then we say something like

The PR does this now. See #4493 (comment)

@pradyunsg
Copy link
Copy Markdown
Member Author

I think this is ready.

/request-review @dstufft @pfmoore @xavfernandez

@dstufft dstufft merged commit d24581f into pypa:master May 19, 2017
Comment thread pip/req/req_uninstall.py
file_ = os.path.join(dirpath, fname)
if os.path.isfile(file_) and file_ not in files:
# We are skipping this file. Add it to the set.
will_skip.add(file_)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@pradyunsg Ideally this logic should be extracted in a function with a few simple tests

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Doing this right now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I was thinking unittest to test that given a long list of files we do end up with the correct shorter list.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Cool. #4502 it is. :)

@pradyunsg
Copy link
Copy Markdown
Member Author

@pfmoore Cool. I think I understand it now -- it's just the matter of running things through os.path.normcase.

@pfmoore
Copy link
Copy Markdown
Member

pfmoore commented Oct 5, 2017

It usually is :-) ("Just scatter normcase around" is the new version, in a post-Unicode world, of "just add a few encode/decode calls" 😃 )

@lock
Copy link
Copy Markdown

lock bot commented Jun 2, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label Jun 2, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Jun 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

auto-locked Outdated issues that have been locked by automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"pip uninstall" is too noisy

4 participants