Browse Source

Merge upstream version 0.4.25

Christoph Biedl 4 months ago
parent
commit
191c08ef92
8 changed files with 54 additions and 10 deletions
  1. 1 0
      .gitignore
  2. 6 0
      CHANGELOG
  3. 17 0
      magic/__init__.py
  4. 3 2
      magic/__init__.pyi
  5. 6 1
      magic/compat.py
  6. 2 2
      setup.py
  7. 9 1
      test/test.py
  8. 10 4
      test_docker.sh

+ 1 - 0
.gitignore

@@ -10,3 +10,4 @@ pip-selfcheck.json
 pyvenv.cfg
 *.pyc
 *~
+dist/

+ 6 - 0
CHANGELOG

@@ -1,3 +1,9 @@
+Changes to 0.4.25:
+  - Support os.PathLike values in Magic.from_file and magic.from_file
+  - Handle some versions of libmagic that return mime string without charset
+  - Fix tests for file 5.41
+  - Include typing stub in package
+
 Changes to 0.4.24:
  - Fix regression in library loading on some Alpine docker images.
 

+ 17 - 0
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

+ 3 - 2
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: ...
 

+ 6 - 1
magic/compat.py

@@ -245,7 +245,12 @@ none_magic.load()
 
 
 def _create_filemagic(mime_detected, type_detected):
-    mime_type, mime_encoding = mime_detected.split('; ')
+    splat = mime_detected.split('; ')
+    mime_type = splat[0]
+    if len(splat) == 2:
+        mime_encoding = splat[1]
+    else:
+        mime_encoding = ''
 
     return FileMagic(name=type_detected, mime_type=mime_type,
                      encoding=mime_encoding.replace('charset=', ''))

+ 2 - 2
setup.py

@@ -18,12 +18,12 @@ setuptools.setup(
     author='Adam Hupp',
     author_email='adam@hupp.org',
     url="http://github.com/ahupp/python-magic",
-    version='0.4.24',
+    version='0.4.25',
     long_description=read('README.md'),
     long_description_content_type='text/markdown',
     packages=['magic'],
     package_data={
-        'magic': ['py.typed'],
+        'magic': ['py.typed', '*.pyi', '**/*.pyi'],
     },
     keywords="mime magic file",
     license="MIT",

+ 9 - 1
test/test.py

@@ -90,7 +90,7 @@ class MagicTest(unittest.TestCase):
         try:
             m = magic.Magic(mime=True)
             self.assert_values(m, {
-                'magic._pyc_': ('application/octet-stream', 'text/x-bytecode.python'),
+                'magic._pyc_': ('application/octet-stream', 'text/x-bytecode.python', 'application/x-bytecode.python'),
                 'test.pdf': 'application/pdf',
                 'test.gz': ('application/gzip', 'application/x-gzip'),
                 'test.snappy.parquet': 'application/octet-stream',
@@ -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()

+ 10 - 4
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