summaryrefslogtreecommitdiff
path: root/python/magic.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/magic.py')
-rw-r--r--python/magic.py116
1 files changed, 90 insertions, 26 deletions
diff --git a/python/magic.py b/python/magic.py
index a17e8da..662569e 100644
--- a/python/magic.py
+++ b/python/magic.py
@@ -1,10 +1,13 @@
-#!/usr/bin/env python
+# coding: utf-8
+
'''
Python bindings for libmagic
'''
import ctypes
+from collections import namedtuple
+
from ctypes import *
from ctypes.util import find_library
@@ -32,7 +35,7 @@ MAGIC_PRESERVE_ATIME = PRESERVE_ATIME = 128
MAGIC_RAW = RAW = 256
MAGIC_ERROR = ERROR = 512
MAGIC_MIME_ENCODING = MIME_ENCODING = 1024
-MAGIC_MIME = MIME = 1040
+MAGIC_MIME = MIME = 1040 # MIME_TYPE + MIME_ENCODING
MAGIC_APPLE = APPLE = 2048
MAGIC_NO_CHECK_COMPRESS = NO_CHECK_COMPRESS = 4096
@@ -47,6 +50,8 @@ MAGIC_NO_CHECK_ENCODING = NO_CHECK_ENCODING = 2097152
MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
+FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name'))
+
class magic_set(Structure):
pass
@@ -112,26 +117,43 @@ class Magic(object):
"""
_close(self._magic_t)
+ @staticmethod
+ def __tostr(s):
+ if s is None:
+ return None
+ if isinstance(s, str):
+ return s
+ try: # keep Python 2 compatibility
+ return str(s, 'utf-8')
+ except TypeError:
+ return str(s)
+
+ @staticmethod
+ def __tobytes(b):
+ if b is None:
+ return None
+ if isinstance(b, bytes):
+ return b
+ try: # keep Python 2 compatibility
+ return bytes(b, 'utf-8')
+ except TypeError:
+ return bytes(b)
+
def file(self, filename):
"""
Returns a textual description of the contents of the argument passed
as a filename or None if an error occurred and the MAGIC_ERROR flag
- is set. A call to errno() will return the numeric error code.
+ is set. A call to errno() will return the numeric error code.
"""
- try: # attempt python3 approach first
- if isinstance(filename, bytes):
- bi = filename
- else:
- bi = bytes(filename, 'utf-8')
- return str(_file(self._magic_t, bi), 'utf-8')
- except:
- return _file(self._magic_t, filename.encode('utf-8'))
+ return Magic.__tostr(_file(self._magic_t, Magic.__tobytes(filename)))
def descriptor(self, fd):
"""
- Like the file method, but the argument is a file descriptor.
+ Returns a textual description of the contents of the argument passed
+ as a file descriptor or None if an error occurred and the MAGIC_ERROR
+ flag is set. A call to errno() will return the numeric error code.
"""
- return _descriptor(self._magic_t, fd)
+ return Magic.__tostr(_descriptor(self._magic_t, fd))
def buffer(self, buf):
"""
@@ -139,20 +161,14 @@ class Magic(object):
as a buffer or None if an error occurred and the MAGIC_ERROR flag
is set. A call to errno() will return the numeric error code.
"""
- try: # attempt python3 approach first
- return str(_buffer(self._magic_t, buf, len(buf)), 'utf-8')
- except:
- return _buffer(self._magic_t, buf, len(buf))
+ return Magic.__tostr(_buffer(self._magic_t, buf, len(buf)))
def error(self):
"""
Returns a textual explanation of the last error or None
if there was no error.
"""
- try: # attempt python3 approach first
- return str(_error(self._magic_t), 'utf-8')
- except:
- return _error(self._magic_t)
+ return Magic.__tostr(_error(self._magic_t))
def setflags(self, flags):
"""
@@ -173,35 +189,38 @@ class Magic(object):
Returns 0 on success and -1 on failure.
"""
- return _load(self._magic_t, filename)
+ return _load(self._magic_t, Magic.__tobytes(filename))
def compile(self, dbs):
"""
Compile entries in the colon separated list of database files
passed as argument or the default database file if no argument.
- Returns 0 on success and -1 on failure.
The compiled files created are named from the basename(1) of each file
argument with ".mgc" appended to it.
+
+ Returns 0 on success and -1 on failure.
"""
- return _compile(self._magic_t, dbs)
+ return _compile(self._magic_t, Magic.__tobytes(dbs))
def check(self, dbs):
"""
Check the validity of entries in the colon separated list of
database files passed as argument or the default database file
if no argument.
+
Returns 0 on success and -1 on failure.
"""
- return _check(self._magic_t, dbs)
+ return _check(self._magic_t, Magic.__tobytes(dbs))
def list(self, dbs):
"""
Check the validity of entries in the colon separated list of
database files passed as argument or the default database file
if no argument.
+
Returns 0 on success and -1 on failure.
"""
- return _list(self._magic_t, dbs)
+ return _list(self._magic_t, Magic.__tobytes(dbs))
def errno(self):
"""
@@ -219,3 +238,48 @@ def open(flags):
Flags argument as for setflags.
"""
return Magic(_open(flags))
+
+
+# Objects used by `detect_from_` functions
+mime_magic = Magic(_open(MAGIC_MIME))
+mime_magic.load()
+none_magic = Magic(_open(MAGIC_NONE))
+none_magic.load()
+
+
+def _create_filemagic(mime_detected, type_detected):
+ mime_type, mime_encoding = mime_detected.split('; ')
+
+ return FileMagic(name=type_detected, mime_type=mime_type,
+ encoding=mime_encoding.replace('charset=', ''))
+
+
+def detect_from_filename(filename):
+ '''Detect mime type, encoding and file type from a filename
+
+ Returns a `FileMagic` namedtuple.
+ '''
+
+ return _create_filemagic(mime_magic.file(filename),
+ none_magic.file(filename))
+
+
+def detect_from_fobj(fobj):
+ '''Detect mime type, encoding and file type from file-like object
+
+ Returns a `FileMagic` namedtuple.
+ '''
+
+ file_descriptor = fobj.fileno()
+ return _create_filemagic(mime_magic.descriptor(file_descriptor),
+ none_magic.descriptor(file_descriptor))
+
+
+def detect_from_content(byte_content):
+ '''Detect mime type, encoding and file type from bytes
+
+ Returns a `FileMagic` namedtuple.
+ '''
+
+ return _create_filemagic(mime_magic.buffer(byte_content),
+ none_magic.buffer(byte_content))