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

16 Commits

Author SHA1 Message Date
2aa834be94 Update version & changelog for 1.8.1b0 2021-08-20 22:42:04 -05:00
5e4517aa53 Add fallback to HOMETRASH on plat_other
In the case where os.path.ismount() does not detect a mount and os.rename errors
fallback to HOMETRASH.  This covers several situations where continuing with
the identified trash location is incorrect due to complex mounts.

Close #26, #41, #63.
2021-08-20 22:30:51 -05:00
62849fba0b Remove Python 3.4 2021-08-19 21:01:55 -05:00
74f2dff57b Add exception handling to file cleanup
- Surpress errors caused by long file cleanup in older python environments
2021-08-19 20:46:02 -05:00
922fc0342a Update tox config 2021-08-19 20:46:02 -05:00
1d1b8755a9 Create codeql-analysis.yml
Test out codeql
2021-08-18 02:26:10 -05:00
d0e4890a4d Black format updates with correct line length 2021-08-17 18:58:11 -05:00
24079e245c Update tox.ini, flake8 ignore fewer errors 2021-08-17 18:54:52 -05:00
24b38e4ffe Update to use pyproject.toml & setup.cfg 2021-08-17 18:53:56 -05:00
69a82a5162 Dropping duplicate runs from travis CI
- Drop the duplicate runs from travis that github actions now cover.
- Add additional ppc64le entries for 3.7, 3.8, 3.9
2021-08-17 01:51:43 -05:00
2b3f9891c2 Temporarily comment out macOS due to failing tests 2021-08-17 01:40:06 -05:00
039f92264b Dropping python 3.4 2021-08-17 01:37:18 -05:00
c2c47610c8 Fix steps in test 2021-08-17 01:32:40 -05:00
66fc79695e Attempt to fix issues with matrix and versions 2021-08-17 01:29:37 -05:00
454ebeb072 Remove extra architecture stuff 2021-08-17 01:21:12 -05:00
7ca68e5473 First attempt at github actions setup 2021-08-17 01:18:26 -05:00
19 changed files with 262 additions and 180 deletions

71
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '25 5 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

80
.github/workflows/default.yml vendored Normal file
View File

@@ -0,0 +1,80 @@
# Workflow lints, and checks format in parallel then runs tests on all platforms
name: Default CI/CD
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
- name: Lint with flake8
run: |
flake8 .
test:
needs: lint
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
python-version: 3.10.0-alpha - 3.10.0
- os: ubuntu-latest
python-version: 3.9
- os: ubuntu-latest
python-version: 3.8
- os: ubuntu-latest
python-version: 3.7
- os: ubuntu-latest
python-version: 3.6
- os: ubuntu-latest
python-version: 3.5
- os: ubuntu-latest
python-version: 2.7
# - os: macos-latest
# python-version: 3.9
# - os: macos-latest
# python-version: 3.8
# - os: macos-latest
# python-version: 2.7
- os: windows-latest
python-version: 3.9
- os: windows-latest
python-version: 3.8
- os: windows-latest
python-version: 2.7
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
- name: Install windows dependencies
if: ${{ matrix.os == 'windows-latest' }}
run: |
pip install pywin32
- name: Install macOS dependencies
if: ${{ matrix.os == 'macos-latest' }}
run: |
pip install pyobjc-framework-Cocoa
- name: Run tests
run: |
pytest

View File

@@ -1,30 +1,16 @@
language: python language: python
matrix: matrix:
include: include:
- os: windows
language: sh
python: "3.8"
env: "PATH=/c/Python38:/c/Python38/Scripts:$PATH"
# Perform the manual steps on windows to install python3
before_install:
- choco install python --version=3.8.6
- python -m pip install --upgrade pip
before_script:
- export TOXENV=py38
- python: "2.7"
- python: "3.4"
- python: "3.5"
- python: "3.6"
- python: "3.7"
- python: "3.8"
- python: "3.9"
- python: "nightly" # 3.10
before_script:
- export TOXENV=py310
- python: "2.7" - python: "2.7"
arch: ppc64le arch: ppc64le
- python: "3.6" - python: "3.6"
arch: ppc64le arch: ppc64le
- python: "3.7"
arch: ppc64le
- python: "3.8"
arch: ppc64le
- python: "3.9"
arch: ppc64le
install: install:
- python -m pip install tox - python -m pip install tox
before_script: before_script:

