1
0
mirror of https://github.com/arsenetar/send2trash.git synced 2026-03-12 02:41:39 +00:00

18 Commits

Author SHA1 Message Date
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
484913ba0f Update version for 1.8.0 release 2021-08-08 21:51:06 -05:00
d249f0106b Fix #59, initialize and uninitialize COM for threading 2021-08-07 22:16:33 -05:00
94e1ec007a Add ability to handle pathlib paths
- Handle pathlib paths across all implementations, plat_other already did
- Move preprocessing code to common location
2021-08-07 21:48:10 -05:00
84c220cbd9 Change extra requires to filter on platform
Also created one extra `nativeLib` to replace the orignal two.  Will remove
the others after a couple releases.
2021-08-07 21:04:40 -05:00
6612545110 Add note about pyobjc to README, add extra option 2021-06-22 21:36:14 -05:00
d52b4f206c Fix CHANGES.rst issue 2021-06-21 22:22:48 -05:00
33171dde82 Update version for 1.7.1 release 2021-06-21 22:13:46 -05:00
077598d2ce Merge pull request #57 from BoboTiG/fix-windows-unc-names-legacy
Windows legacy: fix handling of UNC names
2021-06-21 22:06:06 -05:00
Mickaël Schoentgen
436686bf0f Windows legacy: fix handling of UNC names
The legacy implementation was not handling UNC names properly:

  Traceback (most recent call last):
    File "check.py", line 6, in <module>
      send2trash(str(file))
    File "\...\plat_win_legacy.py", line 79, in send2trash
      paths = [get_short_path_name(path) for path in paths]
    File "\...\plat_win_legacy.py", line 79, in <listcomp>
      paths = [get_short_path_name(path) for path in paths]
    File "\...\plat_win_legacy.py", line 62, in get_short_path_name
      raise WindowsError(err_no, FormatError(err_no), long_name[4:])
  OSError: [Errno 123] La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte.: '\\\\SERVER\\folder\\file.txt'
2021-05-26 17:22:26 +02:00
23ce7b8c16 Bump version 2021-05-14 21:44:21 -05:00
9b0d5796c1 Change conditional for macos pyobjc usage
macOS 11.x will occasionally identify as 10.16, since there was no real
reason to prevent on all supported platforms allow.
2021-05-14 21:40:16 -05:00
13 changed files with 205 additions and 50 deletions

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,17 @@
language: python
matrix:
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"
arch: ppc64le
- python: "3.6"
arch: ppc64le
- python: "3.7"
arch: ppc64le
- python: "3.8"
arch: ppc64le
- python: "3.9"
arch: ppc64le
install:
- python -m pip install tox
before_script:

View File

