From ec952d7633856aa495ef46104d8cd3eed9ee74be Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:09:12 +0200 Subject: [PATCH 01/33] Build platform-specific wheels containing libmagic --- .github/workflows/main.yml | 134 +++++++++++++++++++++++++++++++++++++ Makefile | 20 ++++++ README.md | 37 ++++++---- magic/__init__.py | 7 +- magic/loader.py | 73 +++++++++++--------- setup.py | 29 +++++++- 6 files changed, 255 insertions(+), 45 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 Makefile diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..771bcd4 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,134 @@ +name: GH + +permissions: + contents: write + +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@v3 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - run: sudo apt-get install -y libmagic1 + + - name: Build source distribution + run: | + pip install -U setuptools wheel pip + python setup.py sdist + + - uses: actions/upload-artifact@v3 + with: + name: dist + path: dist/*.tar.* + + + build-wheels-matrix: + runs-on: ubuntu-latest + outputs: + include: ${{ steps.set-matrix.outputs.include }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - run: pip install cibuildwheel==2.15.0 + - id: set-matrix + env: + CIBW_PROJECT_REQUIRES_PYTHON: '==3.8.*' + run: | + MATRIX_INCLUDE=$( + { + cibuildwheel --print-build-identifiers --platform linux --arch x86_64,aarch64,i686 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ + && cibuildwheel --print-build-identifiers --platform macos --arch x86_64,arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-11"}' \ + && cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}' + } | jq -sc + ) + echo "include=$MATRIX_INCLUDE" >> $GITHUB_OUTPUT + + + build-wheels: + needs: build-wheels-matrix + runs-on: ${{ matrix.os }} + name: Build ${{ matrix.only }} + + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.build-wheels-matrix.outputs.include) }} + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 + + - uses: pypa/cibuildwheel@v2.15.0 + timeout-minutes: 10 + with: + only: ${{ matrix.only }} + env: + CIBW_BUILD_VERBOSITY: 1 + CIBW_BEFORE_BUILD: 'bash -c "make install_libmagic"' + + - uses: actions/upload-artifact@v3 + with: + name: dist + path: wheelhouse/*.whl + + + publish: + needs: [build-sdist, build-wheels] + if: github.event_name == 'release' + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v4 + with: + python-version: 3.x + + - uses: actions/download-artifact@v3 + with: + name: dist + path: dist/ + + - run: ls -ltra dist/ + + - run: pip install -U twine python-magic --find-links ./dist + + - name: Smoketest + run: python -c "import magic; magic.Magic()" + + - name: Upload release assets + uses: softprops/action-gh-release@v0.1.15 + with: + files: dist/* + + - name: Upload to PyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + twine upload dist/* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cd6b92e --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +SHELL := /bin/bash + +.PHONY: install_libmagic +## Install libmagic +install_libmagic: + # Debian https://packages.ubuntu.com/libmagic1 + # RHEL https://git.almalinux.org/rpms/file + # Mac https://formulae.brew.sh/formula/libmagic + # Windows https://github.com/julian-r/file-windows + ( ( ( brew install libmagic || ( apt-get update && apt-get install -y libmagic1 ) ) || apk add --update libmagic ) || yum install file-libs ) || ( python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && ls -ltra ) + # on cibuildwheel, the lib needs to exist in the project before running setup.py + python -c "import subprocess; from magic.loader import load_lib; lib = load_lib()._name; print(f'linking {lib}'); subprocess.check_call(['cp', lib, 'magic'])" + cp /usr/share/misc/magic.mgc magic || true # only on linux + ls -ltra magic + +.DEFAULT_GOAL := help +.PHONY: help +## Print Makefile documentation +help: + @perl -0 -nle 'printf("\033[36m %-15s\033[0m %s\n", "$$2", "$$1") while m/^##\s*([^\r\n]+)\n^([\w.-]+):[^=]/gm' $(MAKEFILE_LIST) | sort diff --git a/README.md b/README.md index fb1bc0e..2d22ec8 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,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: @@ -53,26 +52,40 @@ Other sources: - GitHub: https://github.com/ahupp/python-magic This module is a simple wrapper around the libmagic C library, and -that must be installed as well: +comes bundled in the wheels on PyPI. For systems not supported by the wheels, libmagic +needs to be installed before installing this library: -### Debian/Ubuntu +### Linux -``` -sudo apt-get install libmagic1 +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 +# Debian/Ubuntu +apt-get update && apt-get install -y libmagic1 +# Alpine +apk add --update libmagic +# RHEL +yum install file-libs ``` ### Windows -You'll need DLLs for libmagic. @julian-r maintains a pypi package with the DLLs, you can fetch it with: +The DLLs that are bundled in the Windows wheels are compiled by @julian-r and hosted at https://github.com/julian-r/file-windows/releases. -``` -pip install python-magic-bin -``` +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 on GitHub Actions using `macos-11` runners. For older Macs, you'll need to install libmagic from source: + +```sh +# homebrew +brew install libmagic +# macports +port install file +``` ### Troubleshooting diff --git a/magic/__init__.py b/magic/__init__.py index d05ebf9..552fe9e 100644 --- a/magic/__init__.py +++ b/magic/__init__.py @@ -330,7 +330,12 @@ def magic_descriptor(cookie, fd): def magic_load(cookie, filename): - return _magic_load(cookie, coerce_filename(filename)) + try: + return _magic_load(cookie, coerce_filename(filename)) + except MagicException: + # wheels package the mime database in this directory + filename = os.path.join(os.path.dirname(__file__), 'magic.mgc') + return _magic_load(cookie, coerce_filename(filename)) magic_setflags = libmagic.magic_setflags diff --git a/magic/loader.py b/magic/loader.py index 228a35c..8ece31d 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -1,50 +1,61 @@ from ctypes.util import find_library import ctypes -import sys import glob import os.path +import subprocess +import sys def _lib_candidates(): + here = os.path.dirname(__file__) - yield find_library('magic') + if sys.platform == 'darwin': - if sys.platform == 'darwin': + paths = [ + here, + os.path.abspath("."), + '/opt/local/lib', + '/usr/local/lib', + '/opt/homebrew/lib', + ] + glob.glob('/usr/local/Cellar/libmagic/*/lib') - paths = [ - '/opt/local/lib', - '/usr/local/lib', - '/opt/homebrew/lib', - ] + glob.glob('/usr/local/Cellar/libmagic/*/lib') + for i in paths: + yield os.path.join(i, 'libmagic.dylib') - for i in paths: - yield os.path.join(i, 'libmagic.dylib') + elif sys.platform in ('win32', 'cygwin'): - elif sys.platform in ('win32', 'cygwin'): + prefixes = ['libmagic', 'magic1', 'magic-1', 'cygmagic-1', 'libmagic-1', 'msys-magic-1'] - prefixes = ['libmagic', 'magic1', 'magic-1', 'cygmagic-1', 'libmagic-1', 'msys-magic-1'] + for i in prefixes: + # find_library searches in %PATH% but not the current directory, + # so look for both + yield os.path.join(here, '%s.dll' % i) + yield os.path.join(os.path.abspath("."), '%s.dll' % i) + yield find_library(i) - for i in prefixes: - # find_library searches in %PATH% but not the current directory, - # so look for both - yield './%s.dll' % (i,) - yield find_library(i) + elif sys.platform == 'linux': + # on some linux systems (musl/alpine), find_library('magic') returns None + yield subprocess.check_output( + "( ldconfig -p | grep 'libmagic.so.1' | grep -o '/.*' ) || echo '/usr/lib/libmagic.so.1'", + shell=True, + universal_newlines=True, + ).strip() + yield os.path.join(here, 'libmagic.so.1') + yield os.path.join(os.path.abspath("."), 'libmagic.so.1') - elif sys.platform == 'linux': - # This is necessary because alpine is bad - yield 'libmagic.so.1' + yield find_library('magic') def load_lib(): - for lib in _lib_candidates(): - # find_library returns None when lib not found - if lib is None: - continue - try: - return ctypes.CDLL(lib) - except OSError: - pass - else: - # It is better to raise an ImportError since we are importing magic module - raise ImportError('failed to find libmagic. Check your installation') + for lib in _lib_candidates(): + # find_library returns None when lib not found + if lib is None: + continue + try: + return ctypes.CDLL(lib) + except OSError as exc: + pass + else: + # It is better to raise an ImportError since we are importing magic module + raise ImportError('failed to find libmagic. Check your installation') diff --git a/setup.py b/setup.py index d98b731..cab8dd0 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,11 @@ import setuptools import io import os +import sys +# python packages should not install succesfully if libraries are missing +from magic.loader import load_lib +lib = load_lib()._name def read(file_name): """Read a text file and return the content as a string.""" @@ -12,6 +16,28 @@ def read(file_name): encoding='utf-8') as f: return f.read() +def get_cmdclass(): + """Build a forward compatible ABI3 wheel when `setup.py bdist_wheel` is called.""" + if sys.version_info[0] == 2: + return {} + + try: + from wheel.bdist_wheel import bdist_wheel + except ImportError: + return {} + + class bdist_wheel_abi3(bdist_wheel): + def get_tag(self): + python, abi, _ = super().get_tag() + # get the platform tag based on libmagic included in this wheel + self.root_is_pure = False + _, _, plat = super().get_tag() + return python, abi, plat + + return {"bdist_wheel": bdist_wheel_abi3} + +cmdclass = get_cmdclass() + setuptools.setup( name='python-magic', description='File type identification using libmagic', @@ -23,8 +49,9 @@ def read(file_name): long_description_content_type='text/markdown', packages=['magic'], package_data={ - 'magic': ['py.typed', '*.pyi', '**/*.pyi'], + 'magic': ['py.typed', '*.pyi', '*.dylib*', '*.dll', '*.so*', 'magic.mgc'] }, + cmdclass=cmdclass, keywords="mime magic file", license="MIT", python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', From a437409745805a30a9956ffe619023dd83fa3178 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:29:05 +0200 Subject: [PATCH 02/33] Move persmissions into job scope, remove ABI3 reference --- .github/workflows/main.yml | 10 +++++----- setup.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 771bcd4..8f11f4d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,8 +1,5 @@ name: GH -permissions: - contents: write - on: pull_request: push: @@ -67,9 +64,9 @@ jobs: build-wheels: + name: Build ${{ matrix.only }} needs: build-wheels-matrix runs-on: ${{ matrix.os }} - name: Build ${{ matrix.only }} strategy: fail-fast: false @@ -100,10 +97,13 @@ jobs: publish: - needs: [build-sdist, build-wheels] if: github.event_name == 'release' + needs: [build-sdist, build-wheels] runs-on: ubuntu-latest + permissions: + contents: write + steps: - uses: actions/setup-python@v4 with: diff --git a/setup.py b/setup.py index cab8dd0..0668882 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ def read(file_name): return f.read() def get_cmdclass(): - """Build a forward compatible ABI3 wheel when `setup.py bdist_wheel` is called.""" + """Build a platform-specific wheel when `setup.py bdist_wheel` is called.""" if sys.version_info[0] == 2: return {} @@ -26,7 +26,7 @@ def get_cmdclass(): except ImportError: return {} - class bdist_wheel_abi3(bdist_wheel): + class bdist_wheel_platform_specific(bdist_wheel): def get_tag(self): python, abi, _ = super().get_tag() # get the platform tag based on libmagic included in this wheel @@ -34,7 +34,7 @@ def get_tag(self): _, _, plat = super().get_tag() return python, abi, plat - return {"bdist_wheel": bdist_wheel_abi3} + return {"bdist_wheel": bdist_wheel_platform_specific} cmdclass = get_cmdclass() From 4a715e2b849373ddec19a2c9191090a706afeca9 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:23:57 +0100 Subject: [PATCH 03/33] Switch to PyPI trusted publishing --- .github/workflows/main.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8f11f4d..5430534 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -102,7 +102,8 @@ jobs: runs-on: ubuntu-latest permissions: - contents: write + contents: write # softprops/action-gh-release + id-token: write # pypa/gh-action-pypi-publish steps: - uses: actions/setup-python@v4 @@ -116,7 +117,7 @@ jobs: - run: ls -ltra dist/ - - run: pip install -U twine python-magic --find-links ./dist + - run: pip install -U python-magic --find-links ./dist - name: Smoketest run: python -c "import magic; magic.Magic()" @@ -126,9 +127,5 @@ jobs: with: files: dist/* - - name: Upload to PyPI - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - twine upload dist/* + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@v1.8.10 From 1adc0a5ad9dac344ac9e99ca7c4af7bfe1020090 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:31:52 +0100 Subject: [PATCH 04/33] Add CIBW_TEST_COMMAND and indent Makefile --- .github/workflows/main.yml | 8 +++++--- Makefile | 15 ++++++++++++--- magic/loader.py | 31 +++++++++++++++++-------------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5430534..1b1e841 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,7 +48,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.x' - - run: pip install cibuildwheel==2.15.0 + - run: pip install cibuildwheel==2.16.2 # sync version with pypa/cibuildwheel below - id: set-matrix env: CIBW_PROJECT_REQUIRES_PYTHON: '==3.8.*' @@ -82,13 +82,15 @@ jobs: if: runner.os == 'Linux' uses: docker/setup-qemu-action@v2 - - uses: pypa/cibuildwheel@v2.15.0 + - uses: pypa/cibuildwheel@v2.16.2 # sync version with pip install cibuildwheel above timeout-minutes: 10 with: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 - CIBW_BEFORE_BUILD: 'bash -c "make install_libmagic"' + MACOSX_DEPLOYMENT_TARGET: 11.0 # oldest available github runner ("macos-11" above) + CIBW_BEFORE_BUILD: bash -c "make install_libmagic" + CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" - uses: actions/upload-artifact@v3 with: diff --git a/Makefile b/Makefile index cd6b92e..0f524b7 100644 --- a/Makefile +++ b/Makefile @@ -3,14 +3,23 @@ SHELL := /bin/bash .PHONY: install_libmagic ## Install libmagic install_libmagic: + # 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 - # Mac https://formulae.brew.sh/formula/libmagic # Windows https://github.com/julian-r/file-windows - ( ( ( brew install libmagic || ( apt-get update && apt-get install -y libmagic1 ) ) || apk add --update libmagic ) || yum install file-libs ) || ( python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && ls -ltra ) + ( ( ( \ + brew install libmagic \ + || ( apt-get update && apt-get install -y libmagic1 ) ) \ + || apk add --update libmagic ) \ + || yum install file-libs ) \ + || ( python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && ls -ltra ) # on cibuildwheel, the lib needs to exist in the project before running setup.py + # copy lib into the magic dir, regardless of platform python -c "import subprocess; from magic.loader import load_lib; lib = load_lib()._name; print(f'linking {lib}'); subprocess.check_call(['cp', lib, 'magic'])" - cp /usr/share/misc/magic.mgc magic || true # only on linux + # only on linux: additionally copy compiled db into magic dir + cp /usr/share/misc/magic.mgc magic || true + # check what was copied ls -ltra magic .DEFAULT_GOAL := help diff --git a/magic/loader.py b/magic/loader.py index 8ece31d..6b0f254 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -12,7 +12,7 @@ def _lib_candidates(): paths = [ here, - os.path.abspath("."), + os.path.abspath('.'), '/opt/local/lib', '/usr/local/lib', '/opt/homebrew/lib', @@ -29,18 +29,23 @@ def _lib_candidates(): # find_library searches in %PATH% but not the current directory, # so look for both yield os.path.join(here, '%s.dll' % i) - yield os.path.join(os.path.abspath("."), '%s.dll' % i) + yield os.path.join(os.path.abspath('.'), '%s.dll' % i) yield find_library(i) elif sys.platform == 'linux': - # on some linux systems (musl/alpine), find_library('magic') returns None - yield subprocess.check_output( - "( ldconfig -p | grep 'libmagic.so.1' | grep -o '/.*' ) || echo '/usr/lib/libmagic.so.1'", - shell=True, - universal_newlines=True, - ).strip() - yield os.path.join(here, 'libmagic.so.1') - yield os.path.join(os.path.abspath("."), 'libmagic.so.1') + + prefixes = ['libmagic.so.1', 'libmagic.so'] + + for i in prefixes: + yield os.path.join(here, i) + yield os.path.join(os.path.abspath('.'), i) + # on some linux systems (musl/alpine), find_library('magic') returns None + # first try ldconfig with backup string in case of error + yield subprocess.check_output( + "( ldconfig -p | grep '{0}' | grep -o '/.*' ) || echo '/usr/lib/{0}'".format(i), + shell=True, + universal_newlines=True, + ).strip() yield find_library('magic') @@ -53,9 +58,7 @@ def load_lib(): continue try: return ctypes.CDLL(lib) - except OSError as exc: + except OSError: # file not found pass - else: - # It is better to raise an ImportError since we are importing magic module - raise ImportError('failed to find libmagic. Check your installation') + raise ImportError('failed to find libmagic. Check your installation') From 090b1d4b07d0d27a7b7e63417b74046aacaf6271 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:39:21 +0100 Subject: [PATCH 05/33] Fix CI for macos --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1b1e841..9e0c8cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,7 +51,7 @@ jobs: - run: pip install cibuildwheel==2.16.2 # sync version with pypa/cibuildwheel below - id: set-matrix env: - CIBW_PROJECT_REQUIRES_PYTHON: '==3.8.*' + CIBW_PROJECT_REQUIRES_PYTHON: '==3.10.*' run: | MATRIX_INCLUDE=$( { @@ -88,7 +88,6 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 - MACOSX_DEPLOYMENT_TARGET: 11.0 # oldest available github runner ("macos-11" above) CIBW_BEFORE_BUILD: bash -c "make install_libmagic" CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" From 20d8feed55d06452d52b328b27bdc62f08860b6f Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:47:31 +0100 Subject: [PATCH 06/33] Add dependabot.yml --- .github/dependabot.yml | 10 ++++++++++ .github/workflows/main.yml | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..2390d8c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9e0c8cf..60abc55 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,12 +17,12 @@ jobs: PIP_DISABLE_PIP_VERSION_CHECK: 1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' @@ -33,7 +33,7 @@ jobs: pip install -U setuptools wheel pip python setup.py sdist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: dist path: dist/*.tar.* @@ -44,14 +44,14 @@ jobs: outputs: include: ${{ steps.set-matrix.outputs.include }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - run: pip install cibuildwheel==2.16.2 # sync version with pypa/cibuildwheel below - id: set-matrix env: - CIBW_PROJECT_REQUIRES_PYTHON: '==3.10.*' + CIBW_PROJECT_REQUIRES_PYTHON: '==3.11.*' run: | MATRIX_INCLUDE=$( { @@ -74,13 +74,13 @@ jobs: include: ${{ fromJson(needs.build-wheels-matrix.outputs.include) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up QEMU if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - uses: pypa/cibuildwheel@v2.16.2 # sync version with pip install cibuildwheel above timeout-minutes: 10 @@ -91,7 +91,7 @@ jobs: CIBW_BEFORE_BUILD: bash -c "make install_libmagic" CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: dist path: wheelhouse/*.whl @@ -107,11 +107,11 @@ jobs: id-token: write # pypa/gh-action-pypi-publish steps: - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.x - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: dist path: dist/ From 85d4422468dc98247f697c43ac5288f909438976 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:56:40 +0100 Subject: [PATCH 07/33] Migrate actions/upload-artifact@v4 ref https://github.com/actions/download-artifact/blob/v4.1.1/docs/MIGRATION.md#multiple-uploads-to-the-same-named-artifact --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 60abc55..7c87a2d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -93,7 +93,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: dist + name: dist-${{ matrix.only }} path: wheelhouse/*.whl @@ -113,8 +113,9 @@ jobs: - uses: actions/download-artifact@v4 with: - name: dist path: dist/ + pattern: dist-* + merge-multiple: true - run: ls -ltra dist/ From 2efa36d6a9f3add74983ba6dde04a0d050f090fd Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:51:21 +0100 Subject: [PATCH 08/33] Ensure magic.mgc packaged in wheel gets recognised --- magic/__init__.py | 9 ++++----- magic/loader.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/magic/__init__.py b/magic/__init__.py index 46cee19..5d7a47d 100644 --- a/magic/__init__.py +++ b/magic/__init__.py @@ -354,12 +354,11 @@ def magic_descriptor(cookie, fd): def magic_load(cookie, filename): - try: - return _magic_load(cookie, coerce_filename(filename)) - except MagicException: + mime_db = os.path.join(os.path.dirname(__file__), 'magic.mgc') + if os.path.exists(mime_db): # wheels package the mime database in this directory - filename = os.path.join(os.path.dirname(__file__), 'magic.mgc') - return _magic_load(cookie, coerce_filename(filename)) + return _magic_load(cookie, coerce_filename(mime_db)) + return _magic_load(cookie, coerce_filename(filename)) magic_setflags = libmagic.magic_setflags diff --git a/magic/loader.py b/magic/loader.py index 6b0f254..5150107 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -1,7 +1,7 @@ from ctypes.util import find_library import ctypes import glob -import os.path +import os import subprocess import sys From 0b43bc6b7fa08274ed37e1d02b32c8728b01e452 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Mon, 1 Apr 2024 08:48:23 +0200 Subject: [PATCH 09/33] Add note about --no-binary to the installation instructions --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d22ec8..826df3a 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,11 @@ Other sources: - GitHub: https://github.com/ahupp/python-magic This module is a simple wrapper around the libmagic C library, and -comes bundled in the wheels on PyPI. For systems not supported by the wheels, libmagic -needs to be installed before installing this library: +comes bundled in the wheels on PyPI. +If you want to use your own (custom) libmagic installation, +circumvent the wheels by running `pip install python-magic --no-binary python-magic`. +For systems not supported by the wheels, libmagic +needs to be installed before installing python-magic: ### Linux From 05df4f91646bb1fba6d80d722940166223263b5a Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:35:06 +0200 Subject: [PATCH 10/33] Separate mac versions --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7c87a2d..d4d15fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -56,7 +56,8 @@ jobs: MATRIX_INCLUDE=$( { cibuildwheel --print-build-identifiers --platform linux --arch x86_64,aarch64,i686 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ - && cibuildwheel --print-build-identifiers --platform macos --arch x86_64,arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-11"}' \ + && cibuildwheel --print-build-identifiers --platform macos --arch x86_64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-13"}' \ + && cibuildwheel --print-build-identifiers --platform macos --arch arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-14"}' \ && cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}' } | jq -sc ) From d2972b9a16b56a4afeb00c52d943c4b39cba334b Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:50:39 +0200 Subject: [PATCH 11/33] Update cibuildwheel --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d4d15fa..5c4d634 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,10 +48,10 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.x' - - run: pip install cibuildwheel==2.16.2 # sync version with pypa/cibuildwheel below + - run: pip install cibuildwheel==2.17.0 # sync version with pypa/cibuildwheel below - id: set-matrix env: - CIBW_PROJECT_REQUIRES_PYTHON: '==3.11.*' + CIBW_PROJECT_REQUIRES_PYTHON: '==3.12.*' run: | MATRIX_INCLUDE=$( { @@ -83,7 +83,7 @@ jobs: if: runner.os == 'Linux' uses: docker/setup-qemu-action@v3 - - uses: pypa/cibuildwheel@v2.16.2 # sync version with pip install cibuildwheel above + - uses: pypa/cibuildwheel@v2.17.0 # sync version with pip install cibuildwheel above timeout-minutes: 10 with: only: ${{ matrix.only }} From e182ae17b71d5188365d555f7a41a31dcd3e1047 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:59:27 +0200 Subject: [PATCH 12/33] Bump pypa/gh-action-pypi-publish@v1.8.14 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c4d634..ee0307b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -131,4 +131,4 @@ jobs: files: dist/* - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@v1.8.10 + uses: pypa/gh-action-pypi-publish@v1.8.14 From 94718d593f9c3a602eab1ace0478ad57f5c36058 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:46:14 +0200 Subject: [PATCH 13/33] Bump cibuildwheel docker images --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee0307b..f571789 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,6 +89,8 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 + CIBW_MANYLINUX_*_IMAGE: manylinux_2_28 # get a more recent libmagic1 + CIBW_MUSLLINUX_*_IMAGE: musllinux_1_2 CIBW_BEFORE_BUILD: bash -c "make install_libmagic" CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" From 359e0070e99e71861bfa6d99857f1c7ce2c79fea Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:51:29 +0200 Subject: [PATCH 14/33] Revert "Bump cibuildwheel docker images" This reverts commit 94718d593f9c3a602eab1ace0478ad57f5c36058. --- .github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f571789..ee0307b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,8 +89,6 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 - CIBW_MANYLINUX_*_IMAGE: manylinux_2_28 # get a more recent libmagic1 - CIBW_MUSLLINUX_*_IMAGE: musllinux_1_2 CIBW_BEFORE_BUILD: bash -c "make install_libmagic" CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" From bb9c685075139ea89c9b241c465c64bf1cffee3d Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:55:40 +0200 Subject: [PATCH 15/33] Move magic.mgc injection into Magic class --- magic/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/magic/__init__.py b/magic/__init__.py index 5d7a47d..31f54af 100644 --- a/magic/__init__.py +++ b/magic/__init__.py @@ -96,6 +96,12 @@ def __init__(self, mime=False, magic_file=None, mime_encoding=False, self.cookie = magic_open(self.flags) self.lock = threading.Lock() + if magic_file is None and not os.environ.get("MAGIC"): + # wheels package the mime database in this directory + # prefer it when no magic file is specified by the user + mime_db = os.path.join(os.path.dirname(__file__), 'magic.mgc') + if os.path.exists(mime_db): + magic_file = mime_db magic_load(self.cookie, magic_file) # MAGIC_EXTENSION was added in 523 or 524, so bail if @@ -354,10 +360,6 @@ def magic_descriptor(cookie, fd): def magic_load(cookie, filename): - mime_db = os.path.join(os.path.dirname(__file__), 'magic.mgc') - if os.path.exists(mime_db): - # wheels package the mime database in this directory - return _magic_load(cookie, coerce_filename(mime_db)) return _magic_load(cookie, coerce_filename(filename)) From b0fddf3666a7659b29963be894368030b00b78c3 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:45:48 +0200 Subject: [PATCH 16/33] Build on more recent cibw images --- .github/workflows/main.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee0307b..8aea933 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,6 +89,18 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 + CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_PYPY_X86_64_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_PPC64LE_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_S390X_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_PYPY_AARCH64_IMAGE: manylinux_2_28 + CIBW_MANYLINUX_PYPY_I686_IMAGE: manylinux_2_28 + CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 + CIBW_MUSLLINUX_I686_IMAGE: musllinux_1_2 + CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 + CIBW_MUSLLINUX_PPC64LE_IMAGE: musllinux_1_2 + CIBW_MUSLLINUX_S390X_IMAGE: musllinux_1_2 CIBW_BEFORE_BUILD: bash -c "make install_libmagic" CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" From dc075e9d8102fe49f99f5a16542ee42dde31824d Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:07:42 +0200 Subject: [PATCH 17/33] Use hls mp4 (recent libmagic only) for testing --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8aea933..ddfa9a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: CIBW_MUSLLINUX_PPC64LE_IMAGE: musllinux_1_2 CIBW_MUSLLINUX_S390X_IMAGE: musllinux_1_2 CIBW_BEFORE_BUILD: bash -c "make install_libmagic" - CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" + 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: From 144132de360f7c1a2d7584c5418a6282640a4738 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:09:56 +0200 Subject: [PATCH 18/33] Revert "Use hls mp4 (recent libmagic only) for testing" This reverts commit dc075e9d8102fe49f99f5a16542ee42dde31824d. manylinux_2_28 is not available for i686 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ddfa9a0..8aea933 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: CIBW_MUSLLINUX_PPC64LE_IMAGE: musllinux_1_2 CIBW_MUSLLINUX_S390X_IMAGE: musllinux_1_2 CIBW_BEFORE_BUILD: bash -c "make install_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'" + CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" - uses: actions/upload-artifact@v4 with: From fe62a26b1af9d07ee15ad726167c7ddeefbbe9bd Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:31:06 +0200 Subject: [PATCH 19/33] Install from source --- .github/workflows/main.yml | 18 +++---------- Makefile | 29 -------------------- add_libmagic.sh | 54 ++++++++++++++++++++++++++++++++++++++ magic/loader.py | 1 + 4 files changed, 58 insertions(+), 44 deletions(-) delete mode 100644 Makefile create mode 100755 add_libmagic.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8aea933..be891d7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,7 +55,7 @@ jobs: run: | MATRIX_INCLUDE=$( { - cibuildwheel --print-build-identifiers --platform linux --arch x86_64,aarch64,i686 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ + cibuildwheel --print-build-identifiers --platform linux --arch all | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ && cibuildwheel --print-build-identifiers --platform macos --arch x86_64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-13"}' \ && cibuildwheel --print-build-identifiers --platform macos --arch arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-14"}' \ && cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}' @@ -89,20 +89,8 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 - CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_PYPY_X86_64_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_PPC64LE_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_S390X_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_PYPY_AARCH64_IMAGE: manylinux_2_28 - CIBW_MANYLINUX_PYPY_I686_IMAGE: manylinux_2_28 - CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2 - CIBW_MUSLLINUX_I686_IMAGE: musllinux_1_2 - CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2 - CIBW_MUSLLINUX_PPC64LE_IMAGE: musllinux_1_2 - CIBW_MUSLLINUX_S390X_IMAGE: musllinux_1_2 - CIBW_BEFORE_BUILD: bash -c "make install_libmagic" - CIBW_TEST_COMMAND: python -c "import magic; assert magic.Magic(mime=True).from_buffer(b'\x00\x00\x00\x1cftypisom\x00\x00\x02\x00isomiso2mp41\x00') == 'video/mp4'" + CIBW_BEFORE_BUILD: bash "add_libmagic.sh" + 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: diff --git a/Makefile b/Makefile deleted file mode 100644 index 0f524b7..0000000 --- a/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -SHELL := /bin/bash - -.PHONY: install_libmagic -## Install libmagic -install_libmagic: - # 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 - ( ( ( \ - brew install libmagic \ - || ( apt-get update && apt-get install -y libmagic1 ) ) \ - || apk add --update libmagic ) \ - || yum install file-libs ) \ - || ( python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && ls -ltra ) - # on cibuildwheel, the lib needs to exist in the project before running setup.py - # copy lib into the magic dir, regardless of platform - python -c "import subprocess; from magic.loader import load_lib; lib = load_lib()._name; print(f'linking {lib}'); subprocess.check_call(['cp', lib, 'magic'])" - # only on linux: additionally copy compiled db into magic dir - cp /usr/share/misc/magic.mgc magic || true - # check what was copied - ls -ltra magic - -.DEFAULT_GOAL := help -.PHONY: help -## Print Makefile documentation -help: - @perl -0 -nle 'printf("\033[36m %-15s\033[0m %s\n", "$$2", "$$1") while m/^##\s*([^\r\n]+)\n^([\w.-]+):[^=]/gm' $(MAKEFILE_LIST) | sort diff --git a/add_libmagic.sh b/add_libmagic.sh new file mode 100755 index 0000000..7db7b17 --- /dev/null +++ b/add_libmagic.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +install_source() { + version="file-5.45" + ( + tmpfile="$(mktemp)" && + curl -sSLo "${tmpfile}" "https://astron.com/pub/file/${version}.tar.gz" && + tar xvf "${tmpfile}" && + cd "${version}" && + ./configure && + make && + make install && + make installcheck && + cd .. && + rm -r "${version}" + ) || (cd .. && rm -r "${version}" && 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 yum)" ]; then + yum install file-libs + else + python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && + 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 + libmagic_path="$(python -c 'from magic.loader import load_lib; print(load_lib()._name)')" && + cp "${libmagic_path}" "magic" && + # only on linux: additionally copy compiled db into magic dir + ( ( cp "/usr/local/share/misc/magic.mgc" "magic" || cp "/usr/share/misc/magic.mgc" "magic" ) || true ) && + # check what was copied + ls -ltra magic +} + +install_source || install_precompiled +copy_libmagic diff --git a/magic/loader.py b/magic/loader.py index 5150107..3778fde 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -39,6 +39,7 @@ def _lib_candidates(): for i in prefixes: yield os.path.join(here, i) yield os.path.join(os.path.abspath('.'), i) + yield os.path.join('/usr/local/lib', i) # on some linux systems (musl/alpine), find_library('magic') returns None # first try ldconfig with backup string in case of error yield subprocess.check_output( From f7bbb030064c8e095a9b49ee78c91bcff163cef8 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:46:14 +0200 Subject: [PATCH 20/33] Documentation and readability --- .github/workflows/main.yml | 2 ++ README.md | 40 +++++++++++++++++++------------------- add_libmagic.sh | 19 ++++++++++++++++-- magic/loader.py | 15 +++++++++++--- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index be891d7..b750441 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,7 +89,9 @@ jobs: only: ${{ matrix.only }} env: CIBW_BUILD_VERBOSITY: 1 + # add compiled libmagic to the build directory (to include in the wheel) CIBW_BEFORE_BUILD: bash "add_libmagic.sh" + # 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 diff --git a/README.md b/README.md index 826df3a..4c9c7d7 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ [![PyPI version](https://badge.fury.io/py/python-magic.svg)](https://badge.fury.io/py/python-magic) [![Build Status](https://travis-ci.org/ahupp/python-magic.svg?branch=master)](https://travis-ci.org/ahupp/python-magic) [![Join the chat at https://gitter.im/ahupp/python-magic](https://badges.gitter.im/ahupp/python-magic.svg)](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 @@ -43,26 +43,25 @@ 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 - -This module is a simple wrapper around the libmagic C library, and -comes bundled in the wheels on PyPI. -If you want to use your own (custom) libmagic installation, -circumvent the wheels by running `pip install python-magic --no-binary python-magic`. -For systems not supported by the wheels, libmagic -needs to be installed before installing python-magic: +For systems not supported by the wheels, pip installs from source, +requiring libmagic to be available before installing python-magic: ### Linux 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: +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 # Debian/Ubuntu @@ -75,13 +74,15 @@ yum install file-libs ### Windows -The DLLs that are bundled in the Windows wheels are compiled by @julian-r and hosted at https://github.com/julian-r/file-windows/releases. +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 -The Mac wheels are compiled on GitHub Actions using `macos-11` runners. For older Macs, you'll need to install libmagic from source: +The Mac wheels are compiled with maximum backward compatibility. +For older Macs, you'll need to install libmagic from source: ```sh # homebrew @@ -95,7 +96,7 @@ port install file - '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 @@ -105,7 +106,6 @@ port install file - '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. diff --git a/add_libmagic.sh b/add_libmagic.sh index 7db7b17..faf1c15 100755 --- a/add_libmagic.sh +++ b/add_libmagic.sh @@ -3,6 +3,9 @@ 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)" && @@ -34,7 +37,16 @@ install_precompiled() { elif [ -n "$(which yum)" ]; then yum install file-libs else - python -c 'import platform, sysconfig, io, zipfile, urllib.request; assert platform.system() == "Windows"; machine = "x86" if sysconfig.get_platform() == "win32" else "x64"; print(machine); zipfile.ZipFile(io.BytesIO(urllib.request.urlopen(f"https://github.com/julian-r/file-windows/releases/download/v5.44/file_5.44-build104-vs2022-{machine}.zip").read())).extractall(".")' && + # windows (no install, just download into current working directory) + python < Date: Mon, 6 May 2024 08:54:18 +0200 Subject: [PATCH 21/33] Build macos wheels with maximum backwards compatibility --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b750441..f0b21ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,9 @@ jobs: env: CIBW_BUILD_VERBOSITY: 1 # add compiled libmagic to the build directory (to include in the wheel) - CIBW_BEFORE_BUILD: bash "add_libmagic.sh" + 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'" From ca4def380c04cdf48152709772a41ae2b08d3cfb Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Mon, 6 May 2024 11:37:57 +0200 Subject: [PATCH 22/33] Use CIBW_SKIP i686 fails pytest with: /project/test/python_magic_test.py:54: in assert_values self.assertIn(value, expected_value) E AssertionError: 'gzip compressed data, was test, last modified: *Invalid datetime*, from Unix' not found in ('gzip compressed data, was test, from Unix, last modified: Sun Jun 29 01:32:52 2008', 'gzip compressed data, was test, last modified: Sun Jun 29 01:32:52 2008, from Unix', 'gzip compressed data, was test, last modified: Sun Jun 29 01:32:52 2008, from Unix, original size 15', 'gzip compressed data, was test, last modified: Sun Jun 29 01:32:52 2008, from Unix, original size modulo 2^32 15', 'gzip compressed data, was test, last modified: Sun Jun 29 01:32:52 2008, from Unix, truncated') --- .github/workflows/main.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f0b21ec..78f5076 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,14 +51,17 @@ jobs: - 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 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ - && cibuildwheel --print-build-identifiers --platform macos --arch x86_64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-13"}' \ - && cibuildwheel --print-build-identifiers --platform macos --arch arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-14"}' \ - && cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}' + 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 From ba87ffd09ed9f2c00bfdbaa00fcdb59377c8906b Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Mon, 20 May 2024 15:28:52 +0200 Subject: [PATCH 23/33] Apply suggestions from code review Co-authored-by: Christian Clauss --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78f5076..82e8a83 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ jobs: - name: Build source distribution run: | - pip install -U setuptools wheel pip + pip install --upgrade setuptools wheel pip python setup.py sdist - uses: actions/upload-artifact@v4 @@ -127,7 +127,7 @@ jobs: - run: ls -ltra dist/ - - run: pip install -U python-magic --find-links ./dist + - run: pip install --upgrade python-magic --find-links ./dist - name: Smoketest run: python -c "import magic; magic.Magic()" From eba05b637838cf4db2ec7d88993eb10692c6f802 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 22 May 2024 11:23:44 +0200 Subject: [PATCH 24/33] Fix compat.py now that bundled libmagic is preferred --- magic/compat.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/magic/compat.py b/magic/compat.py index 07fad45..a8b0610 100644 --- a/magic/compat.py +++ b/magic/compat.py @@ -5,6 +5,7 @@ ''' import ctypes +import os from collections import namedtuple @@ -16,6 +17,13 @@ _libraries = {} _libraries['magic'] = loader.load_lib() +magic_file = None +if not os.environ.get("MAGIC"): + # wheels package the mime database in this directory + # prefer it when no magic file is specified by the user + mime_db = os.path.join(os.path.dirname(__file__), 'magic.mgc') + if os.path.exists(mime_db): + magic_file = mime_db # Flag constants for open and setflags MAGIC_NONE = NONE = 0 @@ -178,7 +186,7 @@ def setflags(self, flags): """ return _setflags(self._magic_t, flags) - def load(self, filename=None): + def load(self, filename=magic_file): """ Must be called to load entries in the colon separated list of database files passed as argument or the default database file if no argument From 8381a96775eacbfd08a6063dee45ff1c9e74f116 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 22 May 2024 11:30:19 +0200 Subject: [PATCH 25/33] Fix https://github.com/ahupp/python-magic/issues/321 --- .github/workflows/ci.yml | 5 +---- .github/workflows/{main.yml => wheels.yml} | 2 +- setup.py | 2 +- test/python_magic_test.py | 6 ------ 4 files changed, 3 insertions(+), 12 deletions(-) rename .github/workflows/{main.yml => wheels.yml} (99%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c4e4c9..14ec482 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,13 +19,10 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true + - run: ${{ ( startsWith( matrix.os, 'macos' ) && 'sudo -E bash add_libmagic.sh' ) || 'bash add_libmagic.sh' }} - run: pip install --upgrade pip - run: pip install --upgrade pytest - run: pip install --editable . - - if: runner.os == 'macOS' - run: brew install libmagic - - if: runner.os == 'Windows' - run: pip install python-magic-bin - run: LC_ALL=en_US.UTF-8 pytest shell: bash timeout-minutes: 15 # Limit Windows infinite loop. diff --git a/.github/workflows/main.yml b/.github/workflows/wheels.yml similarity index 99% rename from .github/workflows/main.yml rename to .github/workflows/wheels.yml index 82e8a83..c922a55 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/wheels.yml @@ -1,4 +1,4 @@ -name: GH +name: wheels on: pull_request: diff --git a/setup.py b/setup.py index 0668882..e06fa07 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ # python packages should not install succesfully if libraries are missing from magic.loader import load_lib -lib = load_lib()._name +load_lib()._name def read(file_name): """Read a text file and return the content as a string.""" diff --git a/test/python_magic_test.py b/test/python_magic_test.py index 633fcab..ce19903 100755 --- a/test/python_magic_test.py +++ b/test/python_magic_test.py @@ -5,8 +5,6 @@ import tempfile import unittest -import pytest - # for output which reports a local time os.environ["TZ"] = "GMT" @@ -120,8 +118,6 @@ def test_mime_types(self): finally: os.unlink(dest) - # TODO: Fix this failing test on Ubuntu - @pytest.mark.skipif(sys.platform == "linux", reason="'JSON data' not found") def test_descriptions(self): m = magic.Magic() os.environ["TZ"] = "UTC" # To get last modified date of test.gz in UTC @@ -161,8 +157,6 @@ def test_descriptions(self): finally: del os.environ["TZ"] - # TODO: Fix this failing test on Ubuntu - @pytest.mark.skipif(sys.platform == "linux", reason="'JSON data' not found") def test_descriptions_no_soft(self): m = magic.Magic(check_soft=False) self.assert_values( From 9c5f955dd9b3b8d2130754f01ccba592597b8e0e Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 22 May 2024 11:31:42 +0200 Subject: [PATCH 26/33] Use sudo on ubuntu-latest in ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14ec482..481abe2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - run: ${{ ( startsWith( matrix.os, 'macos' ) && 'sudo -E bash add_libmagic.sh' ) || 'bash add_libmagic.sh' }} + - run: sudo -E bash add_libmagic.sh - run: pip install --upgrade pip - run: pip install --upgrade pytest - run: pip install --editable . From e6d5ed00afedae1db1c21c5ed774f1882cc7e459 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 22 May 2024 12:05:14 +0200 Subject: [PATCH 27/33] Fix sudo not available on windows-latest --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 481abe2..eda77f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - run: sudo -E bash add_libmagic.sh + - run: ${{ ( startsWith( matrix.os, 'windows' ) && 'bash add_libmagic.sh' ) || 'sudo -E bash add_libmagic.sh' }} - run: pip install --upgrade pip - run: pip install --upgrade pytest - run: pip install --editable . From 9357f27e215f12efb8a67694a807384a3f847d50 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 23 May 2024 09:26:30 +0200 Subject: [PATCH 28/33] Add entries in CHANGELOG --- CHANGELOG | 12 ++++++++---- add_libmagic.sh | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a8370c6..eb7cac9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,14 @@ -Changes to 0.4.29: +Changes to 0.4.28: +- libmagic and magic.mgc now come bundled in the wheels on PyPI, and will be copied + into site-packages/magic along with the Python files of this library +- magic.loader.load_lib now first searches for libmagic in the same directory as the + Python files, then in the current working directory, and only then in standard paths +- magic.Magic(magic_file=...) and magic.compat.Magic.load(magic_file=...) will now + prefer "magic.mgc" in the same directory as the Python files, only if left + unspecified by the user (and the MAGIC env var is empty or not set) - support MAGIC_SYMLINK (via follow_symlink flag on Magic constructor) - correctly throw FileNotFoundException depending on flag - -Changes to 0.4.28: - - support "magic-1.dll" on Windows, which is produced by vcpkg - add python 3.10 to tox config - update test for upstream gzip extensions diff --git a/add_libmagic.sh b/add_libmagic.sh index faf1c15..af447b3 100755 --- a/add_libmagic.sh +++ b/add_libmagic.sh @@ -38,6 +38,7 @@ install_precompiled() { yum 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 python < Date: Sun, 26 May 2024 13:24:33 +0200 Subject: [PATCH 29/33] Fix test --- test/python_magic_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python_magic_test.py b/test/python_magic_test.py index 2dc50c3..47646c6 100755 --- a/test/python_magic_test.py +++ b/test/python_magic_test.py @@ -191,7 +191,7 @@ def test_descriptions_no_json(self): self.assert_values( m, { - "test.json": "data", + "test.json": "JSON text data", }, buf_equals_file=True, ) From f7341ce9449455ace8171455fe8414ed22f2be01 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Sun, 26 May 2024 14:14:02 +0200 Subject: [PATCH 30/33] PR Suggestions --- magic/loader.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/magic/loader.py b/magic/loader.py index ac19473..1a5f378 100644 --- a/magic/loader.py +++ b/magic/loader.py @@ -11,20 +11,20 @@ def _lib_candidates_linux(): """Yield possible libmagic library names on Linux.""" - prefixes = ('libmagic.so.1', 'libmagic.so') + fnames = ('libmagic.so.1', 'libmagic.so') - for i in prefixes: + for fname in fnames: # libmagic bundled in the wheel - yield os.path.join(here, i) + yield os.path.join(here, fname) # libmagic in the current working directory - yield os.path.join(os.path.abspath('.'), i) + yield os.path.join(os.path.abspath('.'), fname) # libmagic install from source default destination path - yield os.path.join('/usr/local/lib', i) + yield os.path.join('/usr/local/lib', fname) # on some linux systems (musl/alpine), find_library('magic') returns None # first try finding libmagic using ldconfig # otherwise fall back to /usr/lib/ yield subprocess.check_output( - "( ldconfig -p | grep '{0}' | grep -o '/.*' ) || echo '/usr/lib/{0}'".format(i), + "( ldconfig -p | grep '{0}' | grep -o '/.*' ) || echo '/usr/lib/{0}'".format(fname), shell=True, universal_newlines=True, ).strip() @@ -43,13 +43,13 @@ def _lib_candidates_macos(): '/opt/homebrew/lib', ] + glob.glob('/usr/local/Cellar/libmagic/*/lib') - for i in paths: - yield os.path.join(i, 'libmagic.dylib') + for path in paths: + yield os.path.join(path, 'libmagic.dylib') def _lib_candidates_windows(): """Yield possible libmagic library names on Windows.""" - prefixes = ( + fnames = ( "libmagic", "magic1", "magic-1", @@ -58,13 +58,13 @@ def _lib_candidates_windows(): "msys-magic-1", ) - for i in prefixes: + for fname in fnames: # libmagic bundled in the wheel - yield os.path.join(here, '%s.dll' % i) + yield os.path.join(here, '%s.dll' % fname) # libmagic in the current working directory - yield os.path.join(os.path.abspath('.'), '%s.dll' % i) + yield os.path.join(os.path.abspath('.'), '%s.dll' % fname) # find_library searches in %PATH% but not the current directory - yield find_library(i) + yield find_library(fname) def _lib_candidates(): From da5b330991996004ff963b07610d8141edc50c02 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 29 May 2024 00:04:14 +0200 Subject: [PATCH 31/33] Apply suggestions from code review Co-authored-by: Frank Dana --- add_libmagic.sh | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/add_libmagic.sh b/add_libmagic.sh index af447b3..7b6038f 100755 --- a/add_libmagic.sh +++ b/add_libmagic.sh @@ -6,19 +6,17 @@ 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" && - tar xvf "${tmpfile}" && - cd "${version}" && - ./configure && - make && - make install && - make installcheck && - cd .. && - rm -r "${version}" - ) || (cd .. && rm -r "${version}" && false) + version="file-5.45" && + tmpfile="$(mktemp)" && + curl -sSLo "${tmpfile}" "https://astron.com/pub/file/${version}.tar.gz" && + tar xvf "${tmpfile}" && + cd "${version}" && + ./configure && + make && + make install && + make installcheck && + cd .. && + rm -r "${version}" } install_precompiled() { @@ -34,8 +32,8 @@ install_precompiled() { apt-get install -y libmagic1 elif [ -n "$(which apk)" ]; then apk add --update libmagic - elif [ -n "$(which yum)" ]; then - yum install file-libs + 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 From 258efa432774ea3bdd7406c1bb6500d0435a6df2 Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Wed, 29 May 2024 09:43:08 +0200 Subject: [PATCH 32/33] Revert partially: fix install on Windows --- .github/workflows/wheels.yml | 2 +- add_libmagic.sh | 27 +++++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c922a55..cd3b48e 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -68,7 +68,7 @@ jobs: build-wheels: - name: Build ${{ matrix.only }} + name: build ${{ matrix.only }} needs: build-wheels-matrix runs-on: ${{ matrix.os }} diff --git a/add_libmagic.sh b/add_libmagic.sh index 7b6038f..ba90bdc 100755 --- a/add_libmagic.sh +++ b/add_libmagic.sh @@ -6,17 +6,19 @@ 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" && - tar xvf "${tmpfile}" && - cd "${version}" && - ./configure && - make && - make install && - make installcheck && - cd .. && - rm -r "${version}" + ( + version="file-5.45" && + tmpfile="$(mktemp)" && + curl -sSLo "${tmpfile}" "https://astron.com/pub/file/${version}.tar.gz" && + tar xvf "${tmpfile}" && + cd "${version}" && + ./configure && + make && + make install && + make installcheck && + cd .. && + rm -r "${version}" + ) || ( cd .. && false ) } install_precompiled() { @@ -37,6 +39,7 @@ install_precompiled() { 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 < Date: Wed, 26 Jun 2024 18:31:42 +0700 Subject: [PATCH 33/33] Apply suggestions from code review --- .github/workflows/ci.yml | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eda77f7..1f0317d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,8 @@ jobs: with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - run: ${{ ( startsWith( matrix.os, 'windows' ) && 'bash add_libmagic.sh' ) || 'sudo -E bash add_libmagic.sh' }} + - name: Copy libmagic into magic dir + run: ${{ ( startsWith( matrix.os, 'windows' ) && 'bash add_libmagic.sh' ) || 'sudo -E bash add_libmagic.sh' }} - run: pip install --upgrade pip - run: pip install --upgrade pytest - run: pip install --editable . diff --git a/README.md b/README.md index 0aeb9f8..89c1807 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ apt-get update && apt-get install -y libmagic1 # Alpine apk add --update libmagic # RHEL -yum install file-libs +dnf install file-libs ``` ### Windows