mirror of
https://github.com/arsenetar/send2trash.git
synced 2026-03-13 19:11:39 +00:00
Compare commits
8 Commits
10c7693d11
...
1.7.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
d52b4f206c
|
|||
|
33171dde82
|
|||
| 077598d2ce | |||
|
|
436686bf0f | ||
|
23ce7b8c16
|
|||
|
9b0d5796c1
|
|||
|
c8bcaea1e8
|
|||
| 530e9b4bc6 |
21
CHANGES.rst
21
CHANGES.rst
@@ -1,5 +1,26 @@
|
||||
Changes
|
||||
=======
|
||||
Version 1.7.1 -- 2021/06/21
|
||||
---------------------------
|
||||
|
||||
* Release stable version with changes from last 3 releases
|
||||
* Fix handling of UNC names (#57)
|
||||
|
||||
Version 1.7.0a1 -- 2021/05/14
|
||||
-----------------------------
|
||||
|
||||
* Changed conditional for when to try to use pyobjc version (#51)
|
||||
|
||||
Version 1.7.0a0 -- 2021/04/20
|
||||
-----------------------------
|
||||
|
||||
* 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)
|
||||
|
||||
Version 1.6.0b1 -- 2020/06/18
|
||||
-----------------------------
|
||||
|
||||
@@ -4,53 +4,17 @@
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from platform import mac_ver
|
||||
from sys import version_info
|
||||
|
||||
from ctypes import cdll, byref, Structure, c_char, c_char_p
|
||||
from ctypes.util import find_library
|
||||
|
||||
from .compat import binary_type
|
||||
|
||||
Foundation = cdll.LoadLibrary(find_library("Foundation"))
|
||||
CoreServices = cdll.LoadLibrary(find_library("CoreServices"))
|
||||
|
||||
GetMacOSStatusCommentString = Foundation.GetMacOSStatusCommentString
|
||||
GetMacOSStatusCommentString.restype = c_char_p
|
||||
FSPathMakeRefWithOptions = CoreServices.FSPathMakeRefWithOptions
|
||||
FSMoveObjectToTrashSync = CoreServices.FSMoveObjectToTrashSync
|
||||
|
||||
kFSPathMakeRefDefaultOptions = 0
|
||||
kFSPathMakeRefDoNotFollowLeafSymlink = 0x01
|
||||
|
||||
kFSFileOperationDefaultOptions = 0
|
||||
kFSFileOperationOverwrite = 0x01
|
||||
kFSFileOperationSkipSourcePermissionErrors = 0x02
|
||||
kFSFileOperationDoNotMoveAcrossVolumes = 0x04
|
||||
kFSFileOperationSkipPreflight = 0x08
|
||||
|
||||
|
||||
class FSRef(Structure):
|
||||
_fields_ = [("hidden", c_char * 80)]
|
||||
|
||||
|
||||
def check_op_result(op_result):
|
||||
if op_result:
|
||||
msg = GetMacOSStatusCommentString(op_result).decode("utf-8")
|
||||
raise OSError(msg)
|
||||
|
||||
|
||||
def send2trash(paths):
|
||||
if not isinstance(paths, list):
|
||||
paths = [paths]
|
||||
paths = [
|
||||
path.encode("utf-8") if not isinstance(path, binary_type) else path
|
||||
for path in paths
|
||||
]
|
||||
for path in paths:
|
||||
fp = FSRef()
|
||||
opts = kFSPathMakeRefDoNotFollowLeafSymlink
|
||||
op_result = FSPathMakeRefWithOptions(path, opts, byref(fp), None)
|
||||
check_op_result(op_result)
|
||||
opts = kFSFileOperationDefaultOptions
|
||||
op_result = FSMoveObjectToTrashSync(byref(fp), None, opts)
|
||||
check_op_result(op_result)
|
||||
# NOTE: version of pyobjc only supports python >= 3.6 and 10.9+
|
||||
macos_ver = tuple(int(part) for part in mac_ver()[0].split("."))
|
||||
if version_info >= (3, 6) and macos_ver >= (10, 9):
|
||||
try:
|
||||
from .plat_osx_pyobjc import send2trash
|
||||
except ImportError:
|
||||
# Try to fall back to ctypes version, although likely problematic still
|
||||
from .plat_osx_ctypes import send2trash
|
||||
else:
|
||||
# Just use the old version otherwise
|
||||
from .plat_osx_ctypes import send2trash # noqa: F401
|
||||
|
||||
56
send2trash/plat_osx_ctypes.py
Normal file
56
send2trash/plat_osx_ctypes.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright 2017 Virgil Dupras
|
||||
|
||||
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from ctypes import cdll, byref, Structure, c_char, c_char_p
|
||||
from ctypes.util import find_library
|
||||
|
||||
from .compat import binary_type
|
||||
|
||||
Foundation = cdll.LoadLibrary(find_library("Foundation"))
|
||||
CoreServices = cdll.LoadLibrary(find_library("CoreServices"))
|
||||
|
||||
GetMacOSStatusCommentString = Foundation.GetMacOSStatusCommentString
|
||||
GetMacOSStatusCommentString.restype = c_char_p
|
||||
FSPathMakeRefWithOptions = CoreServices.FSPathMakeRefWithOptions
|
||||
FSMoveObjectToTrashSync = CoreServices.FSMoveObjectToTrashSync
|
||||
|
||||
kFSPathMakeRefDefaultOptions = 0
|
||||
kFSPathMakeRefDoNotFollowLeafSymlink = 0x01
|
||||
|
||||
kFSFileOperationDefaultOptions = 0
|
||||
kFSFileOperationOverwrite = 0x01
|
||||
kFSFileOperationSkipSourcePermissionErrors = 0x02
|
||||
kFSFileOperationDoNotMoveAcrossVolumes = 0x04
|
||||
kFSFileOperationSkipPreflight = 0x08
|
||||
|
||||
|
||||
class FSRef(Structure):
|
||||
_fields_ = [("hidden", c_char * 80)]
|
||||
|
||||
|
||||
def check_op_result(op_result):
|
||||
if op_result:
|
||||
msg = GetMacOSStatusCommentString(op_result).decode("utf-8")
|
||||
raise OSError(msg)
|
||||
|
||||
|
||||
def send2trash(paths):
|
||||
if not isinstance(paths, list):
|
||||
paths = [paths]
|
||||
paths = [
|
||||
path.encode("utf-8") if not isinstance(path, binary_type) else path
|
||||
for path in paths
|
||||
]
|
||||
for path in paths:
|
||||
fp = FSRef()
|
||||
opts = kFSPathMakeRefDoNotFollowLeafSymlink
|
||||
op_result = FSPathMakeRefWithOptions(path, opts, byref(fp), None)
|
||||
check_op_result(op_result)
|
||||
opts = kFSFileOperationDefaultOptions
|
||||
op_result = FSMoveObjectToTrashSync(byref(fp), None, opts)
|
||||
check_op_result(op_result)
|
||||
29
send2trash/plat_osx_pyobjc.py
Normal file
29
send2trash/plat_osx_pyobjc.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Virgil Dupras
|
||||
|
||||
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.hardcoded.net/licenses/bsd_license
|
||||
|
||||
from Foundation import NSFileManager, NSURL
|
||||
from .compat import text_type
|
||||
|
||||
|
||||
def check_op_result(op_result):
|
||||
# First value will be false on failure
|
||||
if not op_result[0]:
|
||||
# Error is in third value, localized failure reason matchs ctypes version
|
||||
raise OSError(op_result[2].localizedFailureReason())
|
||||
|
||||
|
||||
def send2trash(paths):
|
||||
if not isinstance(paths, list):
|
||||
paths = [paths]
|
||||
paths = [
|
||||
path.decode("utf-8") if not isinstance(path, text_type) else path
|
||||
for path in paths
|
||||
]
|
||||
for path in paths:
|
||||
file_url = NSURL.fileURLWithPath_(path)
|
||||
fm = NSFileManager.defaultManager()
|
||||
op_result = fm.trashItemAtURL_resultingItemURL_error_(file_url, None, None)
|
||||
check_op_result(op_result)
|
||||
@@ -51,18 +51,53 @@ FOF_ALLOWUNDO = 64
|
||||
FOF_NOERRORUI = 1024
|
||||
|
||||
|
||||
def prefix_and_path(path):
|
||||
r"""Guess the long-path prefix based on the kind of *path*.
|
||||
Local paths (C:\folder\file.ext) and UNC names (\\server\folder\file.ext)
|
||||
are handled.
|
||||
|
||||
Return a tuple of the long-path prefix and the prefixed path.
|
||||
"""
|
||||
prefix, long_path = "\\\\?\\", path
|
||||
|
||||
if not path.startswith(prefix):
|
||||
if path.startswith("\\\\"):
|
||||
# Likely a UNC name
|
||||
prefix = "\\\\?\\UNC"
|
||||
long_path = prefix + path[1:]
|
||||
else:
|
||||
# Likely a local path
|
||||
long_path = prefix + path
|
||||
elif path.startswith(prefix + "UNC\\"):
|
||||
# UNC name with long-path prefix
|
||||
prefix = "\\\\?\\UNC"
|
||||
|
||||
return prefix, long_path
|
||||
|
||||
|
||||
def get_awaited_path_from_prefix(prefix, path):
|
||||
"""Guess the correct path to pass to the SHFileOperationW() call.
|
||||
The long-path prefix must be removed, so we should take care of
|
||||
different long-path prefixes.
|
||||
"""
|
||||
if prefix == "\\\\?\\UNC":
|
||||
# We need to prepend a backslash for UNC names, as it was removed
|
||||
# in prefix_and_path().
|
||||
return "\\" + path[len(prefix) :]
|
||||
return path[len(prefix) :]
|
||||
|
||||
|
||||
def get_short_path_name(long_name):
|
||||
if not long_name.startswith("\\\\?\\"):
|
||||
long_name = "\\\\?\\" + long_name
|
||||
buf_size = GetShortPathNameW(long_name, None, 0)
|
||||
prefix, long_path = prefix_and_path(long_name)
|
||||
buf_size = GetShortPathNameW(long_path, None, 0)
|
||||
# FIX: https://github.com/hsoft/send2trash/issues/31
|
||||
# If buffer size is zero, an error has occurred.
|
||||
if not buf_size:
|
||||
err_no = GetLastError()
|
||||
raise WindowsError(err_no, FormatError(err_no), long_name[4:])
|
||||
raise WindowsError(err_no, FormatError(err_no), long_path)
|
||||
output = create_unicode_buffer(buf_size)
|
||||
GetShortPathNameW(long_name, output, buf_size)
|
||||
return output.value[4:] # Remove '\\?\' for SHFileOperationW
|
||||
GetShortPathNameW(long_path, output, buf_size)
|
||||
return get_awaited_path_from_prefix(prefix, output.value)
|
||||
|
||||
|
||||
def send2trash(paths):
|
||||
|
||||
2
setup.py
2
setup.py
@@ -24,7 +24,7 @@ with open("README.rst", "rt") as f1, open("CHANGES.rst", "rt") as f2:
|
||||
|
||||
setup(
|
||||
name="Send2Trash",
|
||||
version="1.6.0b1",
|
||||
version="1.7.1",
|
||||
author="Andrew Senetar",
|
||||
author_email="arsenetar@voltaicideas.net",
|
||||
packages=["send2trash"],
|
||||
|
||||
Reference in New Issue
Block a user