Skip to content
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

Enable unlinking of symbolic links to folders in Windows #199

Merged
merged 1 commit into from
Jul 10, 2015

Conversation

tillberg
Copy link
Contributor

@tillberg tillberg commented Jul 9, 2015

It appears that in Python 2.x on Windows os.unlink(path) can't remove symbolic links to folders, and it's necessary to use os.rmdir(path) instead. In Python 3.x, this appears to have been fixed along with generally adding support for os.symlink in Windows.

This patch adds special casing to LocalPath.unlink to enable deleting symbolic links to folders in Windows. I chose to duplicate the hasattr(os, "symlink") feature-detect from the LocalPath.symlink method, as that will still use os.unlink all the time if os.symlink is available (Python 3.x, or Python 2.x on Unix-y systems). Additionally, if not self.isdir(), such as for files or for symbolic links to files, we still call os.unlink as before.

A side-effect of this change is that for Python 2.x on Windows, calling LocalPath.unlink on an empty directory (the actual directory, not a symlink to it) will now call os.rmdir instead of os.unlink, which will now successfully remove the directory. but whenever os.symlink is available, this would no longer work. Any currently-existing code would be calling LocalPath.delete, though, to delete directories.

Below are two REPL sessions demonstrating the behavior. The first is Python 2.7, and the second is Python 3.4. Both are in Windows 7. Beforehand, I created a file called testfile and a folder called testfolder.

In Python 2.7, os.symlink is not available, so I need to create the symlinks via plumbum. I tested os.rmdir for the file symlink to see if perchance rmdir might be used for both cases (it can't).

Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, plumbum
>>> plumbum.local.path('testfile').symlink('filelink')
>>> os.rmdir('filelink')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 267] The directory name is invalid: 'filelink'
>>> os.unlink('filelink')
** filelink was deleted **
>>> plumbum.local.path('testfolder').symlink('folderlink')
>>> os.unlink('folderlink')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 5] Access is denied: 'folderlink'
>>> os.rmdir('folderlink')
** folderlink was deleted **

In Python 3.4, os.symlink is available and os.unlink works for symlinks to both files and folders, so no trouble there:

Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.symlink('testfile', 'filelink')
>>> os.unlink('filelink')
** filelink was deleted **
>>> os.symlink('testfolder', 'folderlink')
>>> os.unlink('folderlink')
** folderlink was deleted **

Another course I considered was that some other LocalPath method might work, e.g. I could just call LocalPath.delete(path) for symlinks. This unfortunately doesn't work, as I wind up at

shutil.rmtree(str(self))
, and shutil.rmtree on Windows deletes not just the symlink but also the entire folder that the symlink points to (eek).

PS: Thanks for making this awesome library!

@tillberg tillberg force-pushed the symlink-unlink-windows branch from 228140b to 55c24b6 Compare July 9, 2015 21:42
@tillberg tillberg force-pushed the symlink-unlink-windows branch from 55c24b6 to f32e372 Compare July 9, 2015 21:44
tomerfiliba added a commit that referenced this pull request Jul 10, 2015
Enable unlinking of symbolic links to folders in Windows
@tomerfiliba tomerfiliba merged commit 051265e into tomerfiliba:master Jul 10, 2015
@tillberg tillberg deleted the symlink-unlink-windows branch July 10, 2015 16:56
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.

3 participants