Python library to natively send files to Trash (or Recycle bin) on all platforms.

Overview

Send2Trash -- Send files to trash on all platforms

Send2Trash is a small package that sends files to the Trash (or Recycle Bin) natively and on all platforms. On OS X, it uses native FSMoveObjectToTrashSync Cocoa calls. On Windows, it uses native IFileOperation call if on Vista or newer and pywin32 is installed or falls back to SHFileOperation calls. On other platforms, if PyGObject and GIO are available, it will use this. Otherwise, it will fallback to its own implementation of the trash specifications from freedesktop.org.

ctypes is used to access native libraries, so no compilation is necessary.

Send2Trash supports Python 2.7 and up (Python 3 is supported).

Status: Additional Help Welcome

Additional help is welcome for supporting this package. Specifically help with the OSX and Linux issues and fixes would be most appreciated.

Installation

You can download it with pip:

python -m pip install -U send2trash

or you can download the source from http://github.com/arsenetar/send2trash and install it with:

>>> python setup.py install

Usage

>>> from send2trash import send2trash
>>> send2trash('some_file')
>>> send2trash(['some_file1', 'some_file2'])

On Freedesktop platforms (Linux, BSD, etc.), you may not be able to efficiently trash some files. In these cases, an exception send2trash.TrashPermissionError is raised, so that the application can handle this case. This inherits from PermissionError (OSError on Python 2). Specifically, this affects files on a different device to the user's home directory, where the root of the device does not have a .Trash directory, and we don't have permission to create a .Trash-$UID directory.

For any other problem, OSError is raised.

