[File] Python bindings to libmagic
Hoël Bézier
hoelbezier at leanco.fr
Tue Jul 19 08:48:46 UTC 2022
Hi, this is a follow-up to my previous email.
>So it seems to me that the `open` routine always returns a Magic
>object and cannot fail. The `_open` routine on the other hand might
>fail, and thus the returned Magic object would have a _magic_t
>attribute set to None.
>
>If I understood things properly, maybe the documentation would need to
>be updated so that users may handle failures properly.
I figured it would be best to update the code to reflect the documentation, so
I’ve attached a patch that should do exactly this. I’ve also added a bit of
error handling for the detect_from_* routines, using a magic.error exception.
Since I’m also trying to type my code whenever possible, the patch includes a
brand new magic.pyi file which contains type annotations for all public
routines and constants of the module. However, as I have no experience with
python packaging, I’m not sure this file would be included by the setup.py.
Feedback is of course welcome. :)
Hoël
-------------- next part --------------
diff --git a/python/magic.py b/python/magic.py
--- a/python/magic.py
+++ b/python/magic.py
@@ -272,16 +272,29 @@ def open(flags):
Returns a magic object on success and None on failure.
Flags argument as for setflags.
"""
- return Magic(_open(flags))
+ magic_t = _open(flags)
+ if magic_t is None:
+ return None
+ else:
+ return Magic(magic_t)
# Objects used by `detect_from_` functions
+class error(Exception):
+ pass
+
class MagicDetect(object):
def __init__(self):
- self.mime_magic = Magic(_open(MAGIC_MIME))
- self.mime_magic.load()
- self.none_magic = Magic(_open(MAGIC_NONE))
- self.none_magic.load()
+ self.mime_magic = open(MAGIC_MIME)
+ if self.mime_magic is None:
+ raise error
+ if self.mime_magic.load() == -1:
+ raise error
+ self.none_magic = open(MAGIC_NONE)
+ if self.none_magic is None:
+ raise error
+ if self.none_magic.load() == -1:
+ raise error
def __del__(self):
self.mime_magic.close()
diff --git a/python/magic.pyi b/python/magic.pyi
new file mode 100644
--- /dev/null
+++ b/python/magic.pyi
@@ -0,0 +1,93 @@
+from typing import NamedTuple
+from io import IOBase
+
+MAGIC_NONE: int
+NONE: int
+MAGIC_DEBUG: int
+DEBUG: int
+MAGIC_SYMLINK: int
+SYMLINK: int
+MAGIC_COMPRESS: int
+COMPRESS: int
+MAGIC_DEVICES: int
+DEVICES: int
+MAGIC_MIME_TYPE: int
+MIME_TYPE: int
+MAGIC_CONTINUE: int
+CONTINUE: int
+MAGIC_CHECK: int
+CHECK: int
+MAGIC_PRESERVE_ATIME: int
+PRESERVE_ATIME: int
+MAGIC_RAW: int
+RAW: int
+MAGIC_ERROR: int
+ERROR: int
+MAGIC_MIME_ENCODING: int
+MIME_ENCODING: int
+MAGIC_MIME: int
+MIME: int
+MAGIC_APPLE: int
+APPLE: int
+MAGIC_NO_CHECK_COMPRESS: int
+NO_CHECK_COMPRESS: int
+MAGIC_NO_CHECK_TAR: int
+NO_CHECK_TAR: int
+MAGIC_NO_CHECK_SOFT: int
+NO_CHECK_SOFT: int
+MAGIC_NO_CHECK_APPTYPE: int
+NO_CHECK_APPTYPE: int
+MAGIC_NO_CHECK_ELF: int
+NO_CHECK_ELF: int
+MAGIC_NO_CHECK_TEXT: int
+NO_CHECK_TEXT: int
+MAGIC_NO_CHECK_CDF: int
+NO_CHECK_CDF: int
+MAGIC_NO_CHECK_TOKENS: int
+NO_CHECK_TOKENS: int
+MAGIC_NO_CHECK_ENCODING: int
+NO_CHECK_ENCODING: int
+MAGIC_NO_CHECK_BUILTIN: int
+NO_CHECK_BUILTIN: int
+MAGIC_PARAM_INDIR_MAX: int
+PARAM_INDIR_MAX: int
+MAGIC_PARAM_NAME_MAX: int
+PARAM_NAME_MAX: int
+MAGIC_PARAM_ELF_PHNUM_MAX: int
+PARAM_ELF_PHNUM_MAX: int
+MAGIC_PARAM_ELF_SHNUM_MAX: int
+PARAM_ELF_SHNUM_MAX: int
+MAGIC_PARAM_ELF_NOTES_MAX: int
+PARAM_ELF_NOTES_MAX: int
+MAGIC_PARAM_REGEX_MAX: int
+PARAM_REGEX_MAX: int
+MAGIC_PARAM_BYTES_MAX: int
+PARAM_BYTES_MAX: int
+
+class FileMagic(NamedTuple):
+ mime_type: str
+ encoding: str
+ name: str
+
+class Magic:
+ def close(self) -> None: ...
+ def file(self, filename: str | bytes) -> str | None: ...
+ def descriptor(self, fd: int) -> str | None: ...
+ def buffer(self, buf: str | bytes) -> str | None: ...
+ def error(self) -> str | None: ...
+ def setflags(self, flags: int) -> int: ...
+ def load(self, filename: str | bytes | None = ...) -> int: ...
+ def compile(self, dbs: str | bytes) -> int: ...
+ def check(self, dbs: str | bytes) -> int: ...
+ def list(self, dbs: str | bytes) -> int: ...
+ def errno(self) -> int: ...
+ def getparam(self, param: int) -> int: ...
+ def setparam(self, param: int, value: int) -> int: ...
+
+def open(flags: int) -> Magic | None: ...
+
+class error(Exception): ...
+
+def detect_from_filename(filename: str | bytes) -> FileMagic: ...
+def detect_from_fobj(fobj: IOBase) -> FileMagic: ...
+def detect_from_content(byte_content: str | bytes) -> FileMagic: ...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://mailman.astron.com/pipermail/file/attachments/20220719/89fc29f3/attachment.asc>
More information about the File
mailing list