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
A repository of study materials related to Think Python 2nd Edition by Allen B. Downey. More information about the book can be found here: https://greenteapress.com/wp/think-python-2e/

Intro-To-Python This content is based on the book Think Python 2nd Edition by Allen B. Downey. More information about the book can be found here: http

Brent Eskridge 63 Jan 07, 2023
A script to generate NFT art living on the Solana blockchain.

NFT Generator This script generates NFT art based on its desired traits with their specific rarities. It has been used to generate the full collection

Rude Golems 24 Oct 08, 2022
It really seems like Trump is trying to get his own social media started. Not a huge fan tbh.

FuckTruthSocial It really seems like Trump is trying to get his own social media started. Not a huge fan tbh. (When TruthSocial actually releases, I'l

0 Jul 18, 2022
Um sistema de llogin feito em uma interface grafica.

Interface-para-login Um sistema de login feito com JSON. Utilizando a biblioteca Tkinter, eu criei um sistema de login, onde guarda a informações de l

Mobben 1 Nov 28, 2021
Create rangebased on lists or values of the range itself. Range any type. Can you imagine?

funcao-allrange-for-python3 Create rangebased on lists or values of the range itself. Range any type. Can you imagine? WARNING!!! THIS MODULE DID NOT

farioso-fernando 1 Feb 09, 2022
A simple PID tuner and simulator.

PIDtuner-V0.1 PlantPy PID tuner version 0.1 Features Supports first order and ramp process models. Supports Proportional action on PV or error or a sp

3 Jun 23, 2022
UniPD exam dates finder

UniPD exam dates finder Find dates for exams at UniPD Usage ./finder.py courses.csv It's suggested to save output to a file: ./finder.py courses.csv

Davide Peressoni 1 Jan 25, 2022
Wagtail + Lottie is a Wagtail package for playing Adobe After Effects animations exported as json with Bodymovin.

Wagtail Lottie Wagtail + Lottie is a Wagtail package for playing Adobe After Effects animations exported as json with Bodymovin. Usage Export your ani

Alexis Le Baron 7 Aug 18, 2022
Stack BOF Protection Bypass Techniques

Stack Buffer Overflow - Protection Bypass Techniques

ommadawn46 18 Dec 28, 2022
Nfog - Scriptable Database-Driven NFO Generator for Movies and TV

nfog Scriptable Database-Driven NFO Generator for Movies and TV. Installation pi

6 Oct 08, 2022
A test repository to build a python package and publish the package to Artifact Registry using GCB

A test repository to build a python package and publish the package to Artifact Registry using GCB. Then have the package be a dependency in a GCF function.

1 Feb 09, 2022
Movie recommend community

README 0. 초록 1) 목적 사용자의 Needs를 기반으로 영화를 추천해주는 커뮤니티 서비스 구현 2) p!ck 서비스란? "pick your taste!" 취향대로 영화 플레이리스트(이하 서비스 내에서의 명칭인 '바스켓'이라 함)를 만들고, 비슷한 취향을 가진

2 Dec 08, 2021
It is a personal assistant chatbot, capable to perform many tasks same as Google Assistant plus more extra features...

PersonalAssistant It is an Personal Assistant, capable to perform many tasks with some unique features, that you haven'e seen yet.... Features / Tasks

Roshan Kumar 95 Dec 21, 2022
Сервис служит прокси между cервисом регистрации ошибок платформы и системой сбора ошибок Sentry

Sentry Reg Service Сервис служит прокси между Cервисом регистрации ошибок платформы и системой сбора ошибок Sentry. Как развернуть Sentry onpremise. С

Ingvar Vilkman 13 May 24, 2022
A tool for generating skill map/tree like diagram

skillmap A tool for generating skill map/tree like diagram. What is a skill map/tree? Skill tree is a term used in video games, and it can be used for

Yue 98 Jan 07, 2023
samples of neat code

NEAT-samples Some samples of code and config files for use with the NEAT-Python package These samples are largely copy and pasted, so if you

Harrison 50 Sep 28, 2022
:snake: Complete C99 parser in pure Python

pycparser v2.20 Contents 1 Introduction 1.1 What is pycparser? 1.2 What is it good for? 1.3 Which version of C does pycparser support? 1.4 What gramma

Eli Bendersky 2.8k Dec 29, 2022
Test for using pyIIIFpres for rara magnetica project

raramagnetica_pyIIIFpres Test for using pyIIIFpres for rara magnetica project. This test show how to use pyIIIFpres for creating mannifest compliant t

Giacomo Marchioro 1 Dec 03, 2021
ELF file deserializer and serializer library

elfo ELF file deserializer and serializer library. import elfo elf = elfo.ELF.from_path('main') elf ELF( header=ELFHeader( e_ident=e

Filipe Laíns 3 Aug 23, 2021
An Airdrop alternative for cross-platform users only for desktop with Python

PyDrop An Airdrop alternative for cross-platform users only for desktop with Python, -version 1.0 with less effort, just as a practice. ##############

Bernardo Olisan 6 Mar 25, 2022