-
Notifications
You must be signed in to change notification settings - Fork 293
Build platform-specific wheels containing libmagic #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 38 commits
ec952d7
a437409
4a715e2
1adc0a5
20e2dc9
090b1d4
20d8fee
85d4422
2efa36d
0b43bc6
05df4f9
d2972b9
e182ae1
94718d5
359e007
bb9c685
b0fddf3
dc075e9
144132d
fe62a26
f7bbb03
2e6104e
ca4def3
ba87ffd
e112de3
eba05b6
8381a96
9c5f955
e6d5ed0
50504a2
9357f27
53d099b
9bf2e9c
f7341ce
da5b330
258efa4
3a55538
65fb61c
43c0c99
3e51048
d7b1171
620d78f
d3e886c
2bb9fa8
c8a599b
e1b154c
d111ace
33c827e
688edf0
9dd2ebc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "monthly" | ||
groups: | ||
github-actions: | ||
patterns: | ||
- "*" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
name: wheels | ||
|
||
on: | ||
pull_request: | ||
push: | ||
branches: master | ||
release: | ||
types: [released, prereleased] | ||
workflow_dispatch: # allows running workflow manually from the Actions tab | ||
|
||
jobs: | ||
|
||
build-sdist: | ||
runs-on: ubuntu-latest | ||
|
||
env: | ||
PIP_DISABLE_PIP_VERSION_CHECK: 1 | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.x' | ||
|
||
- run: sudo apt-get install -y libmagic1 | ||
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- name: Build source distribution | ||
run: | | ||
pip install --upgrade setuptools wheel pip | ||
python setup.py sdist | ||
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- uses: actions/upload-artifact@v4 | ||
with: | ||
name: dist | ||
path: dist/*.tar.* | ||
|
||
|
||
build-wheels-matrix: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
include: ${{ steps.set-matrix.outputs.include }} | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.x' | ||
- run: pip install cibuildwheel==2.17.0 # sync version with pypa/cibuildwheel below | ||
- id: set-matrix | ||
env: | ||
# only mention one (trivial) python version, as py2.py3 wheels only need to be build once per arch | ||
CIBW_PROJECT_REQUIRES_PYTHON: '==3.12.*' | ||
# skip PyPy wheels for now, and skip i686 wheels because pytest is failing | ||
CIBW_SKIP: pp* *i686 | ||
run: | | ||
MATRIX_INCLUDE=$( | ||
{ | ||
cibuildwheel --print-build-identifiers --platform linux --arch all | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ | ||
&& cibuildwheel --print-build-identifiers --platform macos --arch x86_64 | jq -nRc '{"only": inputs, "os": "macos-13"}' \ | ||
&& cibuildwheel --print-build-identifiers --platform macos --arch arm64 | jq -nRc '{"only": inputs, "os": "macos-14"}' \ | ||
&& cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | jq -nRc '{"only": inputs, "os": "windows-latest"}' | ||
} | jq -sc | ||
) | ||
echo "include=$MATRIX_INCLUDE" >> $GITHUB_OUTPUT | ||
|
||
|
||
build-wheels: | ||
name: build ${{ matrix.only }} | ||
needs: build-wheels-matrix | ||
runs-on: ${{ matrix.os }} | ||
|
||
strategy: | ||
fail-fast: false | ||
matrix: | ||
include: ${{ fromJson(needs.build-wheels-matrix.outputs.include) }} | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Set up QEMU | ||
if: runner.os == 'Linux' | ||
uses: docker/setup-qemu-action@v3 | ||
|
||
- uses: pypa/[email protected] # sync version with pip install cibuildwheel above | ||
timeout-minutes: 10 | ||
with: | ||
only: ${{ matrix.only }} | ||
env: | ||
CIBW_BUILD_VERBOSITY: 1 | ||
# add compiled libmagic to the build directory (to include in the wheel) | ||
CIBW_BEFORE_BUILD: ${{ ( startsWith( matrix.os, 'macos' ) && 'sudo -E bash add_libmagic.sh' ) || 'bash add_libmagic.sh' }} | ||
# build macos wheels with maximum backwards compatibility (gcc -mmacosx-version-min flag) | ||
MACOSX_DEPLOYMENT_TARGET: ${{ ( endsWith( matrix.only, 'arm64' ) && '11.0' ) || '10.9' }} | ||
# simple smoke test run on each wheel: this is an HLS MP4 video, only recognised in recent versions of libmagic | ||
CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypiso5\x00\x00\x00\x01isomiso5hlsf\x00\x00') == 'video/mp4'" | ||
|
||
- uses: actions/upload-artifact@v4 | ||
with: | ||
name: dist-${{ matrix.only }} | ||
path: wheelhouse/*.whl | ||
|
||
|
||
publish: | ||
if: github.event_name == 'release' | ||
needs: [build-sdist, build-wheels] | ||
runs-on: ubuntu-latest | ||
|
||
permissions: | ||
contents: write # softprops/action-gh-release | ||
id-token: write # pypa/gh-action-pypi-publish | ||
|
||
steps: | ||
- uses: actions/setup-python@v5 | ||
with: | ||
python-version: 3.x | ||
|
||
- uses: actions/download-artifact@v4 | ||
with: | ||
path: dist/ | ||
pattern: dist-* | ||
merge-multiple: true | ||
|
||
- run: ls -ltra dist/ | ||
|
||
- run: pip install --upgrade python-magic --find-links ./dist | ||
|
||
- name: Smoketest | ||
run: python -c "import magic; magic.Magic()" | ||
|
||
- name: Upload release assets | ||
uses: softprops/[email protected] | ||
with: | ||
files: dist/* | ||
|
||
- name: Publish package distributions to PyPI | ||
uses: pypa/[email protected] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,11 @@ | |
[](https://github.com/ahupp/python-magic/actions/workflows/ci.yml) | ||
[](https://gitter.im/ahupp/python-magic?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
|
||
python-magic is a Python interface to the libmagic file type | ||
identification library. libmagic identifies file types by checking | ||
[python-magic](https://github.com/ahupp/python-magic) is a Python interface to the libmagic file type | ||
identification library. libmagic identifies file types by checking | ||
their headers according to a predefined list of file types. This | ||
functionality is exposed to the command line by the Unix command | ||
`file`. | ||
[`file`](https://www.darwinsys.com/file/). | ||
|
||
## Usage | ||
|
||
|
@@ -31,8 +31,7 @@ will fail throw if this is attempted. | |
```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)' | ||
'ASCII text (gzip compressed data, was "test", last modified: Sat Jun 28 21:32:52 2008, from Unix)' | ||
``` | ||
|
||
You can also combine the flag options: | ||
|
@@ -45,27 +44,53 @@ You can also combine the flag options: | |
|
||
## Installation | ||
|
||
The current stable version of python-magic is available on PyPI and | ||
can be installed by running `pip install python-magic`. | ||
This module is a simple [CDLL](https://docs.python.org/3/library/ctypes.html) wrapper around the libmagic C library. | ||
The current stable version of python-magic is available on [PyPI](http://pypi.python.org/pypi/python-magic/) | ||
and can be installed by running `pip install python-magic`. | ||
|
||
Other sources: | ||
Compiled libmagic and the magic database come bundled in the wheels on PyPI. | ||
You can use your own `magic.mgc` database by setting the `MAGIC` | ||
environment variable, or by using `magic.Magic(magic_file='path/to/magic.mgc')`. | ||
If you want to compile your own libmagic, circumvent the wheels | ||
by installing from source: `pip install python-magic --no-binary python-magic`. | ||
|
||
- PyPI: http://pypi.python.org/pypi/python-magic/ | ||
- GitHub: https://github.com/ahupp/python-magic | ||
For systems not supported by the wheels, pip installs from source, | ||
requiring libmagic to be available before installing python-magic: | ||
|
||
This module is a simple wrapper around the libmagic C library, and | ||
that must be installed as well: | ||
### Linux | ||
|
||
### Debian/Ubuntu | ||
The Linux wheels should run on most systems out of the box. | ||
|
||
Depending on your system and CPU architecture, there might be no compatible wheel uploaded. | ||
However, precompiled libmagic might still be available for your system: | ||
|
||
```sh | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be beneficial to add a library installation guide for SUSE as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you provide the relevant command? fwiw, I think mostly all linux flavours will be covered by the wheels in the PR description, so those users won't be needing the install from source instructions provided here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that it would be Currently I don't have OpenSUSE at my disposal for tests and it's likely that it would be a default package. I don't promise anything, but I might find time soon-ish to test it. |
||
# Debian/Ubuntu | ||
apt-get update && apt-get install -y libmagic1 | ||
# Alpine | ||
apk add --update libmagic | ||
# RHEL | ||
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dnf install file-libs | ||
``` | ||
sudo apt-get install libmagic1 | ||
``` | ||
|
||
### Windows | ||
|
||
The DLLs that are bundled in the Windows wheels are compiled by @julian-r | ||
and are hosted at https://github.com/julian-r/file-windows/releases. | ||
|
||
For ARM64 Windows, you'll need to compile libmagic from source. | ||
|
||
### OSX | ||
|
||
- When using Homebrew: `brew install libmagic` | ||
- When using macports: `port install file` | ||
The Mac wheels are compiled with maximum backward compatibility. | ||
For older Macs, you'll need to install libmagic from source: | ||
|
||
```sh | ||
# homebrew | ||
brew install libmagic | ||
# macports | ||
port install file | ||
``` | ||
|
||
If python-magic fails to load the library it may be in a non-standard location, in which case you can set the environment variable `DYLD_LIBRARY_PATH` to point to it. | ||
|
||
|
@@ -78,7 +103,7 @@ If python-magic fails to load the library it may be in a non-standard location, | |
- 'MagicException: could not find any magic files!': some | ||
installations of libmagic do not correctly point to their magic | ||
database file. Try specifying the path to the file explicitly in the | ||
constructor: `magic.Magic(magic_file="path_to_magic_file")`. | ||
constructor: `magic.Magic(magic_file='path/to/magic.mgc')`. | ||
|
||
- 'WindowsError: [Error 193] %1 is not a valid Win32 application': | ||
Attempting to run the 32-bit libmagic DLL in a 64-bit build of | ||
|
@@ -88,7 +113,6 @@ If python-magic fails to load the library it may be in a non-standard location, | |
- 'WindowsError: exception: access violation writing 0x00000000 ' This may indicate you are mixing | ||
Windows Python and Cygwin Python. Make sure your libmagic and python builds are consistent. | ||
|
||
|
||
## Bug Reports | ||
|
||
python-magic is a thin layer over the libmagic C library. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -euxo pipefail | ||
|
||
install_source() { | ||
# install from source | ||
# https://www.darwinsys.com/file/ | ||
# https://github.com/file/file/blob/FILE5_45/INSTALL#L51 | ||
( | ||
version="file-5.45" && | ||
tmpfile="$(mktemp)" && | ||
curl -sSLo "${tmpfile}" "https://astron.com/pub/file/${version}.tar.gz" && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried it on ubuntu's Docker, fails here :)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, the script is only intended for github actions default runner images and the cibuildwheel docker images (both have curl and make) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
tar xvf "${tmpfile}" && | ||
Comment on lines
+11
to
+13
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big deal, but if going with the piped |
||
cd "${version}" && | ||
./configure && | ||
make && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dev dependencies to use "make" and similar commands are not shipped by default in some distros, especially in those that are usually used by Docker. I'd suggest to ensure that necessary dependencies are installed first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wished now, it simply falls back to if make is not available, in the current setup we will only have done an unnecessary curl. not the worst but could be avoided. any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It appears to be doing so already. Try this (and also the same script, but remove the first line or replace set -euxo pipefail
func(){
echo 1
(exit 1)
echo 2
}
func You made me think about other topic when you mentioned that install_stuff(){
real_install()
rm potential_zip
} |
||
make install && | ||
make installcheck && | ||
cd .. && | ||
rm -r "${version}" | ||
) || ( cd .. && false ) | ||
} | ||
|
||
install_precompiled() { | ||
# Mac https://formulae.brew.sh/formula/libmagic | ||
# Debian https://packages.ubuntu.com/libmagic1 | ||
# Alpine https://pkgs.alpinelinux.org/package/libmagic | ||
# RHEL https://git.almalinux.org/rpms/file | ||
# Windows https://github.com/julian-r/file-windows | ||
if [ -n "$(which brew)" ]; then | ||
brew install libmagic | ||
elif [ -n "$(which apt-get)" ]; then | ||
apt-get update | ||
apt-get install -y libmagic1 | ||
elif [ -n "$(which apk)" ]; then | ||
apk add --update libmagic | ||
elif [ -n "$(which dnf)" ]; then | ||
dnf --setopt install_weak_deps=false -y install file-libs | ||
else | ||
# windows (no install, just download into current working directory) | ||
# could also consider install using `pacman`: https://packages.msys2.org/base/mingw-w64-file | ||
# which would require an update of copy_libmagic below to account for new magic.mgc paths | ||
python <<EOF | ||
import platform, sysconfig, io, zipfile, urllib.request | ||
assert platform.system() == "Windows" | ||
machine = "x86" if sysconfig.get_platform() == "win32" else "x64" | ||
url = f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip" | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
print("Downloading", url) | ||
zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(url).read())).extractall(".") | ||
EOF | ||
# check what was copied | ||
ls -ltra | ||
fi | ||
} | ||
|
||
copy_libmagic() { | ||
# on cibuildwheel, the lib needs to exist in the project before running setup.py | ||
# copy lib into the magic dir, regardless of platform | ||
# this python command relies on current working directory containing `./magic/loader.py` | ||
libmagic_path="$(python -c 'from magic.loader import load_lib; print(load_lib()._name)')" && | ||
cp "${libmagic_path}" "magic" && | ||
# only on linux/macos: additionally copy compiled db into magic dir (prefer the one installed by install_source) | ||
( ( cp "/usr/local/share/misc/magic.mgc" "magic" || cp "/usr/share/misc/magic.mgc" "magic" ) || true ) && | ||
# check what was copied | ||
ls -ltra magic | ||
} | ||
|
||
# prefer a recent build from source | ||
install_source || install_precompiled | ||
# files to be copied into the wheel | ||
copy_libmagic |
Uh oh!
There was an error while loading. Please reload this page.