1
0
mirror of https://github.com/arsenetar/send2trash.git synced 2026-01-22 14:41:40 +00:00

chore: More pylint cleanups, and python2 removals

This commit is contained in:
2025-12-31 02:54:09 +00:00
committed by GitHub
parent 8d96aa29df
commit 06a9d37805
5 changed files with 36 additions and 58 deletions

View File

@@ -19,5 +19,5 @@ def send2trash(paths):
if e.code == Gio.IOErrorEnum.NOT_SUPPORTED: if e.code == Gio.IOErrorEnum.NOT_SUPPORTED:
# We get here if we can't create a trash directory on the same # We get here if we can't create a trash directory on the same
# device. I don't know if other errors can result in NOT_SUPPORTED. # device. I don't know if other errors can result in NOT_SUPPORTED.
raise TrashPermissionError("") raise TrashPermissionError("") from e
raise OSError(e.message) raise OSError(e.message) from e

View File

@@ -17,36 +17,15 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import errno import errno
import sys
import os
import shutil import shutil
import os
import os.path as op import os.path as op
from datetime import datetime from datetime import datetime
import stat import stat
try:
from urllib.parse import quote from urllib.parse import quote
except ImportError:
# Python 2
from urllib import quote
from send2trash.util import preprocess_paths from send2trash.util import preprocess_paths
from send2trash.exceptions import TrashPermissionError from send2trash.exceptions import TrashPermissionError
try:
fsencode = os.fsencode # Python 3
fsdecode = os.fsdecode
except AttributeError:
def fsencode(u): # Python 2
return u.encode(sys.getfilesystemencoding())
def fsdecode(b):
return b.decode(sys.getfilesystemencoding())
# The Python 3 versions are a bit smarter, handling surrogate escapes,
# but these should work in most cases.
FILES_DIR = b"files" FILES_DIR = b"files"
INFO_DIR = b"info" INFO_DIR = b"info"
INFO_SUFFIX = b".trashinfo" INFO_SUFFIX = b".trashinfo"
@@ -54,7 +33,7 @@ INFO_SUFFIX = b".trashinfo"
# Default of ~/.local/share [3] # Default of ~/.local/share [3]
XDG_DATA_HOME = op.expanduser(os.environb.get(b"XDG_DATA_HOME", b"~/.local/share")) XDG_DATA_HOME = op.expanduser(os.environb.get(b"XDG_DATA_HOME", b"~/.local/share"))
HOMETRASH_B = op.join(XDG_DATA_HOME, b"Trash") HOMETRASH_B = op.join(XDG_DATA_HOME, b"Trash")
HOMETRASH = fsdecode(HOMETRASH_B) HOMETRASH = os.fsdecode(HOMETRASH_B)
uid = os.getuid() uid = os.getuid()
TOPDIR_TRASH = b".Trash" TOPDIR_TRASH = b".Trash"
@@ -64,10 +43,10 @@ TOPDIR_FALLBACK = b".Trash-" + str(uid).encode("ascii")
def is_parent(parent, path): def is_parent(parent, path):
path = op.realpath(path) # In case it's a symlink path = op.realpath(path) # In case it's a symlink
if isinstance(path, str): if isinstance(path, str):
path = fsencode(path) path = os.fsencode(path)
parent = op.realpath(parent) parent = op.realpath(parent)
if isinstance(parent, str): if isinstance(parent, str):
parent = fsencode(parent) parent = os.fsencode(parent)
return path.startswith(parent) return path.startswith(parent)
@@ -89,34 +68,34 @@ def info_for(src, topdir):
return info return info
def check_create(dir): def check_create(folder):
# use 0700 for paths [3] # use 0700 for paths [3]
if not op.exists(dir): if not op.exists(folder):
os.makedirs(dir, 0o700) os.makedirs(folder, 0o700)
def trash_move(src, dst, topdir=None, cross_dev=False): def trash_move(src, dst, topdir=None, cross_dev=False):
filename = op.basename(src) file_name = op.basename(src)
filespath = op.join(dst, FILES_DIR) files_path = op.join(dst, FILES_DIR)
infopath = op.join(dst, INFO_DIR) info_path = op.join(dst, INFO_DIR)
base_name, ext = op.splitext(filename) base_name, ext = op.splitext(file_name)
counter = 0 counter = 0
destname = filename dest_name = file_name
while op.exists(op.join(filespath, destname)) or op.exists(op.join(infopath, destname + INFO_SUFFIX)): while op.exists(op.join(files_path, dest_name)) or op.exists(op.join(info_path, dest_name + INFO_SUFFIX)):
counter += 1 counter += 1
destname = base_name + b" " + str(counter).encode("ascii") + ext dest_name = base_name + b" " + str(counter).encode("ascii") + ext
check_create(filespath) check_create(files_path)
check_create(infopath) check_create(info_path)
with open(op.join(infopath, destname + INFO_SUFFIX), "w") as f: with open(op.join(info_path, dest_name + INFO_SUFFIX), "w") as f:
f.write(info_for(src, topdir)) f.write(info_for(src, topdir))
destpath = op.join(filespath, destname) dest_path = op.join(files_path, dest_name)
if cross_dev: if cross_dev:
shutil.move(fsdecode(src), fsdecode(destpath)) shutil.move(os.fsdecode(src), os.fsdecode(dest_path))
else: else:
os.rename(src, destpath) os.rename(src, dest_path)
def find_mount_point(path): def find_mount_point(path):
@@ -138,7 +117,7 @@ def find_ext_volume_global_trash(volume_root):
mode = os.lstat(trash_dir).st_mode mode = os.lstat(trash_dir).st_mode
# vol/.Trash must be a directory, cannot be a symlink, and must have the # vol/.Trash must be a directory, cannot be a symlink, and must have the
# sticky bit set. # sticky bit set.
if not op.isdir(trash_dir) or op.islink(trash_dir) or not (mode & stat.S_ISVTX): if not op.isdir(trash_dir) or op.islink(trash_dir) or not mode & stat.S_ISVTX:
return None return None
trash_dir = op.join(trash_dir, str(uid).encode("ascii")) trash_dir = op.join(trash_dir, str(uid).encode("ascii"))
@@ -157,7 +136,7 @@ def find_ext_volume_fallback_trash(volume_root):
check_create(trash_dir) check_create(trash_dir)
except OSError as e: except OSError as e:
if e.errno == errno.EACCES: if e.errno == errno.EACCES:
raise TrashPermissionError(e.filename) raise TrashPermissionError(e.filename) from e
raise raise
return trash_dir return trash_dir
@@ -178,18 +157,18 @@ def send2trash(paths):
paths = preprocess_paths(paths) paths = preprocess_paths(paths)
for path in paths: for path in paths:
if isinstance(path, str): if isinstance(path, str):
path_b = fsencode(path) path_b = os.fsencode(path)
elif isinstance(path, bytes): elif isinstance(path, bytes):
path_b = path path_b = path
else: else:
raise TypeError("str, bytes or PathLike expected, not %r" % type(path)) raise TypeError(f"str, bytes or PathLike expected, not {type(path)}")
if not op.exists(path_b): if not op.exists(path_b):
raise OSError(errno.ENOENT, "File not found: %s" % path) raise OSError(errno.ENOENT, f"File not found: {path}")
# ...should check whether the user has the necessary permissions to delete # ...should check whether the user has the necessary permissions to delete
# it, before starting the trashing operation itself. [2] # it, before starting the trashing operation itself. [2]
if not os.access(path_b, os.W_OK): if not os.access(path_b, os.W_OK):
raise OSError(errno.EACCES, "Permission denied: %s" % path) raise OSError(errno.EACCES, f"Permission denied: {path}")
path_dev = get_dev(path_b) path_dev = get_dev(path_b)
# If XDG_DATA_HOME or HOMETRASH do not yet exist we need to stat the # If XDG_DATA_HOME or HOMETRASH do not yet exist we need to stat the
@@ -205,7 +184,7 @@ def send2trash(paths):
topdir = find_mount_point(path_b) topdir = find_mount_point(path_b)
trash_dev = get_dev(topdir) trash_dev = get_dev(topdir)
if trash_dev != path_dev: if trash_dev != path_dev:
raise OSError("Couldn't find mount point for %s" % path) raise OSError(f"Couldn't find mount point for {path}")
dest_trash = find_ext_volume_trash(topdir) dest_trash = find_ext_volume_trash(topdir)
try: try:
trash_move(path_b, dest_trash, topdir) trash_move(path_b, dest_trash, topdir)

