From 7f7542fcbc192fef6e4939f4eb748e941a720b2c Mon Sep 17 00:00:00 2001 From: Adam Hupp Date: Mon, 4 Oct 2021 14:46:37 -0700 Subject: Support os.PathLike types See https://github.com/ahupp/python-magic/pull/251 --- CHANGELOG | 3 +++ magic/__init__.py | 17 +++++++++++++++++ magic/__init__.pyi | 5 +++-- test/test.py | 8 ++++++++ test_docker.sh | 14 ++++++++++---- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c578572..26e01f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Changes to 0.4.25: + - Support os.PathLike values in Magic.from_file and magic.from_file + Changes to 0.4.24: - Fix regression in library loading on some Alpine docker images. diff --git a/magic/__init__.py b/magic/__init__.py index 363e88f..bab7c7b 100644 --- a/magic/__init__.py +++ b/magic/__init__.py @@ -100,6 +100,7 @@ class Magic: # if we're on python3, convert buf to bytes # otherwise this string is passed as wchar* # which is not what libmagic expects + # NEXTBREAK: only take bytes if type(buf) == str and str != bytes: buf = buf.encode('utf-8', errors='replace') return maybe_decode(magic_buffer(self.cookie, buf)) @@ -229,6 +230,7 @@ def errorcheck_negative_one(result, func, args): # return str on python3. Don't want to unconditionally # decode because that results in unicode on python2 def maybe_decode(s): + # NEXTBREAK: remove if str == bytes: return s else: @@ -237,13 +239,28 @@ def maybe_decode(s): return s.decode('utf-8', 'backslashreplace') +try: + from os import PathLike + def unpath(filename): + if isinstance(filename, PathLike): + return filename.__fspath__() + else: + return filename +except ImportError: + def unpath(filename): + return filename + def coerce_filename(filename): if filename is None: return None + + filename = unpath(filename) + # ctypes will implicitly convert unicode strings to bytes with # .encode('ascii'). If you use the filesystem encoding # then you'll get inconsistent behavior (crashes) depending on the user's # LANG environment variable + # NEXTBREAK: remove is_unicode = (sys.version_info[0] <= 2 and isinstance(filename, unicode)) or \ (sys.version_info[0] >= 3 and diff --git a/magic/__init__.pyi b/magic/__init__.pyi index 8d5f38f..b6b5489 100644 --- a/magic/__init__.pyi +++ b/magic/__init__.pyi @@ -1,6 +1,7 @@ import ctypes.util import threading from typing import Any, Text, Optional, Union +from os import PathLike class MagicException(Exception): message: Any = ... @@ -12,13 +13,13 @@ class Magic: lock: threading.Lock = ... def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ...) -> None: ... def from_buffer(self, buf: Union[bytes, str]) -> Text: ... - def from_file(self, filename: Union[bytes, str]) -> Text: ... + def from_file(self, filename: Union[bytes, str, PathLike]) -> Text: ... def from_descriptor(self, fd: int, mime: bool = ...) -> Text: ... def setparam(self, param: Any, val: Any): ... def getparam(self, param: Any): ... def __del__(self) -> None: ... -def from_file(filename: Union[bytes, str], mime: bool = ...) -> Text: ... +def from_file(filename: Union[bytes, str, PathLike], mime: bool = ...) -> Text: ... def from_buffer(buffer: Union[bytes, str], mime: bool = ...) -> Text: ... def from_descriptor(fd: int, mime: bool = ...) -> Text: ... diff --git a/test/test.py b/test/test.py index 0cd12fd..0c4621c 100755 --- a/test/test.py +++ b/test/test.py @@ -219,6 +219,14 @@ class MagicTest(unittest.TestCase): with open(os.path.join(self.TESTDATA_DIR, 'name_use.jpg'), 'rb') as f: m.from_buffer(f.read()) + def test_pathlike(self): + if sys.version_info < (3, 6): + return + from pathlib import Path + path = Path(self.TESTDATA_DIR, "test.pdf") + m = magic.Magic(mime=True) + self.assertEqual('application/pdf', m.from_file(path)) + if __name__ == '__main__': unittest.main() diff --git a/test_docker.sh b/test_docker.sh index 59d6b7c..ad2bc5d 100755 --- a/test_docker.sh +++ b/test_docker.sh @@ -5,8 +5,14 @@ set -e -NAME=`basename $1` -TAG="python_magic/${NAME}:latest" -docker build -t $TAG -f $1 . -docker run $TAG +DEFAULT_TARGETS="xenial bionic focal centos7 centos8 archlinux alpine" +TARGETS=${1:-${DEFAULT_TARGETS}} + +HERE=`dirname $0` + +for i in $TARGETS; do + TAG="python_magic/${i}:latest" + docker build -t $TAG -f ${HERE}/test/docker/$i . + docker run $TAG +done -- cgit v1.2.1