# python-magic: the module name collides with the bindings libmagic itself ships

> A ctypes wrapper around the C library behind the Unix file command, with a convenience function for one-off checks and a class for direct control. The class is documented as unsafe across threads, the file name you import collides with another module of the same name, and the package declares support all the way back to Python 2.7.

**ahupp/python-magic** — A python wrapper for libmagic

- Repository: https://github.com/ahupp/python-magic
- Stars: 2,920 · Forks: 307
- Language: Python
- License: NOASSERTION
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/ahupp-python-magic

## The module name collides with the bindings libmagic itself ships

The library you import is called magic, and so are the Python bindings that come with the C library. The readme states the conflict outright and says what was done about it: this package includes a compatibility layer for the C library's own API, with a separate compatibility document at the root of the repository explaining how the two APIs relate. So the same import name resolves to different things depending on which package is installed, and a project that has both on its path is in the situation the compatibility document exists to resolve. It is worth checking which one answered the import before trusting a result, because the failure is silent: both answer, and they do not have the same interface.

## The class is documented as unsafe to share across threads

There are two ways to use this. There is a module level function for a one-off check, and there is a class that gives more direct control, including overriding the path to the magic database and turning on character encoding detection:

```python
>>> f = magic.Magic(uncompress=True)
>>> f.from_file('testdata/test.gz')
'ASCII text (gzip compressed data, was "test", last modified: Sat Jun 28
21:32:52 2008, from Unix)'
```

The readme says plainly that the class is not recommended for general use, and that in particular it is not safe for sharing across multiple threads and will fail if that is attempted. The mechanism is not described, but the consequence is specific enough to act on: the object wraps a native library handle, so one instance per thread or a lock around it. A web application that keeps a single instance in a module global and serves requests from a worker pool is exactly the shape the warning describes.

## Reading fewer than two kilobytes can produce a wrong answer

The usage examples carry a comment that is easy to read past, and it is the most practically useful line in the file. It recommends using at least the first two thousand and forty eight bytes, because less can produce an incorrect identification. The example shows both calls side by side:

```python
>>> import magic
>>> magic.from_file("testdata/test.pdf")
'PDF document, version 1.2'
# recommend using at least the first 2048 bytes, as less can produce incorrect identification
>>> magic.from_buffer(open("testdata/test.pdf", "rb").read(2048))
'PDF document, version 1.2'
```

So the buffer variant is not a convenience with a rough edge; for many formats the header is all that is needed, and for others a short read returns a guess. Anyone reading a small buffer to save memory should treat the result as unverified.

## Two of the three documented failures need a different libmagic build

The troubleshooting section is specific about failure messages, which makes it the most useful part of the file. One is about the magic database not being found, and the fix is to pass the path to that file explicitly in the constructor. The other two are about Windows. One error, the invalid Win32 application one, means a thirty two bit library has been loaded into a sixty four bit interpreter, and the file links two separate third party repositories carrying sixty four bit builds. The third error, an access violation writing to a null address, means a native Windows interpreter and a Cygwin one have been mixed, and the fix is to make the library and interpreter builds consistent. Both are environment problems rather than bugs, and both have a documented cause and a documented fix.

## Most reported bugs belong upstream and go to a personal tracker

The bug reporting section sets an expectation before you file anything. It says this is a thin layer over the C library, that historically most bugs reported against it are actually bugs in the C library, and that those should go to the C library's own tracker, which the file links. That tracker is hosted as a personal issue page rather than as a project site. If you are unsure where a fault lies, the readme invites an issue on GitHub and offers to triage it. The practical consequence is that the package's own issue tracker is explicitly not the right place for a misdetection, which is the failure people are most likely to report, and that diagnosis has to happen across two projects.

## The declared floor is Python 2.7 and the classifiers stop at 3.13

The packaging metadata carries two different statements about which interpreters are supported. The version requirement is a lower bound of two point seven with five exclusions for interpreter versions three point zero through three point four. The classifier list, by contrast, names Python two point seven and then versions three point five through three point thirteen, and only the one C implementation. So the declared floor has not moved in fifteen years while the classifier list has been kept current. That combination is common in old packaging and it is mostly harmless, since a lower bound permits newer interpreters, but it does mean the metadata claims a range nobody has tested in this century. The test instructions, which use a multi interpreter runner, are the part that reflects real coverage.

## The author separates his own licence from his employer's

The licence section does something unusual at the end. It states that the code is under the MIT licence and points at the included licence file, then adds that the code in this repository is provided under an open source licence and that because this is a personal repository, the licence covering the author's code comes from the author rather than from the employer, naming that employer. The repository's own metadata records no licence at all, so a reader relying on the metadata alone gets nothing, while the packaging file, the classifier list and the readme all name MIT and a licence file is present in the tree. The clarification about the employer is the part worth copying into other personal repositories, because it removes an ambiguity that open source contributions from employees routinely create.

## There is no release tag and the version lives in the packaging script

The repository has no releases. The version number is in the packaging script, and the readme describes the numbering policy without any link to a tag list: minor version bumps should be backwards compatible, and major bumps are not. That policy is stated in one sentence and is the only versioning contract the project publishes. The last push to the default branch is dated 2026-09-22, and the package is distributed through a package index rather than from the repository, so a consumer who wants to know what changed between two installed versions has a changelog file with no extension at the root of the tree and nothing else to compare against.

## Conclusion

Reach for this when you have to identify a file by its contents rather than its extension, and prefer the single-shot function over the class unless you need its options. Three things to know before you rely on it. The import name is ambiguous, because the C library ships bindings under the same module name, so check which one you actually got. The class holds a native handle and is documented as unsafe to share between threads, which rules it out for a request handler that runs concurrently. And reading a truncated buffer is documented as a source of wrong answers, so the two kilobyte floor in the examples is a correctness constraint and not a performance hint.

## FAQ

### How do I install Python-magic?

The package installs from PyPI with a pip command, but the C library it wraps must be installed separately as well. The README gives per platform instructions: an apt command for Debian and Ubuntu, and either a Homebrew or a MacPorts command for macOS.

### What does ahupp/python-magic do?

It is a Python interface to the C library that identifies file types by checking their headers against a predefined list, the same library behind the Unix file command. It was first written in 2001, originally using SWIG and later switched to ctypes once that was in the standard library.

### Is python-magic safe to use across threads?

The module level function for a one-off check is presented as the normal entry point. The Magic class, which offers more direct control, is documented as not recommended for general use and specifically not safe for sharing across multiple threads, and it will fail if that is attempted.

### Why does python-magic sometimes give the wrong file type?

The README states that you should read at least the first 2048 bytes, because reading less can produce an incorrect identification. It also lists a separate failure where the magic database cannot be found, which is fixed by passing the path to that file explicitly in the constructor.

### How is python-magic different from the Python mimetypes module?

The repository makes no comparison to the standard library module. What it does document is a name collision: the Python bindings shipped with the underlying C library use a module name that conflicts with this package, and a compatibility layer is included for the C library API with a separate document explaining it.

## Sources

- [ahupp/python-magic on GitHub](https://github.com/ahupp/python-magic)
- [Issues](https://github.com/ahupp/python-magic/issues)
- [README](https://github.com/ahupp/python-magic/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ahupp-python-magic
