-
Couldn't load subscription status.
- Fork 304
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 all 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
57b2559
ed077fc
0571c11
ead0595
3ebe8bc
b4c04a3
49982d2
f99e6de
f35ff40
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,180 @@ | ||
| name: wheels | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: master | ||
| release: | ||
| types: [released, prereleased] | ||
| workflow_dispatch: # allows running workflow manually from the Actions tab | ||
|
|
||
| concurrency: # https://stackoverflow.com/questions/66335225#comment133398800_72408109 | ||
| group: ${{ github.workflow }}-${{ github.ref || github.run_id }} | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | ||
|
|
||
| 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 build | ||
| python -m build --sdist | ||
|
|
||
| - 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-15-intel"}' \ | ||
| && cibuildwheel --print-build-identifiers --platform macos --arch arm64 | jq -nRc '{"only": inputs, "os": "macos-15"}' \ | ||
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| && 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 | ||
|
|
||
| # For Windows, grabbing latest file from MSYS2 is easier than building from source | ||
| # It's generally up to date ref https://packages.msys2.org/base/mingw-w64-file | ||
| - name: Setup MSYS2 and install file | ||
| if: runner.os == 'Windows' | ||
| uses: msys2/[email protected] | ||
| with: | ||
| msystem: ${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }} | ||
| location: D:\ | ||
| install: >- | ||
| ${{ endsWith(matrix.only, '32') && 'mingw-w64-i686-file' || 'mingw-w64-x86_64-file' }} | ||
|
|
||
| # The DLL dependency tree flattened out ref "Dependencies" https://packages.msys2.org/packages/mingw-w64-x86_64-file | ||
| - name: Copy Windows ddl and mgc | ||
| if: runner.os == 'Windows' | ||
| run: | | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/share/misc/magic.mgc" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libmagic-1.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libsystre-0.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libtre-5.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libasprintf-0.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libintl-8.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libatomic-1.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libgomp-1.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libquadmath-0.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libstdc++-6.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libcharset-1.dll" "magic" | ||
| cp "/msys64/${{ endsWith(matrix.only, '32') && 'mingw32' || 'mingw64' }}/bin/libiconv-2.dll" "magic" | ||
|
|
||
| # These are needed additionally in the win32 wheel ref https://packages.msys2.org/packages/mingw-w64-i686-file | ||
| - name: Copy additional 32-bit runtime DLLs | ||
| if: runner.os == 'Windows' && endsWith(matrix.only, '32') | ||
| run: | | ||
| cp "/msys64/mingw32/bin/libgcc_s_dw2-1.dll" "magic" | ||
| cp "/msys64/mingw32/bin/libwinpthread-1.dll" "magic" | ||
|
|
||
| - 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_MACOS: sudo -E bash add_libmagic.sh | ||
| CIBW_BEFORE_BUILD_LINUX: bash add_libmagic.sh | ||
ddelange marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # 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,30 +44,58 @@ 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: | ||
| This module is a [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 explicitly 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, | ||
| which requires libmagic to be installed separately: | ||
|
|
||
| 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 built by MSYS2 ([mingw32](https://packages.msys2.org/packages/mingw-w64-i686-file) and [mingw64](https://packages.msys2.org/packages/mingw-w64-x86_64-file)). | ||
|
|
||
| For ARM64 Windows, you'll need to compile libmagic from source or [install](https://packages.msys2.org/packages/mingw-w64-clang-aarch64-file) from MSYS2. | ||
|
|
||
| ### 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. | ||
|
|
||
|
|
@@ -81,7 +108,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 | ||
|
|
@@ -91,7 +118,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,58 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| set -euxo pipefail | ||
|
|
||
| install_source() { | ||
| # install from source | ||
| # https://www.darwinsys.com/file/ | ||
| # https://github.com/file/file/blob/FILE5_46/INSTALL#L51 | ||
| ( | ||
| version="file-5.46" && | ||
| 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
}
funcYou 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 | ||
| 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 | ||
| 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" && | ||
| # 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 | ||
| } | ||
|
|
||
| # skip windows (taken care of separately in wheels.yml) | ||
| python -c 'import platform; assert platform.system() != "Windows"' || ( echo "skipping on windows" && exit 0 ) | ||
| # 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.