Skip to content

Commit 53d099b

Browse files
committed
Merge branch 'master' of https://github.com/ahupp/python-magic into abi3-wheels
* 'master' of https://github.com/ahupp/python-magic: log warning on ctypes load error, adapted from ahupp#279 smartos support, adapted from ahupp#132 rename no_json test to avoid duplicate function definitions handle unknown platforms gracefully in loader.py Clean up loader.py
2 parents 9357f27 + a9e6276 commit 53d099b

3 files changed

Lines changed: 88 additions & 55 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ brew install libmagic
9292
port install file
9393
```
9494

95+
### SmartOS:
96+
- Install libmagic for source https://github.com/threatstack/libmagic/
97+
- Depending on your ./configure --prefix settings set your LD_LIBRARY_PATH to <prefix>/lib
98+
9599
### Troubleshooting
96100

97101
- 'MagicException: could not find any magic files!': some

magic/loader.py

Lines changed: 82 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,102 @@
11
from ctypes.util import find_library
22
import ctypes
3+
import sys
34
import glob
45
import os
6+
import logging
57
import subprocess
6-
import sys
8+
9+
logger = logging.getLogger(__name__)
10+
here = os.path.dirname(__file__)
11+
12+
def _lib_candidates_linux():
13+
"""Yield possible libmagic library names on Linux."""
14+
prefixes = ('libmagic.so.1', 'libmagic.so')
15+
16+
for i in prefixes:
17+
# libmagic bundled in the wheel
18+
yield os.path.join(here, i)
19+
# libmagic in the current working directory
20+
yield os.path.join(os.path.abspath('.'), i)
21+
# libmagic install from source default destination path
22+
yield os.path.join('/usr/local/lib', i)
23+
# on some linux systems (musl/alpine), find_library('magic') returns None
24+
# first try finding libmagic using ldconfig
25+
# otherwise fall back to /usr/lib/
26+
yield subprocess.check_output(
27+
"( ldconfig -p | grep '{0}' | grep -o '/.*' ) || echo '/usr/lib/{0}'".format(i),
28+
shell=True,
29+
universal_newlines=True,
30+
).strip()
31+
32+
33+
def _lib_candidates_macos():
34+
"""Yield possible libmagic library names on macOS."""
35+
paths = [
36+
# libmagic bundled in the wheel
37+
here,
38+
# libmagic in the current working directory
39+
os.path.abspath('.'),
40+
# libmagic in other common sources like homebrew
41+
'/opt/local/lib',
42+
'/usr/local/lib',
43+
'/opt/homebrew/lib',
44+
] + glob.glob('/usr/local/Cellar/libmagic/*/lib')
45+
46+
for i in paths:
47+
yield os.path.join(i, 'libmagic.dylib')
48+
49+
50+
def _lib_candidates_windows():
51+
"""Yield possible libmagic library names on Windows."""
52+
prefixes = (
53+
"libmagic",
54+
"magic1",
55+
"magic-1",
56+
"cygmagic-1",
57+
"libmagic-1",
58+
"msys-magic-1",
59+
)
60+
61+
for i in prefixes:
62+
# libmagic bundled in the wheel
63+
yield os.path.join(here, '%s.dll' % i)
64+
# libmagic in the current working directory
65+
yield os.path.join(os.path.abspath('.'), '%s.dll' % i)
66+
# find_library searches in %PATH% but not the current directory
67+
yield find_library(i)
68+
769

870
def _lib_candidates():
9-
here = os.path.dirname(__file__)
10-
11-
if sys.platform == 'darwin':
12-
13-
paths = [
14-
# libmagic bundled in the wheel
15-
here,
16-
# libmagic in the current working directory
17-
os.path.abspath('.'),
18-
# libmagic in other common sources like homebrew
19-
'/opt/local/lib',
20-
'/usr/local/lib',
21-
'/opt/homebrew/lib',
22-
] + glob.glob('/usr/local/Cellar/libmagic/*/lib')
23-
24-
for i in paths:
25-
yield os.path.join(i, 'libmagic.dylib')
26-
27-
elif sys.platform in ('win32', 'cygwin'):
28-
29-
prefixes = ['libmagic', 'magic1', 'magic-1', 'cygmagic-1', 'libmagic-1', 'msys-magic-1']
30-
31-
for i in prefixes:
32-
# libmagic bundled in the wheel
33-
yield os.path.join(here, '%s.dll' % i)
34-
# libmagic in the current working directory
35-
yield os.path.join(os.path.abspath('.'), '%s.dll' % i)
36-
# find_library searches in %PATH% but not the current directory
37-
yield find_library(i)
38-
39-
elif sys.platform == 'linux':
40-
41-
prefixes = ['libmagic.so.1', 'libmagic.so']
42-
43-
for i in prefixes:
44-
# libmagic bundled in the wheel
45-
yield os.path.join(here, i)
46-
# libmagic in the current working directory
47-
yield os.path.join(os.path.abspath('.'), i)
48-
# libmagic install from source default destination path
49-
yield os.path.join('/usr/local/lib', i)
50-
# on some linux systems (musl/alpine), find_library('magic') returns None
51-
# first try finding libmagic using ldconfig
52-
# otherwise fall back to /usr/lib/
53-
yield subprocess.check_output(
54-
"( ldconfig -p | grep '{0}' | grep -o '/.*' ) || echo '/usr/lib/{0}'".format(i),
55-
shell=True,
56-
universal_newlines=True,
57-
).strip()
71+
func = {
72+
"cygwin": _lib_candidates_windows,
73+
"darwin": _lib_candidates_macos,
74+
"linux": _lib_candidates_linux,
75+
"win32": _lib_candidates_windows,
76+
"sunos5": _lib_candidates_linux,
77+
}.get(sys.platform)
78+
if func is None:
79+
raise ImportError("python-magic: Unsupported platform: " + sys.platform)
80+
# When we drop legacy Python, we can just `yield from func()`
81+
for path in func():
82+
yield path
5883

5984
# fallback
6085
yield find_library('magic')
6186

6287

6388
def load_lib():
64-
6589
for lib in _lib_candidates():
6690
# find_library returns None when lib not found
6791
if lib is None:
6892
continue
93+
if not os.path.exists(lib):
94+
continue
95+
6996
try:
7097
return ctypes.CDLL(lib)
71-
except OSError: # file not found
72-
pass
73-
raise ImportError('failed to find libmagic. Check your installation')
98+
except OSError:
99+
logger.warning("Failed to load: " + lib, exc_info=True)
74100

101+
# It is better to raise an ImportError since we are importing magic module
102+
raise ImportError("python-magic: failed to find libmagic. Check your installation")

test/python_magic_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ def test_descriptions_no_json(self):
196196
buf_equals_file=True,
197197
)
198198

199-
def test_descriptions_no_json(self):
199+
def test_descriptions_no_json_unchanged(self):
200+
# verify non-json results are unchanged
200201
m = magic.Magic(check_json=False)
201202
os.environ["TZ"] = "UTC" # To get last modified date of test.gz in UTC
202203
try:

0 commit comments

Comments
 (0)