@@ -1,8 +1,27 @@
Changes
=======
Version 1.7.0a -- 2020/04/20
----------------------------
Version 1.8.0 -- 2021/08/08
---------------------------
* Add compatibility with pathlib paths (#49)
* Fix thread compatibility of modern windows implementation (#59)
* Fix handling of UNC names in legacy windows implementation (#57)
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)

View File

@@ -3,11 +3,11 @@ 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`_.
*all platforms*. On OS X, it uses native ``FSMoveObjectToTrashSync`` Cocoa calls or can use pyobjc
with NSFileManager. 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.
@@ -22,10 +22,14 @@ issues and fixes would be most appreciated.
Installation
------------
You can download it with pip::
You can download it with pip:
python -m pip install -U send2trash
To install with pywin32 or pyobjc required specify the extra `nativeLib`:
python -m pip install -U send2trash[nativeLib]
or you can download the source from http://github.com/arsenetar/send2trash and install it with::
>>> python setup.py install

View File

@@ -6,11 +6,11 @@
from gi.repository import GObject, Gio
from .exceptions import TrashPermissionError
from .util import preprocess_paths
def send2trash(paths):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
for path in paths:
try:
f = Gio.File.new_for_path(path)

View File

@@ -7,9 +7,9 @@
from platform import mac_ver
from sys import version_info
# If macOS is 11.0 or newer try to use the pyobjc version to get around #51
# NOTE: pyobjc only supports python >= 3.6
if version_info >= (3, 6) and int(mac_ver()[0].split(".", 1)[0]) >= 11:
# 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:

View File

@@ -10,6 +10,7 @@ from ctypes import cdll, byref, Structure, c_char, c_char_p
from ctypes.util import find_library
from .compat import binary_type
from .util import preprocess_paths
Foundation = cdll.LoadLibrary(find_library("Foundation"))
CoreServices = cdll.LoadLibrary(find_library("CoreServices"))
@@ -40,8 +41,7 @@ def check_op_result(op_result):
def send2trash(paths):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
paths = [
path.encode("utf-8") if not isinstance(path, binary_type) else path
for path in paths

View File

@@ -6,6 +6,7 @@
from Foundation import NSFileManager, NSURL
from .compat import text_type
from .util import preprocess_paths
def check_op_result(op_result):
@@ -16,8 +17,7 @@ def check_op_result(op_result):
def send2trash(paths):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
paths = [
path.decode("utf-8") if not isinstance(path, text_type) else path
for path in paths

View File

@@ -30,6 +30,7 @@ except ImportError:
from urllib import quote
from .compat import text_type, environb
from .util import preprocess_paths
from .exceptions import TrashPermissionError
try:
@@ -172,8 +173,7 @@ def get_dev(path):
def send2trash(paths):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
for path in paths:
if isinstance(path, text_type):
path_b = fsencode(path)

View File

@@ -7,6 +7,8 @@
from __future__ import unicode_literals
import os.path as op
from .compat import text_type
from .util import preprocess_paths
from ctypes import (
windll,
Structure,
@@ -51,23 +53,57 @@ 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):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
# convert data type
paths = [
text_type(path, "mbcs") if not isinstance(path, text_type) else path

View File

@@ -7,6 +7,7 @@
from __future__ import unicode_literals
import os.path as op
from .compat import text_type
from .util import preprocess_paths
from platform import version
import pythoncom
import pywintypes
@@ -15,8 +16,7 @@ from .IFileOperationProgressSink import CreateSink
def send2trash(paths):
if not isinstance(paths, list):
paths = [paths]
paths = preprocess_paths(paths)
# convert data type
paths = [
text_type(path, "mbcs") if not isinstance(path, text_type) else path
@@ -26,6 +26,8 @@ def send2trash(paths):
paths = [op.abspath(path) if not op.isabs(path) else path for path in paths]
# remove the leading \\?\ if present
paths = [path[4:] if path.startswith("\\\\?\\") else path for path in paths]
# Need to initialize the com before using
pythoncom.CoInitialize()
# create instance of file operation object
fileop = pythoncom.CoCreateInstance(
shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation,
@@ -65,3 +67,6 @@ def send2trash(paths):
# convert to standard OS error, allows other code to get a
# normal errno
raise OSError(None, error.strerror, path, error.hresult)
finally:
# Need to make sure we call this once fore every init
pythoncom.CoUninitialize()

16
send2trash/util.py Normal file
View File

@@ -0,0 +1,16 @@
# encoding: utf-8
# 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
def preprocess_paths(paths):
if not isinstance(paths, list):
paths = [paths]
# Convert items such as pathlib paths to strings
paths = [
path.__fspath__() if hasattr(path, "__fspath__") else path for path in paths
]
return paths

View File

@@ -24,7 +24,7 @@ with open("README.rst", "rt") as f1, open("CHANGES.rst", "rt") as f2:
setup(
name="Send2Trash",
version="1.7.0a",
version="1.8.0",
author="Andrew Senetar",
author_email="arsenetar@voltaicideas.net",
packages=["send2trash"],
@@ -34,8 +34,16 @@ setup(
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"]},
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"]},
)