View File

@@ -5,6 +5,7 @@
# which should be included with this package. The terms are also available at # which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license # http://www.hardcoded.net/licenses/bsd_license
import os
import collections.abc import collections.abc
@@ -14,5 +15,4 @@ def preprocess_paths(paths):
elif not isinstance(paths, list): elif not isinstance(paths, list):
paths = [paths] paths = [paths]
# Convert items such as pathlib paths to strings # Convert items such as pathlib paths to strings
paths = [path.__fspath__() if hasattr(path, "__fspath__") else path for path in paths] return [os.fspath(path) for path in paths]
return paths

View File

@@ -6,9 +6,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os.path as op import os.path as op
from send2trash.util import preprocess_paths
from ctypes import ( from ctypes import (
windll, windll,
Structure, Structure,
@@ -21,6 +18,8 @@ from ctypes import (
) )
from ctypes.wintypes import HWND, UINT, LPCWSTR, BOOL from ctypes.wintypes import HWND, UINT, LPCWSTR, BOOL
from send2trash.util import preprocess_paths
kernel32 = windll.kernel32 kernel32 = windll.kernel32
GetShortPathNameW = kernel32.GetShortPathNameW GetShortPathNameW = kernel32.GetShortPathNameW

View File

@@ -6,11 +6,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os.path as op import os.path as op
from send2trash.util import preprocess_paths
from platform import version from platform import version
import pythoncom import pythoncom
import pywintypes import pywintypes
from win32com.shell import shell, shellcon from win32com.shell import shell, shellcon
from send2trash.util import preprocess_paths
from send2trash.win.IFileOperationProgressSink import create_sink from send2trash.win.IFileOperationProgressSink import create_sink
@@ -59,7 +59,7 @@ def send2trash(paths):
except pywintypes.com_error as error: except pywintypes.com_error as error:
# convert to standard OS error, allows other code to get a # convert to standard OS error, allows other code to get a
# normal errno # normal errno
raise OSError(None, error.strerror, path, error.hresult) raise OSError(None, error.strerror, path, error.hresult) from error
finally: finally:
# Need to make sure we call this once fore every init # Need to make sure we call this once fore every init
pythoncom.CoUninitialize() pythoncom.CoUninitialize()