View File

@@ -1,6 +1,10 @@
Changes Changes
======= =======
Version 1.8.1b0 -- 2021/09/20
-----------------------------
* Add fallback to HOMETRASH when cross device errors happen in plat_other (#26, $41, #63)
Version 1.8.0 -- 2021/08/08 Version 1.8.0 -- 2021/08/08
--------------------------- ---------------------------

6
pyproject.toml Normal file
View File

@@ -0,0 +1,6 @@
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 120

View File

@@ -35,9 +35,7 @@ class FileOperationProgressSink(DesignatedWrapPolicy):
# Can detect cases where to stop via flags and condition below, however the operation # Can detect cases where to stop via flags and condition below, however the operation
# does not actual stop, we can resort to raising an exception as that does stop things # does not actual stop, we can resort to raising an exception as that does stop things
# but that may need some additional considerations before implementing. # but that may need some additional considerations before implementing.
return ( return 0 if flags & shellcon.TSF_DELETE_RECYCLE_IF_POSSIBLE else 0x80004005 # S_OK, or E_FAIL
0 if flags & shellcon.TSF_DELETE_RECYCLE_IF_POSSIBLE else 0x80004005
) # S_OK, or E_FAIL
def PostDeleteItem(self, flags, item, hrDelete, newlyCreated): def PostDeleteItem(self, flags, item, hrDelete, newlyCreated):
if newlyCreated: if newlyCreated:
@@ -58,31 +56,20 @@ class FileOperationProgressSink(DesignatedWrapPolicy):
def PreMoveItem(self, Flags, Item, DestinationFolder, NewName): def PreMoveItem(self, Flags, Item, DestinationFolder, NewName):
pass pass
def PostMoveItem( def PostMoveItem(self, Flags, Item, DestinationFolder, NewName, hrMove, NewlyCreated):
self, Flags, Item, DestinationFolder, NewName, hrMove, NewlyCreated
):
pass pass
def PreCopyItem(self, Flags, Item, DestinationFolder, NewName): def PreCopyItem(self, Flags, Item, DestinationFolder, NewName):
pass pass
def PostCopyItem( def PostCopyItem(self, Flags, Item, DestinationFolder, NewName, hrCopy, NewlyCreated):
self, Flags, Item, DestinationFolder, NewName, hrCopy, NewlyCreated
):
pass pass
def PreNewItem(self, Flags, DestinationFolder, NewName): def PreNewItem(self, Flags, DestinationFolder, NewName):
pass pass
def PostNewItem( def PostNewItem(
self, self, Flags, DestinationFolder, NewName, TemplateName, FileAttributes, hrNew, NewItem,
Flags,
DestinationFolder,
NewName,
TemplateName,
FileAttributes,
hrNew,
NewItem,
): ):
pass pass
@@ -100,6 +87,4 @@ class FileOperationProgressSink(DesignatedWrapPolicy):
def CreateSink(): def CreateSink():
return pythoncom.WrapObject( return pythoncom.WrapObject(FileOperationProgressSink(), shell.IID_IFileOperationProgressSink)
FileOperationProgressSink(), shell.IID_IFileOperationProgressSink
)

View File

@@ -14,20 +14,20 @@ from send2trash import send2trash
def main(args=None): def main(args=None):
parser = ArgumentParser(description='Tool to send files to trash') parser = ArgumentParser(description="Tool to send files to trash")
parser.add_argument('files', nargs='+') parser.add_argument("files", nargs="+")
parser.add_argument('-v', '--verbose', action='store_true', help='Print deleted files') parser.add_argument("-v", "--verbose", action="store_true", help="Print deleted files")
args = parser.parse_args(args) args = parser.parse_args(args)
for filename in args.files: for filename in args.files:
try: try:
send2trash(filename) send2trash(filename)
if args.verbose: if args.verbose:
print('Trashed «' + filename + '»') print("Trashed «" + filename + "»")
except OSError as e: except OSError as e:
print(str(e), file=sys.stderr) print(str(e), file=sys.stderr)
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@@ -42,10 +42,7 @@ def check_op_result(op_result):
def send2trash(paths): def send2trash(paths):
paths = preprocess_paths(paths) paths = preprocess_paths(paths)
paths = [ paths = [path.encode("utf-8") if not isinstance(path, binary_type) else path for path in paths]
path.encode("utf-8") if not isinstance(path, binary_type) else path
for path in paths
]
for path in paths: for path in paths:
fp = FSRef() fp = FSRef()
opts = kFSPathMakeRefDoNotFollowLeafSymlink opts = kFSPathMakeRefDoNotFollowLeafSymlink

View File

@@ -18,10 +18,7 @@ def check_op_result(op_result):
def send2trash(paths): def send2trash(paths):
paths = preprocess_paths(paths) paths = preprocess_paths(paths)
paths = [ paths = [path.decode("utf-8") if not isinstance(path, text_type) else path for path in paths]
path.decode("utf-8") if not isinstance(path, text_type) else path
for path in paths
]
for path in paths: for path in paths:
file_url = NSURL.fileURLWithPath_(path) file_url = NSURL.fileURLWithPath_(path)
fm = NSFileManager.defaultManager() fm = NSFileManager.defaultManager()

View File

@@ -19,6 +19,7 @@ from __future__ import unicode_literals
import errno import errno
import sys import sys
import os import os
import shutil
import os.path as op import os.path as op
from datetime import datetime from datetime import datetime
import stat import stat
@@ -95,7 +96,7 @@ def check_create(dir):
os.makedirs(dir, 0o700) os.makedirs(dir, 0o700)
def trash_move(src, dst, topdir=None): def trash_move(src, dst, topdir=None, cross_dev=False):
filename = op.basename(src) filename = op.basename(src)
filespath = op.join(dst, FILES_DIR) filespath = op.join(dst, FILES_DIR)
infopath = op.join(dst, INFO_DIR) infopath = op.join(dst, INFO_DIR)
@@ -103,9 +104,7 @@ def trash_move(src, dst, topdir=None):
counter = 0 counter = 0
destname = filename destname = filename
while op.exists(op.join(filespath, destname)) or op.exists( while op.exists(op.join(filespath, destname)) or op.exists(op.join(infopath, destname + INFO_SUFFIX)):
op.join(infopath, destname + INFO_SUFFIX)
):
counter += 1 counter += 1
destname = base_name + b" " + text_type(counter).encode("ascii") + ext destname = base_name + b" " + text_type(counter).encode("ascii") + ext
@@ -114,14 +113,18 @@ def trash_move(src, dst, topdir=None):
with open(op.join(infopath, destname + INFO_SUFFIX), "w") as f: with open(op.join(infopath, destname + INFO_SUFFIX), "w") as f:
f.write(info_for(src, topdir)) f.write(info_for(src, topdir))
os.rename(src, op.join(filespath, destname)) destpath = op.join(filespath, destname)
if cross_dev:
shutil.move(src, destpath)
else:
os.rename(src, destpath)
def find_mount_point(path): def find_mount_point(path):
# Even if something's wrong, "/" is a mount point, so the loop will exit. # Even if something's wrong, "/" is a mount point, so the loop will exit.
# Use realpath in case it's a symlink # Use realpath in case it's a symlink
path = op.realpath(path) # Required to avoid infinite loop path = op.realpath(path) # Required to avoid infinite loop
while not op.ismount(path): while not op.ismount(path): # Note ismount() does not always detect mounts
path = op.split(path)[0] path = op.split(path)[0]
return path return path
@@ -208,4 +211,11 @@ def send2trash(paths):
if trash_dev != path_dev: if trash_dev != path_dev:
raise OSError("Couldn't find mount point for %s" % path) raise OSError("Couldn't find mount point for %s" % path)
dest_trash = find_ext_volume_trash(topdir) dest_trash = find_ext_volume_trash(topdir)
try:
trash_move(path_b, dest_trash, topdir) trash_move(path_b, dest_trash, topdir)
except OSError as error:
# Cross link errors default back to HOMETRASH
if error.errno == errno.EXDEV:
trash_move(path_b, HOMETRASH_B, XDG_DATA_HOME, cross_dev=True)
else:
raise

View File

@@ -105,10 +105,7 @@ def get_short_path_name(long_name):
def send2trash(paths): def send2trash(paths):
paths = preprocess_paths(paths) paths = preprocess_paths(paths)
# convert data type # convert data type
paths = [ paths = [text_type(path, "mbcs") if not isinstance(path, text_type) else path for path in paths]
text_type(path, "mbcs") if not isinstance(path, text_type) else path
for path in paths
]
# convert to full paths # convert to full paths
paths = [op.abspath(path) if not op.isabs(path) else path for path in paths] paths = [op.abspath(path) if not op.isabs(path) else path for path in paths]
# get short path to handle path length issues # get short path to handle path length issues

View File

@@ -18,10 +18,7 @@ from .IFileOperationProgressSink import CreateSink
def send2trash(paths): def send2trash(paths):
paths = preprocess_paths(paths) paths = preprocess_paths(paths)
# convert data type # convert data type
paths = [ paths = [text_type(path, "mbcs") if not isinstance(path, text_type) else path for path in paths]
text_type(path, "mbcs") if not isinstance(path, text_type) else path
for path in paths
]
# convert to full paths # convert to full paths
paths = [op.abspath(path) if not op.isabs(path) else path for path in paths] paths = [op.abspath(path) if not op.isabs(path) else path for path in paths]
# remove the leading \\?\ if present # remove the leading \\?\ if present
@@ -33,19 +30,11 @@ def send2trash(paths):
shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation, shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation,
) )
# default flags to use # default flags to use
flags = ( flags = shellcon.FOF_NOCONFIRMATION | shellcon.FOF_NOERRORUI | shellcon.FOF_SILENT | shellcon.FOFX_EARLYFAILURE
shellcon.FOF_NOCONFIRMATION
| shellcon.FOF_NOERRORUI
| shellcon.FOF_SILENT
| shellcon.FOFX_EARLYFAILURE
)
# determine rest of the flags based on OS version # determine rest of the flags based on OS version
# use newer recommended flags if available # use newer recommended flags if available
if int(version().split(".", 1)[0]) >= 8: if int(version().split(".", 1)[0]) >= 8:
flags |= ( flags |= 0x20000000 | 0x00080000 # FOFX_ADDUNDORECORD win 8+ # FOFX_RECYCLEONDELETE win 8+
0x20000000 # FOFX_ADDUNDORECORD win 8+
| 0x00080000 # FOFX_RECYCLEONDELETE win 8+
)
else: else:
flags |= shellcon.FOF_ALLOWUNDO flags |= shellcon.FOF_ALLOWUNDO
# set the flags # set the flags