Comments
  • Windows Performance Improvement & Multi-Item support

    Windows Performance Improvement & Multi-Item support

    • Use pywin32 to implement IFileOperation
    • Add ability to allow passing a list of files to send2trash across all platforms
    • Batch trash operations on windows for both IFileOperation and SHFileOperation

    Notes:

    • My code format plugin formatted the contents of the files I changed, let me know if this is an issue and I can back those out (it fixed some flake8 style issues as well)
    • IFileOperation should open up the ability to address #28 but I'll add in the extras for that in another PR.
    opened by arsenetar 11
  • Fails with python 3.6.3 on windows

    Fails with python 3.6.3 on windows

    I get the following when calling send2trash on python 3.6.3 on windows 7: File "...\AppData\Local\Programs\Python\Python36\lib\site-packages\send2trash\plat_win.py", line 49, in send2trash fileop.pFrom = LPCWSTR(path + '\0') ValueError: embedded null character

    I'm pretty sure it didn't fail until I switched to 3.6.3. My guess is that this fix is responsible.

    opened by rkhwaja 11
  • Error while running send2trash on Python 3.7.0 beta 2

    Error while running send2trash on Python 3.7.0 beta 2

    I have a small script that uses send2trash and works very well in Python 3.6 (Mac OS X 10.11 El Capitan). However, when I try to run it in Python 3.7.0 beta 2, it fails with the traceback bellow.

    best regards, victor

    Traceback (most recent call last):
      File "/Users/fact/Dropbox/Aplicativos/Filemaker_backups/NPK-Backup/remove_old_archives.py", line 26, in <module>
        from send2trash import send2trash
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/send2trash/__init__.py", line 12, in <module>
        from .plat_osx import send2trash
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/send2trash/plat_osx.py", line 17, in <module>
        GetMacOSStatusCommentString = Foundation.GetMacOSStatusCommentString
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 369, in __getattr__
        func = self.__getitem__(name)
      File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ctypes/__init__.py", line 374, in __getitem__
        func = self._FuncPtr((name_or_ordinal, self))
    AttributeError: dlsym(RTLD_DEFAULT, GetMacOSStatusCommentString): symbol not found
    
    opened by victordomingos 9
  • Use bytes paths in plat_other

    Use bytes paths in plat_other

    This fixes issues with non-ascii paths when using the fallback freedesktop trash implementation.

    This is a rather ugly set of changes, but it's based on two things:

    1. urllib.quote() on Python 2 requires bytes. On Python 3, it can handle unicode or bytes.
    2. Paths on Unix filesystems are really bytes. We can usually represent them as unicode, but for 100% fidelity, they should be passed around as bytes.

    So this is a complete switch around from #12: rather than converting all paths to unicode when they're passed in, convert them all to bytes.

    I added tests for passing in a path as unicode or as bytes. Before the changes, both tests fail under Python 2. Afterwards, everything passes, on both versions of Python.

    opened by takluyver 9
  • "OSError: [Errno 120] This function is not supported by the system."

    Hi! Whenever I try running create_project.py i get this error:

    Traceback (most recent call last):
      File "test_project.py", line 14, in <module>
        add_on = create_project.CreateProject( "myaddon","mya")  #This Class Will create the project
      File "C:\Users\Retcy\Downloads\8. Coding Fun\neptune_api\neptune_lib\core\create_project.py", line 108, in __init__
        send2trash.send2trash(self.name)
      File "C:\Users\Retcy\AppData\Local\Programs\Python\Python37-32\lib\site-packages\send2trash\plat_win_legacy.py", line 146, in send2trash
        raise WindowsError(result, FormatError(result), paths)
    OSError: [Errno 120] This function is not supported by the system.: ['C:\\Users\\Retcy\\DOWNLO~1\\8. Coding Fun\\neptune_api\\builds\\myaddon'] 
    

    Code: create_project.txt

    opened by retr0cube 7
  • File not move to Recycle Bin in Windows

    File not move to Recycle Bin in Windows

    I try to use send2trash('file_path') but file still not move to my Recycle Bin with no any error message.

    It's look like the issue came from get_short_path_name() because it return u'' But when I bypass get_short_path_name() method, send2trash() seem working for me.

    def get_short_path_name(long_name):
        return long_name
        # if not long_name.startswith('\\\\?\\'):
        #     long_name = '\\\\?\\' + long_name
        # buf_size = GetShortPathNameW(long_name, None, 0)
        # output = create_unicode_buffer(buf_size)
        # GetShortPathNameW(long_name, output, buf_size)
        # return output.value[4:]  # Remove '\\?\' for SHFileOperationW
    

    I'm using python 2.7.14 on Windows 10.0.16299 .

    opened by Shayen 7
  • 🚧 WIP: macOS trash

    🚧 WIP: macOS trash "put back" feature [ctypes]

    This is a WIP!


    This is my initial attempt at using ctypes, just putting it up online so we have a record of it, and also to help catch if I've done anything wrong.

    I was hopeful about the progress I was making, until I came across some hurdles that have blocked this approach. At the moment running it causes a segmentation fault (I believe because of the incorrectly initialised AEDesc). We need:

    • Need to find a way to initialise:
      • [ ] AEDesc
      • [ ] AEDataStorage
    • Need to confirm how the following values should be defined:
      • [ ] typeKernelProcessID
      • [ ] typeWildCard
      • [ ] keyDirectObject
      • [ ] pid_t

    If this turns out to be too arch-dependent, or too much of a hack, I'll open a different PR using some compiled Objective-C.

    Fixes #9.

    /cc @BoboTiG @hsoft

    opened by acheronfail 7
  • ImportError: no module named mac

    ImportError: no module named mac

    After cloning the directory, entering it, and typing 'pip install .' I got what seemed to be a successful build and install, ending in:

    Successfully built Send2Trash
    Installing collected packages: Send2Trash
    Successfully installed Send2Trash-1.8.1b0
    

    But when I try to run my Python 2.7 script I get an error message:

    Traceback (most recent call last):
      File "/Users/larryy/Dropbox/src/file_rename.py", line 8, in <module>
        from send2trash import send2trash
      File "/usr/local/lib/python2.7/site-packages/send2trash/__init__.py", line 12, in <module>
        from .mac import send2trash
    ImportError: No module named mac
    

    As shown, the line of code in question is a standard import:

    from send2trash import send2trash
    

    This is macOS Monterey 12.4 (latest) and the latest Send2Trash (1.8.1b0). Apologies if I've just done something stupid setting things up.

    opened by larryy 6
  • Add CLI Using __main__.py

    Add CLI Using __main__.py

    Great project. I wish this functionality were included in the standard library. Thank you.

    I'm curious how the methodology here compares with this JavaScript package: https://github.com/sindresorhus/trash

    If you have time, what are your thoughts?

    opened by grantjenks 6
  • Fix Windows compatibility with multithreading

    Fix Windows compatibility with multithreading

    Hi.

    I've faced with some tests of Jupyterhub Notebook repo are failing:

    Traceback (most recent call last):
      File "c:\hostedtoolcache\windows\python\3.6.8\x64\lib\site-packages\tornado\web.py", line 1704, in _execute
        result = await result
      File "c:\hostedtoolcache\windows\python\3.6.8\x64\lib\site-packages\tornado\gen.py", line 234, in wrapper
        yielded = ctx_run(next, result)
      File "c:\hostedtoolcache\windows\python\3.6.8\x64\lib\site-packages\tornado\gen.py", line 162, in _fake_ctx_run
        return f(*args, **kw)
      File "D:\a\notebook\notebook\notebook\services\contents\handlers.py", line 237, in delete
        yield maybe_future(cm.delete(path))
      File "D:\a\notebook\notebook\notebook\services\contents\manager.py", line 279, in delete
        self.delete_file(path)
      File "D:\a\notebook\notebook\notebook\services\contents\filemanager.py", line 533, in delete_file
        send2trash(os_path)
      File "c:\hostedtoolcache\windows\python\3.6.8\x64\lib\site-packages\send2trash\plat_win_modern.py", line 31, in send2trash
        shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation,
    pywintypes.com_error: (-2147221008, 'CoInitialize has not been called.', None, None)
    

    According to https://stackoverflow.com/questions/37258257/why-does-this-script-not-work-with-threading-python, it is important to call .CoInitialize() method to allow win32 API calls in multithread mode.

    opened by dolfinus 5
  • fix trash_move

    fix trash_move

    the same as https://github.com/arsenetar/send2trash/pull/41

    this bug prevents using jupyter* in research environments where file systems aren't always local

    e.g. https://github.com/jupyterlab/jupyterlab/issues/5781 and our own use at https://cri.uchicago.edu/

    cc @annawoodard

    opened by makslevental 4
  • Can't delete files or folders on OneDrive

    Can't delete files or folders on OneDrive

    I'm using JupyterLab and OneDrive on an M1 Macbook Air with Macos 12.6.1. I get an OSError when trying to delete a file or folder on Onedrive with JupyterLab. Maybe OneDrive's Files On-Demand is causing the problem.

          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/tornado/web.py", line 1713, in _execute
            result = await result
          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/jupyter_server/services/contents/handlers.py", line 275, in delete
            await ensure_async(cm.delete(path))
          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/jupyter_server/services/contents/manager.py", line 417, in delete
            self.delete_file(path)
          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/jupyter_server/services/contents/filemanager.py", line 511, in delete_file
            send2trash(os_path)
          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/send2trash/plat_osx_pyobjc.py", line 29, in send2trash
            check_op_result(op_result)
          File "/opt/homebrew/Caskroom/mambaforge/base/lib/python3.10/site-packages/send2trash/plat_osx_pyobjc.py", line 16, in check_op_result
            raise OSError(op_result[2].localizedFailureReason())
        OSError: None```
    opened by peccator085 0
  • Failed to move files to trash in overlayfs

    Failed to move files to trash in overlayfs

    In overlayfs, directories always have st_dev from lower filesystem whereas files can have st_dev either from lower filesystem or upper filesystem. Due to this behavior, https://github.com/arsenetar/send2trash/blob/1.8.1b0/send2trash/plat_other.py#L178 always fails when the file's st_dev is from the upper filesystem. gio already tackled this issue, by avoiding comparison b/w file_dev and trash_dev, instead, it compares parent_dir(file).dev to trash_dev (ref: https://gitlab.gnome.org/GNOME/glib/-/blob/main/gio/glocalfile.c#L2019). I think send2trash also can adapt the same approach.

    opened by pjknkda 1
  • Module not callable

    Module not callable

    Working through the Automate the Boring stuff book and came across Send2Trash. Tried following the tutorial but found that the module was not callable.

    my code is

    send to trash

    I am doing this in VSCode and pylint keeps giving the error that the module is not callable:

    I have tried reinstalling send2trash and restarting the computer.

    opened by PeterCLarsen 1
  • send2trash function failed to delete a directory with unknown error

    send2trash function failed to delete a directory with unknown error

    This function is referred in Jupyter server folder deletion logic. We observed the error in jupyterlab app and here in this description we try to simplify the scenario and reproduce it in a windows command prompt.

    In python interpreter, we import the send2trash: from send2trash import send2trash

    And run this code line, deleting the directory: send2trash('C:\\Users\\traveler\\AppData\\Local\\projects\\Untitled Folder') In this case the "Untitled Folder" is newly created under a jlabapp project and there is a newly created ipynb file in it, it failed to delete "Untitled Folder" and throws message:

    >>> send2trash('C:\Users\traveler\AppData\Local\projects\Untitled Folder') Traceback (most recent call last): File "C:\Users\traveler\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\send2trash\plat_win_modern.py", line 61, in send2trash result = fileop.PerformOperations() pywintypes.com_error: (-2144927705, 'OLE error 0x80270027', None, None)

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last): File "", line 1, in File "C:\Users\traveler\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\send2trash\plat_win_modern.py", line 69, in send2trash raise OSError(None, error.strerror, path, error.hresult) OSError: [WinError -2144927705] OLE error 0x80270027: 'C:\Users\traveler\AppData\Local\projects\Untitled Folder'

    However, when we close the project tab and reopen it. The above code line (exactly the same func and path) works and was able to delete "Untitled Folder".

    Watching "Untitled Folder" in File Explorer and it seems there is no visible difference between the above two cases.

    opened by WentingTan 2
  • Five tests error/fail in a testing chroot on Linux with bizarre error messages

    Five tests error/fail in a testing chroot on Linux with bizarre error messages

    Hi! As part of the Debian build, the package tests are run in a minimal chroot environment. I've set the HOME environment variable first:

    (sid-sbuild)[email protected]:/build/send2trash-IKQvlF/send2trash-1.8.1~b0$ export HOME=$(mktemp -p)
    (sid-sbuild)[email protected]:/build/send2trash-IKQvlF/send2trash-1.8.1~b0$ echo $HOME
    /tmp/tmp.CSc9dofzh7/
    (sid-sbuild)[email protected]:/build/send2trash-IKQvlF/send2trash-1.8.1~b0$ mkdir -p $HOME/.local/share/Trash
    (sid-sbuild)[email protected]:/build/send2trash-IKQvlF/send2trash-1.8.1~b0$ dpkg-buildpackage -b -us -uc
    dpkg-buildpackage: info: source package send2trash
    dpkg-buildpackage: info: source version 1.8.1~b0-1
    dpkg-buildpackage: info: source distribution unstable
    dpkg-buildpackage: info: source changed by Julian Gilbey <[email protected]>
    dpkg-buildpackage: info: host architecture amd64
    [... build the python package, snipped ...]
    Successfully built Send2Trash-1.8.1b0-py3-none-any.whl
    I: pybuild plugin_pyproject:123: Unpacking wheel built for python3.10 with "installer" module
    [... do the same for Python 3.9, snipped ...]
    Successfully built Send2Trash-1.8.1b0-py3-none-any.whl
    I: pybuild plugin_pyproject:123: Unpacking wheel built for python3.9 with "installer" module
       dh_auto_test -O--buildsystem=pybuild
    I: pybuild base:237: cd '/build/send2trash-IKQvlF/send2trash-1.8.1~b0/.pybuild/cpython3_3.10/build'; python3.10 -m pytest tests
    ============================= test session starts ==============================
    platform linux -- Python 3.10.2, pytest-6.2.5, py-1.10.0, pluggy-0.13.0
    rootdir: /build/send2trash-IKQvlF/send2trash-1.8.1~b0/.pybuild/cpython3_3.10/build
    collected 10 items / 1 skipped / 9 selected                                    
    
    tests/test_plat_other.py ....FFFEF                                       [ 80%]
    tests/test_script_main.py ..                                             [100%]
    
    ==================================== ERRORS ====================================
    ________________ ERROR at teardown of test_trash_topdir_failure ________________
    
        @pytest.fixture
        def testExtVol():
            trashTopdir = mkdtemp(prefix="s2t")
            volume = ExtVol(trashTopdir)
            fileName = "test.txt"
            filePath = op.join(volume.trashTopdir, fileName)
            touch(filePath)
            assert op.exists(filePath) is True
            yield volume, fileName, filePath
    >       volume.cleanup()
    
    tests/test_plat_other.py:156: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    tests/test_plat_other.py:144: in cleanup
        shutil.rmtree(self.trashTopdir)
    /usr/lib/python3.10/shutil.py:717: in rmtree
        _rmtree_safe_fd(fd, path, onerror)
    /usr/lib/python3.10/shutil.py:674: in _rmtree_safe_fd
        onerror(os.unlink, fullname, sys.exc_info())
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    topfd = 11, path = '/tmp/s2tw916afk4'
    onerror = <function rmtree.<locals>.onerror at 0x7fa2915feef0>
    
        def _rmtree_safe_fd(topfd, path, onerror):
            try:
                with os.scandir(topfd) as scandir_it:
                    entries = list(scandir_it)
            except OSError as err:
                err.filename = path
                onerror(os.scandir, path, sys.exc_info())
                return
            for entry in entries:
                fullname = os.path.join(path, entry.name)
                try:
                    is_dir = entry.is_dir(follow_symlinks=False)
                except OSError:
                    is_dir = False
                else:
                    if is_dir:
                        try:
                            orig_st = entry.stat(follow_symlinks=False)
                            is_dir = stat.S_ISDIR(orig_st.st_mode)
                        except OSError:
                            onerror(os.lstat, fullname, sys.exc_info())
                            continue
                if is_dir:
                    try:
                        dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
                    except OSError:
                        onerror(os.open, fullname, sys.exc_info())
                    else:
                        try:
                            if os.path.samestat(orig_st, os.fstat(dirfd)):
                                _rmtree_safe_fd(dirfd, fullname, onerror)
                                try:
                                    os.rmdir(entry.name, dir_fd=topfd)
                                except OSError:
                                    onerror(os.rmdir, fullname, sys.exc_info())
                            else:
                                try:
                                    # This can only happen if someone replaces
                                    # a directory with a symlink after the call to
                                    # os.scandir or stat.S_ISDIR above.
                                    raise OSError("Cannot call rmtree on a symbolic "
                                                  "link")
                                except OSError:
                                    onerror(os.path.islink, fullname, sys.exc_info())
                        finally:
                            os.close(dirfd)
                else:
                    try:
    >                   os.unlink(entry.name, dir_fd=topfd)
    E                   PermissionError: [Errno 13] Permission denied: 'test.txt'
    
    /usr/lib/python3.10/shutil.py:672: PermissionError
    =================================== FAILURES ===================================
    ______________________________ test_trash_topdir _______________________________
    
    testExtVol = (<tests.test_plat_other.ExtVol object at 0x7fa2915df430>, 'test.txt', '/tmp/s2t1_l_qvbt/test.txt')
    
        def test_trash_topdir(testExtVol):
            trashDir = op.join(testExtVol[0].trashTopdir, ".Trash")
            os.mkdir(trashDir, 0o777 | stat.S_ISVTX)
        
    >       s2t(testExtVol[2])
    
    tests/test_plat_other.py:163: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    send2trash/plat_other.py:213: in send2trash
        dest_trash = find_ext_volume_trash(topdir)
    send2trash/plat_other.py:169: in find_ext_volume_trash
        trash_dir = find_ext_volume_fallback_trash(volume_root)
    send2trash/plat_other.py:158: in find_ext_volume_fallback_trash
        check_create(trash_dir)
    send2trash/plat_other.py:96: in check_create
        os.makedirs(dir, 0o700)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    name = b'/tmp/s2t1_l_qvbt/test.txt/.Trash-1000', mode = 448, exist_ok = False
    
        def makedirs(name, mode=0o777, exist_ok=False):
            """makedirs(name [, mode=0o777][, exist_ok=False])
        
            Super-mkdir; create a leaf directory and all intermediate ones.  Works like
            mkdir, except that any intermediate path segment (not just the rightmost)
            will be created if it does not exist. If the target directory already
            exists, raise an OSError if exist_ok is False. Otherwise no exception is
            raised.  This is recursive.
        
            """
            head, tail = path.split(name)
            if not tail:
                head, tail = path.split(head)
            if head and tail and not path.exists(head):
                try:
                    makedirs(head, exist_ok=exist_ok)
                except FileExistsError:
                    # Defeats race condition when another thread created the path
                    pass
                cdir = curdir
                if isinstance(tail, bytes):
                    cdir = bytes(curdir, 'ASCII')
                if tail == cdir:           # xxx/newdir/. exists if xxx/newdir exists
                    return
            try:
    >           mkdir(name, mode)
    E           NotADirectoryError: [Errno 20] Not a directory: b'/tmp/s2t1_l_qvbt/test.txt/.Trash-1000'
    
    /usr/lib/python3.10/os.py:225: NotADirectoryError
    __________________________ test_trash_topdir_fallback __________________________
    
    testExtVol = (<tests.test_plat_other.ExtVol object at 0x7fa291497a60>, 'test.txt', '/tmp/s2tmx3ups_b/test.txt')
    
        def test_trash_topdir_fallback(testExtVol):
    >       s2t(testExtVol[2])
    
    tests/test_plat_other.py:175: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    send2trash/plat_other.py:213: in send2trash
        dest_trash = find_ext_volume_trash(topdir)
    send2trash/plat_other.py:169: in find_ext_volume_trash
        trash_dir = find_ext_volume_fallback_trash(volume_root)
    send2trash/plat_other.py:158: in find_ext_volume_fallback_trash
        check_create(trash_dir)
    send2trash/plat_other.py:96: in check_create
        os.makedirs(dir, 0o700)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    name = b'/tmp/s2tmx3ups_b/test.txt/.Trash-1000', mode = 448, exist_ok = False
    
        def makedirs(name, mode=0o777, exist_ok=False):
            """makedirs(name [, mode=0o777][, exist_ok=False])
        
            Super-mkdir; create a leaf directory and all intermediate ones.  Works like
            mkdir, except that any intermediate path segment (not just the rightmost)
            will be created if it does not exist. If the target directory already
            exists, raise an OSError if exist_ok is False. Otherwise no exception is
            raised.  This is recursive.
        
            """
            head, tail = path.split(name)
            if not tail:
                head, tail = path.split(head)
            if head and tail and not path.exists(head):
                try:
                    makedirs(head, exist_ok=exist_ok)
                except FileExistsError:
                    # Defeats race condition when another thread created the path
                    pass
                cdir = curdir
                if isinstance(tail, bytes):
                    cdir = bytes(curdir, 'ASCII')
                if tail == cdir:           # xxx/newdir/. exists if xxx/newdir exists
                    return
            try:
    >           mkdir(name, mode)
    E           NotADirectoryError: [Errno 20] Not a directory: b'/tmp/s2tmx3ups_b/test.txt/.Trash-1000'
    
    /usr/lib/python3.10/os.py:225: NotADirectoryError
    __________________________ test_trash_topdir_failure ___________________________
    
    testExtVol = (<tests.test_plat_other.ExtVol object at 0x7fa2914756c0>, 'test.txt', '/tmp/s2tw916afk4/test.txt')
    
        def test_trash_topdir_failure(testExtVol):
            os.chmod(testExtVol[0].trashTopdir, 0o500)  # not writable to induce the exception
    >       pytest.raises(TrashPermissionError, s2t, [testExtVol[2]])
    
    tests/test_plat_other.py:182: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    send2trash/plat_other.py:213: in send2trash
        dest_trash = find_ext_volume_trash(topdir)
    send2trash/plat_other.py:169: in find_ext_volume_trash
        trash_dir = find_ext_volume_fallback_trash(volume_root)
    send2trash/plat_other.py:158: in find_ext_volume_fallback_trash
        check_create(trash_dir)
    send2trash/plat_other.py:96: in check_create
        os.makedirs(dir, 0o700)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    name = b'/tmp/s2tw916afk4/test.txt/.Trash-1000', mode = 448, exist_ok = False
    
        def makedirs(name, mode=0o777, exist_ok=False):
            """makedirs(name [, mode=0o777][, exist_ok=False])
        
            Super-mkdir; create a leaf directory and all intermediate ones.  Works like
            mkdir, except that any intermediate path segment (not just the rightmost)
            will be created if it does not exist. If the target directory already
            exists, raise an OSError if exist_ok is False. Otherwise no exception is
            raised.  This is recursive.
        
            """
            head, tail = path.split(name)
            if not tail:
                head, tail = path.split(head)
            if head and tail and not path.exists(head):
                try:
                    makedirs(head, exist_ok=exist_ok)
                except FileExistsError:
                    # Defeats race condition when another thread created the path
                    pass
                cdir = curdir
                if isinstance(tail, bytes):
                    cdir = bytes(curdir, 'ASCII')
                if tail == cdir:           # xxx/newdir/. exists if xxx/newdir exists
                    return
            try:
    >           mkdir(name, mode)
    E           NotADirectoryError: [Errno 20] Not a directory: b'/tmp/s2tw916afk4/test.txt/.Trash-1000'
    
    /usr/lib/python3.10/os.py:225: NotADirectoryError
    ______________________________ test_trash_symlink ______________________________
    
    testExtVol = (<tests.test_plat_other.ExtVol object at 0x7fa2915da8c0>, 'test.txt', '/tmp/s2t9qns8us6/test.txt')
    
        def test_trash_symlink(testExtVol):
            # Use mktemp (race conditioney but no symlink equivalent)
            # Since is_parent uses realpath(), and our getdev uses is_parent,
            # this should work
            slDir = mktemp(prefix="s2t", dir=op.expanduser("~"))
            os.mkdir(op.join(testExtVol[0].trashTopdir, "subdir"), 0o700)
            filePath = op.join(testExtVol[0].trashTopdir, "subdir", testExtVol[1])
            touch(filePath)
            os.symlink(op.join(testExtVol[0].trashTopdir, "subdir"), slDir)
    >       s2t(op.join(slDir, testExtVol[1]))
    
    tests/test_plat_other.py:195: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    send2trash/plat_other.py:213: in send2trash
        dest_trash = find_ext_volume_trash(topdir)
    send2trash/plat_other.py:169: in find_ext_volume_trash
        trash_dir = find_ext_volume_fallback_trash(volume_root)
    send2trash/plat_other.py:158: in find_ext_volume_fallback_trash
        check_create(trash_dir)
    send2trash/plat_other.py:96: in check_create
        os.makedirs(dir, 0o700)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    name = b'/tmp/s2t9qns8us6/subdir/test.txt/.Trash-1000', mode = 448
    exist_ok = False
    
        def makedirs(name, mode=0o777, exist_ok=False):
            """makedirs(name [, mode=0o777][, exist_ok=False])
        
            Super-mkdir; create a leaf directory and all intermediate ones.  Works like
            mkdir, except that any intermediate path segment (not just the rightmost)
            will be created if it does not exist. If the target directory already
            exists, raise an OSError if exist_ok is False. Otherwise no exception is
            raised.  This is recursive.
        
            """
            head, tail = path.split(name)
            if not tail:
                head, tail = path.split(head)
            if head and tail and not path.exists(head):
                try:
                    makedirs(head, exist_ok=exist_ok)
                except FileExistsError:
                    # Defeats race condition when another thread created the path
                    pass
                cdir = curdir
                if isinstance(tail, bytes):
                    cdir = bytes(curdir, 'ASCII')
                if tail == cdir:           # xxx/newdir/. exists if xxx/newdir exists
                    return
            try:
    >           mkdir(name, mode)
    E           NotADirectoryError: [Errno 20] Not a directory: b'/tmp/s2t9qns8us6/subdir/test.txt/.Trash-1000'
    
    /usr/lib/python3.10/os.py:225: NotADirectoryError
    =========================== short test summary info ============================
    FAILED tests/test_plat_other.py::test_trash_topdir - NotADirectoryError: [Err...
    FAILED tests/test_plat_other.py::test_trash_topdir_fallback - NotADirectoryEr...
    FAILED tests/test_plat_other.py::test_trash_topdir_failure - NotADirectoryErr...
    FAILED tests/test_plat_other.py::test_trash_symlink - NotADirectoryError: [Er...
    ERROR tests/test_plat_other.py::test_trash_topdir_failure - PermissionError: ...
    =============== 4 failed, 6 passed, 1 skipped, 1 error in 0.20s ================
    E: pybuild pybuild:367: test: plugin pyproject failed with: exit code=1: cd '/build/send2trash-IKQvlF/send2trash-1.8.1~b0/.pybuild/cpython3_3.10/build'; python3.10 -m pytest tests
    [... similar errors with Python 3.9 snipped ...]
    

    The thing that seems so weird to me is the strange filenames/directories it's trying to work with, such as b'/tmp/s2t9qns8us6/subdir/test.txt/.Trash-1000'. It strikes me that something has gone wrong in the calculation of the trash directory name. (And there's no sign of the HOME directory I so carefully set up!)

    opened by juliangilbey 7
Releases(1.8.1b0)
  • 1.8.1b0(Aug 21, 2021)

  • 1.8.0(Aug 9, 2021)

    • Add compatibility with pathlib paths (#49)
    • Fix thread compatibility of modern windows implementation (#59)
    • Fix handling of UNC names in legacy windows implementation (#57)
    Source code(tar.gz)
    Source code(zip)
  • 1.7.1(Jun 23, 2021)

    • Release stable version with changes from last 3 releases including:
      • Changed conditional for when to try to use pyobjc version (#51)
      • Add console_script entry point (#50)
      • Increased python CI versions (#52, #54)
      • Fix minor issue in setup.py (#53)
      • Fix issue with windows tests importing modules on non-windows (#55)
      • Unit test cleanups, rewrites, and flake8 cleanups
      • Windows: Fix legacy windows platform for multi-byte unicode and add tests
      • macOS: Add alternative pyobjc version to potentially improve compatibility (#51)
      • Add main method which allows calling via python -m send2trash somefile
      • Windows: Add support for using IFileOperation when pywin32 is present on Vista and newer
      • Add support for passing multiple files at once in a list
      • Windows: Batch multi-file calls to improve performance (#42)
      • Windows: Fix issue with SHFileOperation failing silently when path is not found (#33)
    • Fix handling of UNC names (#57)
    Source code(tar.gz)
    Source code(zip)
  • 1.7.0a1(Jun 23, 2021)

  • 1.7.0a0(Jun 23, 2021)

    • Add console_script entry point (#50)
    • Increased python CI versions (#52, #54)
    • Fix minor issue in setup.py (#53)
    • Fix issue with windows tests importing modules on non-windows (#55)
    • Unit test cleanups, rewrites, and flake8 cleanups
    • Windows: Fix legacy windows platform for multi-byte unicode and add tests
    • macOS: Add alternative pyobjc version to potentially improve compatibility (#51)
    Source code(tar.gz)
    Source code(zip)
  • 1.6.0b1(Jun 19, 2020)

    This is a beta version including the following changes:

    • Add main method which allows calling via python -m send2trash somefile
    • Windows: Add support for using IFileOperation when pywin32 is present on Vista and newer
    • Add support for passing multiple files at once in a list
    • Windows: Batch multi-file calls to improve performance (#42)
    • Windows: Fix issue with SHFileOperation failing silently when path is not found (#33)
    Source code(tar.gz)
    Source code(zip)
Owner
Andrew Senetar
Andrew Senetar
Flames Calculater App used to calculate flames status between two names created using python's Flask web framework.

Flames Finder Web App Flames Calculater App used to calculate flames status between two names created using python's Flask web framework. First, App g

Siva Prakash 4 Jan 02, 2022
Pyjiting is a experimental Python-JIT compiler, which is the product of my undergraduate thesis

Pyjiting is a experimental Python-JIT compiler, which is the product of my undergraduate thesis. The goal is to implement a light-weight miniature general-purpose Python JIT compiler.

Lance.Moe 10 Apr 17, 2022
Tiling manager which runs on top of EWMH window managers.

PyTyle is an extremely versatile and extensible tiling manager that is meant to be used on top of EWMH window managers. Its feature set was modeled af

55 Jul 29, 2021
🔵Open many google dorks in a fasted way

Dorkinho 🔵 The author is not responsible for misuse of the tool, use it in good practices like Pentest and CTF OSINT challenges. Dorkinho is a script

SidHawks 2 May 02, 2022
Rotazioni: a linear programming workout split optimizer

Rotazioni: a linear programming workout split optimizer Dependencies Dependencies for the frontend and backend are respectively listed in client/packa

Marco 3 Oct 13, 2022
Automated GitHub profile content using the USGS API, Plotly and GitHub Actions.

Top 20 Largest Earthquakes in the Past 24 Hours Location Mag Date and Time (UTC) 92 km SW of Sechura, Peru 5.2 11-05-2021 23:19:50 113 km NNE of Lobuj

Mr. Phantom 28 Oct 31, 2022
Pulse sequence builder and compiler for q1asm

q1pulse Pulse sequence builder and compiler for q1asm. q1pulse is a simple library to compile pulse sequence to q1asm, the assembly language of Qblox

Sander de Snoo 3 Dec 14, 2022
Заглушки .NET библиотек для IronPython

Код репозитория основан на ironpython-stubs. Выражаю gtalarico бесконечную благодарность за вклад в развитие сообщества разработчиков скриптов и плаги

12 Nov 23, 2022
Manipulation OpenAI Gym environments to simulate robots at the STARS lab

liegroups Python implementation of SO2, SE2, SO3, and SE3 matrix Lie groups using numpy or PyTorch. [Documentation] Installation To install, cd into t

STARS Laboratory 259 Dec 11, 2022
March-madness - March Madness results 1985-2021

march-madness Results for all 2,268 NCAA Division I Men's Basketball Tournament games since the modern format was introduced in 1985. Includes years,

Darik Harter 2 Feb 26, 2022
Traffic flow test platform, especially for reinforcement learning

Traffic Flow Test Platform Traffic flow test platform, especially for reinforcement learning, named TFTP. A traffic signal control framework that can

4 Nov 07, 2022
Small projects for python beginners.

Python Mini Projects For Beginners I recently started doing the #100DaysOfCode Challenge in Python. I've used Python before, but I had switched to JS

Sreekesh Iyer 10 Dec 12, 2022
Change ACLs for QNAP LXD unprivileged container.

qnaplxdunpriv If Advanced Folder Permissions is enabled in QNAP NAS, unprivileged LXD containers won't start. qnaplxdunpriv changes ACLs of some Conta

1 Jan 10, 2022
A streaming animation of all the edits to a given Wikipedia page.

WikiFilms! What is it? A streaming animation of all the edits to a given Wikipedia page. How it works. It works by creating a "virtual camera," which

Tal Zaken 2 Jan 18, 2022
Course materials for a 3-day seminar "Machine Learning and NLP: Advances and Applications" at New College of Florida

Machine Learning and NLP: Advances and Applications This repository hosts the course materials used for a 3-day seminar "Machine Learning and NLP: Adv

Yoshi Suhara 11 Jun 22, 2022
Scripts to integrate DFIR-IRIS, MISP and TimeSketch

Scripts to integrate DFIR-IRIS, MISP and TimeSketch

Koen Van Impe 20 Dec 16, 2022
Data on Free Food at MIT

MIT Free Food Timing Procrastinating research by plotting data on how long it takes emails on the free-food at mit edu mailing list to go through. Dat

Peter Sharpe 2 Nov 01, 2021
Aerial Ace is a helper bot for poketwo which provide various functionalities on top of being a pokedex.

Aerial Ace is a helper bot for poketwo which provide various functionalities on top of being a pokedex.

Devanshu Mishra 1 Dec 01, 2021
Choice Coin 633 Dec 23, 2022
A minimalist personal blogging system that natively supports Markdown, LaTeX, and code highlighting.

December Welcome to the December blogging system's code repository! Introduction December is a minimalist personal blogging system that natively suppo

TriNitroTofu 10 Dec 05, 2022