Skip to main content

magical_py

Native Python bindings for magical_rs, a zero-dependency Rust library that identifies files by their magic bytes.

This is not a drop-in replacement for python-magic, and it is not trying to be one. python-magic returns a string like "image/png" and leaves you to parse it. This returns a typed value that carries its media type and conventional extension with it.

Install

pip install magical-py

There is a binary wheel for every platform we publish for. One abi3 wheel covers CPython 3.8 and later, so you will not have to build from source.

FileKind covers all 114 formats the Rust crate detects, and the enum is declared in Python rather than generated, so it is a real enum.Enum and your editor completes FileKind. with every member and its docstring.

Use

from magical_py import FileKind, detect

kind = detect("photo.jpg")

kind is FileKind.Jpg      # True, a real enum member your editor can complete
kind.value                 # 'jpg', a stable id for serialising
kind.mime                  # 'image/jpeg'
kind.extension             # 'jpg'
kind.description           # 'JPEG'

For data you already have in memory:

from magical_py import detect_bytes

detect_bytes(header)       # FileKind.Png | None

Both return None when nothing matches, and raise the usual OSError subclasses when a file cannot be read:

try:
    kind = detect(path)
except FileNotFoundError:
    kind = None

What it looks like

Each member carries its display name as its __doc__, which is the attribute the REPL and help() read. Python 3.9 and later render it for all 114 members; Python 3.8 omits it from help(), so on 3.8 read __doc__ directly as below.

>>> FileKind.Png.__doc__
'PNG'
>>> FileKind.ISO.__doc__
'ISO 9660'
>>> FileKind.PkgZip.description
'Zip / JAR / APK'

Things worth knowing

Detection reads magic bytes only. The file name is never consulted, so a .jpg that actually contains PNG data is reported as FileKind.Png. That is the behaviour you want from a detection library, and it is also why the extension is advisory rather than something to switch on.

Some media types are None. FileKind.mime and FileKind.extension return None when no media type is registered or verified for that format. None means "there isn't one", never "we guessed". A wrong media type would be a documentation bug of the same kind as a wrong magic byte, and this project does not ship those.

detect reads 36,870 bytes. ISO 9660 stores its magic at offset 36,865, so detecting it means reading that far into the file. detect does that for you; magical_py.bytes_read() reports the figure if you are reading headers yourself. Do not hardcode 2048 and assume you are done.

Some signatures are only two bytes. 9 formats match on nothing but a two-byte prefix: Arj, Bitmap, Gzip, MP3, MSDOS, Pcx, Pickle, SerializedJavaData and Zlib. Those are the values the formats themselves specify, so a file beginning with those bytes is reported as that format even if it is not really one. Each one is listed with its bytes in the magical_rs README.

Two rules look at more than a fixed pattern. FileKind.ScriptExecute requires a / later on the first line, so a bare #! does not count; FileKind.WEBP requires the full RIFF....WEBP layout. The shebang rule exists because #!AMR is the literal magic of AMR audio: without the / check, the script rule claimed those files and they became undetectable.

Type checking

The package ships a py.typed marker and stubs for the compiled module, and it is checked with pyright in strict mode. pythonVersion is pinned to 3.8 so the checker enforces the same floor as the wheel.

from magical_py import FileKind

# Narrowed to FileKind after the None check.
kind: FileKind | None = detect("photo.jpg")
if kind is not None:
    reveal_type(kind)     # FileKind
    reveal_type(kind.mime)  # str | None

Development

Managed with uv.

uv sync                # create the venv and install maturin, pytest, pyright
uv run maturin develop # build the extension into the venv
uv run pytest          # run the tests
uv run pyright         # type check in strict mode
uv build               # build the wheel and the sdist

python/magical_py/_kinds.py is generated. Edit the metadata table in gen_kinds.ps1 and re-run it; tests/test_drift.py fails if the enum and the Rust detection table disagree.

License

MIT, the same as magical_rs.

Metadata

Release files for magical-py 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for magical-py 0.1.1
File Size Uploaded
magical_py-0.1.1.tar.gz 69.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for magical-py 0.1.1
File
magical_py-0.1.1-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details
magical_py-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 abi3 Linux glibc 2.17+ x86-64 Details
magical_py-0.1.1-cp38-abi3-macosx_11_0_arm64.whl CPython 3.8 abi3 macOS 11.0+ ARM64 Details
magical_py-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl CPython 3.8 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.2 MB

Release files / magical_py-0.1.1.tar.gz

Download URL magical_py-0.1.1.tar.gz
Size 69.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3548245ebf686525b67e390b9bab76dd290e14619c0b0e241c67dc92ffaecc79
BLAKE2b-256 checksum
How to use checksums
9f67347a5bdbce0d76d68d5e8e898a38bd390aedd531a1a19692ca3d6d4413a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / magical_py-0.1.1-cp38-abi3-win_amd64.whl

Download URL magical_py-0.1.1-cp38-abi3-win_amd64.whl
Size 187.8 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
13533500a1df67a8b57eaa9323eaba8ac63150cf678c46b76a44df6dfcb55c39
BLAKE2b-256 checksum
How to use checksums
a9f705432d0c627cf994cd496423ea7d314317bf172d6248882080735e3d587b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / magical_py-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL magical_py-0.1.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.2 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
5c5b588a249ac85a0ef2804d7de98e86e7c939fbc301cb61eb3e373ab0c26127
BLAKE2b-256 checksum
How to use checksums
291c6af29c686835490e9847befed7e12983c60671d698be306d7ee2f9b2bbb6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / magical_py-0.1.1-cp38-abi3-macosx_11_0_arm64.whl

Download URL magical_py-0.1.1-cp38-abi3-macosx_11_0_arm64.whl
Size 348.1 kB
Tags CPython 3.8 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d722ece14a9f178a4a5d236db54400fa4323b7db549d2ca606935054214af7a1
BLAKE2b-256 checksum
How to use checksums
19d86071a6f30da85fe95beb860cf79dc91b0db86178ba2d98bfd0d24dd391d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / magical_py-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl

Download URL magical_py-0.1.1-cp38-abi3-macosx_10_12_x86_64.whl
Size 325.5 kB
Tags CPython 3.8 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
9f2dd39ed6d314205abfdfb72ee1b295989fc701f74a338af134d51ccef44505
BLAKE2b-256 checksum
How to use checksums
a4276cdeeddb22f02dee73762070375bda31099dabcf957707c605815a8fd199
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.20 {"installer":{"name":"uv","version":"0.12.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.5.0

5 release files

0.4.0

5 release files

0.3.0

5 release files

0.2.0

5 release files

This release

0.1.1 This release

5 release files

0.1.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page