View File

@@ -10,7 +10,5 @@ def preprocess_paths(paths):
if not isinstance(paths, list): if 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 = [ paths = [path.__fspath__() if hasattr(path, "__fspath__") else path for path in paths]
path.__fspath__() if hasattr(path, "__fspath__") else path for path in paths
]
return paths return paths

45
setup.cfg Normal file
View File

@@ -0,0 +1,45 @@
[metadata]
name = Send2Trash
version = 1.8.1b0
url = https://github.com/arsenetar/send2trash
project_urls =
Bug Reports = https://github.com/arsenetar/send2trash/issues
author = Andrew Senetar
author_email = arsenetar@voltaicideas.net
license = BSD License
license_files = LICENSE
description = Send file to trash natively under Mac OS X, Windows and Linux
long_description = file:README.rst
long_description_content_type = text/x-rst
classifiers =
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: MacOS :: MacOS X
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Topic :: Desktop Environment :: File Managers
[options]
packages = send2trash
tests_require = pytest
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
[options.extras_require]
win32 = pywin32; sys_platform == "win32"
objc = pyobjc-framework-Cocoa; sys_platform == "darwin"
nativeLib =
pywin32; sys_platform == "win32"
pyobjc-framework-Cocoa; sys_platform == "darwin"
[options.entry_points]
console_scripts =
send2trash = send2trash.__main__:main

View File

@@ -1,49 +0,0 @@
from setuptools import setup
CLASSIFIERS = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Desktop Environment :: File Managers",
]
with open("README.rst", "rt") as f1, open("CHANGES.rst", "rt") as f2:
LONG_DESCRIPTION = f1.read() + "\n\n" + f2.read()
setup(
name="Send2Trash",
version="1.8.0",
author="Andrew Senetar",
author_email="arsenetar@voltaicideas.net",
packages=["send2trash"],
scripts=[],
test_suite="tests",
url="https://github.com/arsenetar/send2trash",
license="BSD License",
description="Send file to trash natively under Mac OS X, Windows and Linux.",
long_description=LONG_DESCRIPTION,
long_description_content_type="text/x-rst",
classifiers=CLASSIFIERS,
extras_require={
"win32": ['pywin32; sys_platform == "win32"'],
"objc": ['pyobjc-framework-Cocoa; sys_platform == "darwin"'],
"nativeLib": [
'pywin32; sys_platform == "win32"',
'pyobjc-framework-Cocoa; sys_platform == "darwin"',
],
},
project_urls={"Bug Reports": "https://github.com/arsenetar/send2trash/issues"},
entry_points={"console_scripts": ["send2trash=send2trash.__main__:main"]},
)

View File

@@ -28,9 +28,7 @@ else:
@pytest.fixture @pytest.fixture
def testfile(): def testfile():
file = NamedTemporaryFile( file = NamedTemporaryFile(dir=op.expanduser("~"), prefix="send2trash_test", delete=False)
dir=op.expanduser("~"), prefix="send2trash_test", delete=False
)
file.close() file.close()
assert op.exists(file.name) is True assert op.exists(file.name) is True
yield file yield file
@@ -50,9 +48,7 @@ def testfiles():
files = list( files = list(
map( map(
lambda index: NamedTemporaryFile( lambda index: NamedTemporaryFile(
dir=op.expanduser("~"), dir=op.expanduser("~"), prefix="send2trash_test{}".format(index), delete=False,
prefix="send2trash_test{}".format(index),
delete=False,
), ),
range(10), range(10),
) )
@@ -62,10 +58,7 @@ def testfiles():
yield files yield files
filenames = [op.basename(file.name) for file in files] filenames = [op.basename(file.name) for file in files]
[os.remove(op.join(HOMETRASH, "files", filename)) for filename in filenames] [os.remove(op.join(HOMETRASH, "files", filename)) for filename in filenames]
[ [os.remove(op.join(HOMETRASH, "info", filename + ".trashinfo")) for filename in filenames]
os.remove(op.join(HOMETRASH, "info", filename + ".trashinfo"))
for filename in filenames
]
def test_trash(testfile): def test_trash(testfile):
@@ -136,10 +129,7 @@ class ExtVol:
return st.st_dev return st.st_dev
def s_ismount(path): def s_ismount(path):
if op.realpath(path) in ( if op.realpath(path) in (op.realpath(self.trashTopdir), op.realpath(self.trashTopdir_b),):
op.realpath(self.trashTopdir),
op.realpath(self.trashTopdir_b),
):
return True return True
return old_ismount(path) return old_ismount(path)
@@ -172,15 +162,8 @@ def test_trash_topdir(testExtVol):
s2t(testExtVol[2]) s2t(testExtVol[2])
assert op.exists(testExtVol[2]) is False assert op.exists(testExtVol[2]) is False
assert ( assert op.exists(op.join(trashDir, str(os.getuid()), "files", testExtVol[1])) is True
op.exists(op.join(trashDir, str(os.getuid()), "files", testExtVol[1])) is True assert op.exists(op.join(trashDir, str(os.getuid()), "info", testExtVol[1] + ".trashinfo",)) is True
)
assert (
op.exists(
op.join(trashDir, str(os.getuid()), "info", testExtVol[1] + ".trashinfo",)
)
is True
)
# info relative path (if another test is added, with the same fileName/Path, # info relative path (if another test is added, with the same fileName/Path,
# then it gets renamed etc.) # then it gets renamed etc.)
cfg = ConfigParser() cfg = ConfigParser()
@@ -191,17 +174,7 @@ def test_trash_topdir(testExtVol):
def test_trash_topdir_fallback(testExtVol): def test_trash_topdir_fallback(testExtVol):
s2t(testExtVol[2]) s2t(testExtVol[2])
assert op.exists(testExtVol[2]) is False assert op.exists(testExtVol[2]) is False
assert ( assert op.exists(op.join(testExtVol[0].trashTopdir, ".Trash-" + str(os.getuid()), "files", testExtVol[1],)) is True
op.exists(
op.join(
testExtVol[0].trashTopdir,
".Trash-" + str(os.getuid()),
"files",
testExtVol[1],
)
)
is True
)
def test_trash_topdir_failure(testExtVol): def test_trash_topdir_failure(testExtVol):
@@ -221,15 +194,5 @@ def test_trash_symlink(testExtVol):
os.symlink(op.join(testExtVol[0].trashTopdir, "subdir"), slDir) os.symlink(op.join(testExtVol[0].trashTopdir, "subdir"), slDir)
s2t(op.join(slDir, testExtVol[1])) s2t(op.join(slDir, testExtVol[1]))
assert op.exists(filePath) is False assert op.exists(filePath) is False
assert ( assert op.exists(op.join(testExtVol[0].trashTopdir, ".Trash-" + str(os.getuid()), "files", testExtVol[1],)) is True
op.exists(
op.join(
testExtVol[0].trashTopdir,
".Trash-" + str(os.getuid()),
"files",
testExtVol[1],
)
)
is True
)
os.remove(slDir) os.remove(slDir)

View File

@@ -144,7 +144,10 @@ def longdir(tmp_path):
dirname = "\\\\?\\" + str(tmp_path) dirname = "\\\\?\\" + str(tmp_path)
name = "A" * 100 name = "A" * 100
yield op.join(dirname, name, name, name) yield op.join(dirname, name, name, name)
try:
shutil.rmtree(dirname, ignore_errors=True) shutil.rmtree(dirname, ignore_errors=True)
except TypeError:
pass
@pytest.fixture @pytest.fixture

View File

@@ -14,9 +14,7 @@ if sys.platform != "win32":
@pytest.fixture @pytest.fixture
def file(): def file():
file = NamedTemporaryFile( file = NamedTemporaryFile(dir=op.expanduser("~"), prefix="send2trash_test", delete=False)
dir=op.expanduser("~"), prefix="send2trash_test", delete=False
)
file.close() file.close()
# Verify file was actually created # Verify file was actually created
assert op.exists(file.name) is True assert op.exists(file.name) is True

View File

@@ -1,6 +1,7 @@
[tox] [tox]
envlist = py{27,34,35,36,37,38,39,310} envlist = py{27,34,35,36,37,38,39,310}
skip_missing_interpreters = True skip_missing_interpreters = True
isolated_build = True
[testenv] [testenv]
deps = deps =
@@ -20,4 +21,5 @@ deps =
[flake8] [flake8]
exclude = .tox,env,build exclude = .tox,env,build
max-line-length = 120 max-line-length = 120
ignore = E731,E203,E501,W503 select = C,E,F,W,B,B950
extend-ignore = E203, E501