Browse Source

Pick all commits upstream since the 0.4.27 release

This also fixes a test suite error with file 5.47.

Commit 54d86fd ("python-magic tests: add test files for elf and json,
use to test flags") needs some extra loop here to transport binary data
in a patch file.
Christoph Biedl 2 days ago
parent
commit
47ef34b429
55 changed files with 3932 additions and 9 deletions
  1. 19 0
      debian/patches/cherry-picked/0.4.27-1-gf3ab085.add-magic-1-dll-to-the-list-of-dll-files-to-search-for-on-windows.patch
  2. 22 0
      debian/patches/cherry-picked/0.4.27-10-gb805925.dont-run-coverage-by-default-in-tox-config.patch
  3. 17 0
      debian/patches/cherry-picked/0.4.27-11-gc7a2e7b.remove-python3-ism-from-loader.patch
  4. 37 0
      debian/patches/cherry-picked/0.4.27-12-gc7642f0.chore-tests-add-python-3-10-and-3-11-in-ci-runs-tox-trove-classifier-284.patch
  5. 27 0
      debian/patches/cherry-picked/0.4.27-13-ge0052c5.bump-to-0-4-28.patch
  6. 19 0
      debian/patches/cherry-picked/0.4.27-14-g7cde785.revert-remove-python3-ism-from-loader.patch
  7. 36 0
      debian/patches/cherry-picked/0.4.27-15-g3ab9608.revert-added-path-for-local-homebrew-installation-267.patch
  8. 2 2
      debian/patches/cherry-pick/1690968587.0.4.27-16-g545a2a5.fix-test-suite-with-file-5-45.patch
  9. 35 0
      debian/patches/cherry-picked/0.4.27-17-g0cc3cf8.chore-python-add-python-3-12-in-test-matrix.patch
  10. 40 0
      debian/patches/cherry-picked/0.4.27-18-g7229954.fix-dont-raise-filenotfoundexception-on-symlinks.patch
  11. 519 0
      debian/patches/cherry-picked/0.4.27-19-g2a01b18.add-magic-symlink-support-and-tests-for-same.patch
  12. 16 0
      debian/patches/cherry-picked/0.4.27-20-g64ed0bd.typing-stubs-add-magic-init-extension-follow-symlinks-args.patch
  13. 96 0
      debian/patches/cherry-picked/0.4.27-21-gfd279e0.magic-init-add-kwargs-to-enable-disable-different-types-of-magic-detection.patch
  14. 206 0
      debian/patches/cherry-picked/0.4.27-22-g54d86fd.python-magic-tests-add-test-files-for-elf-and-json-use-to-test-flags.patch
  15. 26 0
      debian/patches/cherry-picked/0.4.27-23-g8eecfb7.travis-ci-test-on-python-3-13-beta.patch
  16. 39 0
      debian/patches/cherry-picked/0.4.27-24-g7ee4180.delete-travis-yml.patch
  17. 86 0
      debian/patches/cherry-picked/0.4.27-25-ge578995.github-action-to-replace-travis-ci.patch
  18. 16 0
      debian/patches/cherry-picked/0.4.27-26-gab1b2a4.update-ci-yml.patch
  19. 17 0
      debian/patches/cherry-picked/0.4.27-27-gaa49677.update-readme-md.patch
  20. 18 0
      debian/patches/cherry-picked/0.4.27-28-geae08a3.readme-md-add-a-badge-for-github-actions.patch
  21. 15 0
      debian/patches/cherry-picked/0.4.27-29-gfc7ebc0.update-readme-md.patch
  22. 16 0
      debian/patches/cherry-picked/0.4.27-3-gcc0c587.corrected-the-command-for-the-test-for-python3.patch
  23. 25 0
      debian/patches/cherry-picked/0.4.27-30-g1217005.fix-typos-discovered-by-codespell.patch
  24. 108 0
      debian/patches/cherry-picked/0.4.27-31-gcf21065.clean-up-loader-py.patch
  25. 24 0
      debian/patches/cherry-picked/0.4.27-32-g0a2fda3.handle-unknown-platforms-gracefully-in-loader-py.patch
  26. 17 0
      debian/patches/cherry-picked/0.4.27-33-g4b776d7.rename-no-json-test-to-avoid-duplicate-function-definitions.patch
  27. 28 0
      debian/patches/cherry-picked/0.4.27-34-g339eac0.smartos-support-adapted-from-132.patch
  28. 38 0
      debian/patches/cherry-picked/0.4.27-35-ga9e6276.log-warning-on-ctypes-load-error-adapted-from-279.patch
  29. 29 0
      debian/patches/cherry-picked/0.4.27-36-g067399b.update-readme-md.patch
  30. 446 0
      debian/patches/cherry-picked/0.4.27-37-g42980e5.simplify-tests-into-something-more-delarative.patch
  31. 197 0
      debian/patches/cherry-picked/0.4.27-38-g36ecbf9.update-magic-compat-py.patch
  32. 391 0
      debian/patches/cherry-picked/0.4.27-39-ga3ed086.unbreak-various-things.patch
  33. 111 0
      debian/patches/cherry-picked/0.4.27-40-g5a89644.add-support-for-python-3-13.patch
  34. 267 0
      debian/patches/cherry-picked/0.4.27-41-g62bd3c6.format-with-ruff.patch
  35. 23 0
      debian/patches/cherry-picked/0.4.27-42-gfac6615.small-fix-to-readme-that-makes-pip-install-command-easier-to-see-find.patch
  36. 16 0
      debian/patches/cherry-picked/0.4.27-43-g8361a33.update-readme-md.patch
  37. 16 0
      debian/patches/cherry-picked/0.4.27-44-g7cbbc99.update-readme-md.patch
  38. 36 0
      debian/patches/cherry-picked/0.4.27-45-gf8fb0ee.add-python-3-14-to-the-testing.patch
  39. 25 0
      debian/patches/cherry-picked/0.4.27-46-g07bd5dd.keep-github-actions-up-to-date-with-github-s-dependabot.patch
  40. 35 0
      debian/patches/cherry-picked/0.4.27-47-g5cffa79.bump-actions-checkout-from-5-to-6-in-the-github-actions-group.patch
  41. 38 0
      debian/patches/cherry-picked/0.4.27-48-gff3e049.drop-unused-imports.patch
  42. 35 0
      debian/patches/cherry-picked/0.4.27-49-ga1fad43.fix-test-for-apache-parquet-files-for-file-5-47.patch
  43. 37 0
      debian/patches/cherry-picked/0.4.27-5-gcd3929f.added-path-for-local-homebrew-installation-267.patch
  44. 28 0
      debian/patches/cherry-picked/0.4.27-50-g71301b0.add-python-3-14-to-ci.patch
  45. 152 0
      debian/patches/cherry-picked/0.4.27-51-g8e7d98e.move-lock-to-global-scope.patch
  46. 67 0
      debian/patches/cherry-picked/0.4.27-52-g892543d.add-test.patch
  47. 26 0
      debian/patches/cherry-picked/0.4.27-53-gf3cef27.apply-suggestions-from-code-review.patch
  48. 150 0
      debian/patches/cherry-picked/0.4.27-54-g4043553.revert-move-lock-to-global-scope.patch
  49. 27 0
      debian/patches/cherry-picked/0.4.27-6-gea2150d.add-python-3-10-to-tox-environment-list.patch
  50. 38 0
      debian/patches/cherry-picked/0.4.27-7-g05fde96.further-update-readme-for-test-running-changes.patch
  51. 110 0
      debian/patches/cherry-picked/0.4.27-8-g3794a39.docker-test-cleanup.patch
  52. 12 5
      debian/patches/2022-12-23.adjust-for-5.43.patch
  53. 52 2
      debian/patches/series
  54. 2 0
      debian/rules
  55. 2 0
      debian/tests/run-testsuite

+ 19 - 0
debian/patches/cherry-picked/0.4.27-1-gf3ab085.add-magic-1-dll-to-the-list-of-dll-files-to-search-for-on-windows.patch

@@ -0,0 +1,19 @@
+Subject: Add "magic-1.dll" to the list of DLL files to search for on Windows
+Origin: upstream, commit 0.4.27-1-gf3ab085 <https://github.com/ahupp/python-magic/commit/0.4.27-1-gf3ab085>
+Author: valpogus <32718480+valpogus@users.noreply.github.com>
+Date: Thu Jun 16 13:26:45 2022 +0200
+
+    This is the name of the DLL file generated when using vcpkg to build libmagic:
+    https://github.com/microsoft/vcpkg/tree/master/ports/libmagic
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -21,7 +21,7 @@
+ 
+   elif sys.platform in ('win32', 'cygwin'):
+ 
+-    prefixes = ['libmagic', 'magic1', '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,

+ 22 - 0
debian/patches/cherry-picked/0.4.27-10-gb805925.dont-run-coverage-by-default-in-tox-config.patch

@@ -0,0 +1,22 @@
+Subject: Don't run coverage by default in tox config
+Origin: upstream, commit 0.4.27-10-gb805925 <https://github.com/ahupp/python-magic/commit/0.4.27-10-gb805925>
+Author: Adam Hupp <adam@hupp.org>
+Date: Tue Jan 10 15:03:02 2023 -0800
+
+--- a/tox.ini
++++ b/tox.ini
+@@ -1,6 +1,5 @@
+ [tox]
+ envlist =
+-    coverage-clean,
+     py27,
+     py35,
+     py36,
+@@ -8,7 +7,6 @@
+     py38,
+     py39,
+     py310,
+-    coverage-report,
+     mypy
+ 
+ [testenv]

+ 17 - 0
debian/patches/cherry-picked/0.4.27-11-gc7a2e7b.remove-python3-ism-from-loader.patch

@@ -0,0 +1,17 @@
+Subject: Remove python3-ism from loader
+Origin: upstream, commit 0.4.27-11-gc7a2e7b <https://github.com/ahupp/python-magic/commit/0.4.27-11-gc7a2e7b>
+Author: Adam Hupp <adam@hupp.org>
+Date: Tue Jan 10 15:03:22 2023 -0800
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -19,7 +19,8 @@
+ 
+     try:
+       local_brew_path = subprocess.check_output(['brew', '--prefix']).decode('UTF-8')
+-      paths.append(f'{local_brew_path.strip()}/lib')
++      local_brew_path = local_brew_path.strip()
++      paths.append(local_brew_path + '/lib')
+     except:
+       pass
+ 

+ 37 - 0
debian/patches/cherry-picked/0.4.27-12-gc7642f0.chore-tests-add-python-3-10-and-3-11-in-ci-runs-tox-trove-classifier-284.patch

@@ -0,0 +1,37 @@
+Subject: Chore(tests): add Python 3.10 and 3.11 in CI runs/tox/trove classifier (#284)
+Origin: upstream, commit 0.4.27-12-gc7642f0 <https://github.com/ahupp/python-magic/commit/0.4.27-12-gc7642f0>
+Author: Stevie Gayet <87695919+stegayet@users.noreply.github.com>
+Date: Mon Jan 23 16:06:24 2023 +0100
+
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -9,6 +9,8 @@
+   - "3.7"
+   - "3.8"
+   - "3.9"
++  - "3.10"
++  - "3.11"
+ 
+ install:
+   - pip install coverage coveralls codecov
+--- a/setup.py
++++ b/setup.py
+@@ -39,6 +39,8 @@
+         'Programming Language :: Python :: 3.7',
+         'Programming Language :: Python :: 3.8',
+         'Programming Language :: Python :: 3.9',
++        'Programming Language :: Python :: 3.10',
++        'Programming Language :: Python :: 3.11',
+         'Programming Language :: Python :: Implementation :: CPython',
+     ],
+ )
+--- a/tox.ini
++++ b/tox.ini
+@@ -7,6 +7,7 @@
+     py38,
+     py39,
+     py310,
++    py311,
+     mypy
+ 
+ [testenv]

+ 27 - 0
debian/patches/cherry-picked/0.4.27-13-ge0052c5.bump-to-0-4-28.patch

@@ -0,0 +1,27 @@
+Subject: Bump to 0.4.28
+Origin: upstream, commit 0.4.27-13-ge0052c5 <https://github.com/ahupp/python-magic/commit/0.4.27-13-ge0052c5>
+Author: Adam Hupp <adam@hupp.org>
+Date: Thu Mar 23 13:54:10 2023 -0700
+
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,3 +1,8 @@
++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
++
+ Changes to 0.4.27:
+   - remove spurious pyproject.toml that breaks source builds
+ 
+--- a/setup.py
++++ b/setup.py
+@@ -18,7 +18,7 @@
+     author='Adam Hupp',
+     author_email='adam@hupp.org',
+     url="http://github.com/ahupp/python-magic",
+-    version='0.4.27',
++    version='0.4.28',
+     long_description=read('README.md'),
+     long_description_content_type='text/markdown',
+     packages=['magic'],

+ 19 - 0
debian/patches/cherry-picked/0.4.27-14-g7cde785.revert-remove-python3-ism-from-loader.patch

@@ -0,0 +1,19 @@
+Subject: Revert "remove python3-ism from loader"
+Origin: upstream, commit 0.4.27-14-g7cde785 <https://github.com/ahupp/python-magic/commit/0.4.27-14-g7cde785>
+Author: Adam Hupp <adam@hupp.org>
+Date: Thu Mar 30 11:22:14 2023 -0700
+
+    This reverts commit c7a2e7bc7c387af23b3c896bf05003cf2bd8646b.
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -19,8 +19,7 @@
+ 
+     try:
+       local_brew_path = subprocess.check_output(['brew', '--prefix']).decode('UTF-8')
+-      local_brew_path = local_brew_path.strip()
+-      paths.append(local_brew_path + '/lib')
++      paths.append(f'{local_brew_path.strip()}/lib')
+     except:
+       pass
+ 

+ 36 - 0
debian/patches/cherry-picked/0.4.27-15-g3ab9608.revert-added-path-for-local-homebrew-installation-267.patch

@@ -0,0 +1,36 @@
+Subject: Revert "added path for local homebrew installation (#267)"
+Origin: upstream, commit 0.4.27-15-g3ab9608 <https://github.com/ahupp/python-magic/commit/0.4.27-15-g3ab9608>
+Author: Adam Hupp <adam@hupp.org>
+Date: Thu Mar 30 11:22:46 2023 -0700
+
+    This reverts commit cd3929fa7cbc2e383629d0893fc08bcb68a7614c.
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -3,7 +3,6 @@
+ import sys
+ import glob
+ import os.path
+-import subprocess
+ 
+ def _lib_candidates():
+ 
+@@ -14,16 +13,8 @@
+     paths = [
+       '/opt/local/lib',
+       '/usr/local/lib',
+-      '/opt/homebrew/lib'
+-    ]
+-
+-    try:
+-      local_brew_path = subprocess.check_output(['brew', '--prefix']).decode('UTF-8')
+-      paths.append(f'{local_brew_path.strip()}/lib')
+-    except:
+-      pass
+-
+-    paths += glob.glob('/usr/local/Cellar/libmagic/*/lib')
++      '/opt/homebrew/lib',
++    ] + glob.glob('/usr/local/Cellar/libmagic/*/lib')
+ 
+     for i in paths:
+       yield os.path.join(i, 'libmagic.dylib')

+ 2 - 2
debian/patches/cherry-pick/1690968587.0.4.27-16-g545a2a5.fix-test-suite-with-file-5-45.patch

@@ -1,6 +1,6 @@
 Subject: Fix test suite with file 5.45
 Subject: Fix test suite with file 5.45
-Origin: upstream, 0.4.27-16-g545a2a5 <https://github.com/ahupp/python-magic/commit/0.4.27-16-g545a2a5>
-Upstream-Author: Dominique Leuenberger <dimstar@opensuse.org>
+Origin: upstream, commit 0.4.27-16-g545a2a5 <https://github.com/ahupp/python-magic/commit/0.4.27-16-g545a2a5>
+Author: Dominique Leuenberger <dimstar@opensuse.org>
 Date: Wed Aug 2 11:29:47 2023 +0200
 Date: Wed Aug 2 11:29:47 2023 +0200
 
 
     [   12s] test/python_magic_test.py:53: in assert_values
     [   12s] test/python_magic_test.py:53: in assert_values

+ 35 - 0
debian/patches/cherry-picked/0.4.27-17-g0cc3cf8.chore-python-add-python-3-12-in-test-matrix.patch

@@ -0,0 +1,35 @@
+Subject: Chore(python): add Python 3.12 in test matrix
+Origin: upstream, commit 0.4.27-17-g0cc3cf8 <https://github.com/ahupp/python-magic/commit/0.4.27-17-g0cc3cf8>
+Author: Stevie <stevie.gayet@backmarket.com>
+Date: Sun Aug 6 00:13:22 2023 +0200
+
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -11,6 +11,7 @@
+   - "3.9"
+   - "3.10"
+   - "3.11"
++  - "3.12"
+ 
+ install:
+   - pip install coverage coveralls codecov
+--- a/setup.py
++++ b/setup.py
+@@ -41,6 +41,7 @@
+         'Programming Language :: Python :: 3.9',
+         'Programming Language :: Python :: 3.10',
+         'Programming Language :: Python :: 3.11',
++        'Programming Language :: Python :: 3.12',
+         'Programming Language :: Python :: Implementation :: CPython',
+     ],
+ )
+--- a/tox.ini
++++ b/tox.ini
+@@ -8,6 +8,7 @@
+     py39,
+     py310,
+     py311,
++    py312,
+     mypy
+ 
+ [testenv]

+ 40 - 0
debian/patches/cherry-picked/0.4.27-18-g7229954.fix-dont-raise-filenotfoundexception-on-symlinks.patch

@@ -0,0 +1,40 @@
+Subject: Fix: Don't raise FileNotFoundException on symlinks
+Origin: upstream, commit 0.4.27-18-g7229954 <https://github.com/ahupp/python-magic/commit/0.4.27-18-g7229954>
+Author: Marten Ringwelski <git@maringuu.de>
+Date: Wed Aug 23 22:17:30 2023 +0200
+
+    The builtin `open` will always follow symlinks.
+    Using `os.stat` is the easiest solution imo.
+    An alternative would be using `os.access` but that does not raise
+    a FileNotFoundException so I chose `os.stat`.
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -17,6 +17,7 @@
+ """
+ 
+ import sys
++import os
+ import glob
+ import ctypes
+ import ctypes.util
+@@ -25,9 +26,6 @@
+ 
+ from ctypes import c_char_p, c_int, c_size_t, c_void_p, byref, POINTER
+ 
+-# avoid shadowing the real open with the version from compat.py
+-_real_open = open
+-
+ 
+ class MagicException(Exception):
+     def __init__(self, message):
+@@ -109,8 +107,7 @@
+ 
+     def from_file(self, filename):
+         # raise FileNotFoundException or IOError if the file does not exist
+-        with _real_open(filename):
+-            pass
++        os.stat(filename, follow_symlinks=self.flags & MAGIC_SYMLINK)
+ 
+         with self.lock:
+             try:

+ 519 - 0
debian/patches/cherry-picked/0.4.27-19-g2a01b18.add-magic-symlink-support-and-tests-for-same.patch

@@ -0,0 +1,519 @@
+Subject: Add MAGIC_SYMLINK support, and tests for same
+Origin: upstream, commit 0.4.27-19-g2a01b18 <https://github.com/ahupp/python-magic/commit/0.4.27-19-g2a01b18>
+Author: Adam Hupp <adam@hupp.org>
+Date: Fri Aug 25 11:02:53 2023 -0700
+
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,41 +1,51 @@
++Changes to 0.4.29:
++
++- 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
++
++- support "magic-1.dll" on Windows, which is produced by vcpkg
++- add python 3.10 to tox config
++- update test for upstream gzip extensions
+ 
+ Changes to 0.4.27:
+-  - remove spurious pyproject.toml that breaks source builds
++
++- remove spurious pyproject.toml that breaks source builds
+ 
+ Changes to 0.4.26:
+-  - Use tox for all multi-version testing
+-  - Fix use of pytest, use it via tox
++
++- Use tox for all multi-version testing
++- Fix use of pytest, use it via tox
+ 
+ Changes to 0.4.25:
+-  - Support os.PathLike values in Magic.from_file and magic.from_file
+-  - Handle some versions of libmagic that return mime string without charset
+-  - Fix tests for file 5.41
+-  - Include typing stub in package
++
++- Support os.PathLike values in Magic.from_file and magic.from_file
++- Handle some versions of libmagic that return mime string without charset
++- Fix tests for file 5.41
++- Include typing stub in package
+ 
+ Changes to 0.4.24:
+- - Fix regression in library loading on some Alpine docker images.
++
++- Fix regression in library loading on some Alpine docker images.
+ 
+ Changes to 0.4.23
+ 
+- - Include a `py.typed` sentinal to enable type checking
+- - Improve fix for attribute error during destruction
+- - Cleanup library loading logic
+- - Add new homebrew library dir for OSX
++- Include a `py.typed` sentinal to enable type checking
++- Improve fix for attribute error during destruction
++- Cleanup library loading logic
++- Add new homebrew library dir for OSX
+ 
+ Changes to 0.4.21, 0.4.22
+ 
+- - Unify dll loader between the standard and compat library, fixing load
+- failures on some previously supported platforms.
++- Unify dll loader between the standard and compat library, fixing load
++  failures on some previously supported platforms.
+ 
+ Changes to 0.4.20
+ 
+ - merge in a compatibility layer for the upstream libmagic python binding.
+   Since both this package and that one are called 'magic', this compat layer
+-  removes a very common source of runtime errors.  Use of that libmagic API will
++  removes a very common source of runtime errors. Use of that libmagic API will
+   produce a deprecation warning.
+ 
+ - support python 3.9 in tests and pypi metadata
+@@ -44,9 +54,9 @@
+   rather than a filename.
+ 
+ - sometimes the returned description includes snippets of the file, e.g a title
+-  for MS Word docs.  Since this is in an unknown encoding, we would throw a
+-  unicode decode error trying to decode.  Now, it decodes with
+-  'backslashreplace' to handle this more gracefully.  The undecodable characters
++  for MS Word docs. Since this is in an unknown encoding, we would throw a
++  unicode decode error trying to decode. Now, it decodes with
++  'backslashreplace' to handle this more gracefully. The undecodable characters
+   are replaced with hex escapes.
+ 
+ - add support for MAGIC_EXTENSION, to return possible file extensions.
+@@ -55,18 +65,18 @@
+ 
+ Changes in 0.4.18
+ 
+-- Make bindings for magic_[set|get]param optional, and throw NotImplementedError
+-if they are used but not supported.  Only call setparam() in the constructor if
+-it's supported. This prevents breakage on CentOS7 which uses an old version of
+-libmagic.
++- Make bindings for magic\_[set|get]param optional, and throw NotImplementedError
++  if they are used but not supported. Only call setparam() in the constructor if
++  it's supported. This prevents breakage on CentOS7 which uses an old version of
++  libmagic.
+ 
+ - Add tests for CentOS 7 & 8
+ 
+ Changes in 0.4.16 and 0.4.17
+ 
+ - add MAGIC_MIME_TYPE constant, use that in preference to MAGIC_MIME internally.
+-This sets up for a breaking change in a future major version bump where
+-MAGIC_MIME will change to mathch magic.h.
++  This sets up for a breaking change in a future major version bump where
++  MAGIC_MIME will change to mathch magic.h.
+ - add magic.version() function to return library version
+ - add setparam/getparam to control internal behavior
+ - increase internal limits with setparam to prevent spurious error on some jpeg files
+@@ -76,12 +86,12 @@
+ - include tests in source distribution
+ 
+ - many test improvements:
+--- tox runner support
+--- remove deprecated test_suite field from setup.py
+--- docker tests that cover all LTS ubuntu versions
+--- add test for snapp file identification
++  -- tox runner support
++  -- remove deprecated test_suite field from setup.py
++  -- docker tests that cover all LTS ubuntu versions
++  -- add test for snapp file identification
+ 
+ - doc improvements
+--- document dependency install process for debian
+--- various typos
+--- document test running process
++  -- document dependency install process for debian
++  -- various typos
++  -- document test running process
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -39,7 +39,8 @@
+     """
+ 
+     def __init__(self, mime=False, magic_file=None, mime_encoding=False,
+-                 keep_going=False, uncompress=False, raw=False, extension=False):
++                 keep_going=False, uncompress=False, raw=False, extension=False,
++                 follow_symlinks=False):
+         """
+         Create a new libmagic wrapper.
+ 
+@@ -65,6 +66,9 @@
+         if extension:
+             self.flags |= MAGIC_EXTENSION
+ 
++        if follow_symlinks:
++            self.flags |= MAGIC_SYMLINK
++
+         self.cookie = magic_open(self.flags)
+         self.lock = threading.Lock()
+ 
+--- a/test/README
++++ b/test/README
+@@ -1,6 +1,4 @@
+ There are a few ways to run the python-magic tests
+ 
+- 1. `pytest` will run the test suite against your default version of python
+- 2. `./test/run_all_versions.py` will run the tests against all installed versions of python.
+- 3. `./test/run_all_docker_test.sh` will run against a variety of different Linux distributions, using docker.
+-
++1.  `tox` will run the tests against all installed versions of python
++2.  `./test/run_all_docker_test.sh` will run against a variety of different Linux distributions, using docker.
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -1,9 +1,10 @@
++import tempfile
+ import os
+ 
+ # for output which reports a local time
+-os.environ['TZ'] = 'GMT'
++os.environ["TZ"] = "GMT"
+ 
+-if os.environ.get('LC_ALL', '') != 'en_US.UTF-8':
++if os.environ.get("LC_ALL", "") != "en_US.UTF-8":
+     # this ensure we're in a utf-8 default filesystem encoding which is
+     # necessary for some tests
+     raise Exception("must run `export LC_ALL=en_US.UTF-8` before running test suite")
+@@ -16,10 +17,11 @@
+ import sys
+ 
+ # magic_descriptor is broken (?) in centos 7, so don't run those tests
+-SKIP_FROM_DESCRIPTOR = bool(os.environ.get('SKIP_FROM_DESCRIPTOR'))
++SKIP_FROM_DESCRIPTOR = bool(os.environ.get("SKIP_FROM_DESCRIPTOR"))
++
+ 
+ class MagicTest(unittest.TestCase):
+-    TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'testdata'))
++    TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
+ 
+     def test_version(self):
+         try:
+@@ -28,20 +30,19 @@
+             pass
+ 
+     def test_fs_encoding(self):
+-        self.assertEqual('utf-8', sys.getfilesystemencoding().lower())
++        self.assertEqual("utf-8", sys.getfilesystemencoding().lower())
+ 
+     def assert_values(self, m, expected_values, buf_equals_file=True):
+         for filename, expected_value in expected_values.items():
+             try:
+                 filename = os.path.join(self.TESTDATA_DIR, filename)
+             except TypeError:
+-                filename = os.path.join(
+-                    self.TESTDATA_DIR.encode('utf-8'), filename)
++                filename = os.path.join(self.TESTDATA_DIR.encode("utf-8"), filename)
+ 
+             if type(expected_value) is not tuple:
+                 expected_value = (expected_value,)
+ 
+-            with open(filename, 'rb') as f:
++            with open(filename, "rb") as f:
+                 buf_value = m.from_buffer(f.read())
+ 
+             file_value = m.from_file(filename)
+@@ -55,10 +56,10 @@
+     def test_from_file_str_and_bytes(self):
+         filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
+ 
+-        self.assertEqual('application/pdf',
+-                         magic.from_file(filename, mime=True))
+-        self.assertEqual('application/pdf',
+-                         magic.from_file(filename.encode('utf-8'), mime=True))
++        self.assertEqual("application/pdf", magic.from_file(filename, mime=True))
++        self.assertEqual(
++            "application/pdf", magic.from_file(filename.encode("utf-8"), mime=True)
++        )
+ 
+     def test_from_descriptor_str_and_bytes(self):
+         if SKIP_FROM_DESCRIPTOR:
+@@ -66,10 +67,12 @@
+ 
+         filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
+         with open(filename) as f:
+-            self.assertEqual('application/pdf',
+-                             magic.from_descriptor(f.fileno(), mime=True))
+-            self.assertEqual('application/pdf',
+-                             magic.from_descriptor(f.fileno(), mime=True))
++            self.assertEqual(
++                "application/pdf", magic.from_descriptor(f.fileno(), mime=True)
++            )
++            self.assertEqual(
++                "application/pdf", magic.from_descriptor(f.fileno(), mime=True)
++            )
+ 
+     def test_from_buffer_str_and_bytes(self):
+         if SKIP_FROM_DESCRIPTOR:
+@@ -78,125 +81,151 @@
+ 
+         self.assertTrue(
+             m.from_buffer('#!/usr/bin/env python\nprint("foo")')
+-            in ("text/x-python", "text/x-script.python"))
++            in ("text/x-python", "text/x-script.python")
++        )
+         self.assertTrue(
+             m.from_buffer(b'#!/usr/bin/env python\nprint("foo")')
+-            in ("text/x-python", "text/x-script.python"))
++            in ("text/x-python", "text/x-script.python")
++        )
+ 
+     def test_mime_types(self):
+-        dest = os.path.join(MagicTest.TESTDATA_DIR,
+-                            b'\xce\xbb'.decode('utf-8'))
+-        shutil.copyfile(os.path.join(MagicTest.TESTDATA_DIR, 'lambda'), dest)
++        dest = os.path.join(MagicTest.TESTDATA_DIR, b"\xce\xbb".decode("utf-8"))
++        shutil.copyfile(os.path.join(MagicTest.TESTDATA_DIR, "lambda"), dest)
+         try:
+             m = magic.Magic(mime=True)
+-            self.assert_values(m, {
+-                'magic._pyc_': ('application/octet-stream', 'text/x-bytecode.python', 'application/x-bytecode.python'),
+-                'test.pdf': 'application/pdf',
+-                'test.gz': ('application/gzip', 'application/x-gzip'),
+-                'test.snappy.parquet': 'application/octet-stream',
+-                'text.txt': 'text/plain',
+-                b'\xce\xbb'.decode('utf-8'): 'text/plain',
+-                b'\xce\xbb': 'text/plain',
+-            })
++            self.assert_values(
++                m,
++                {
++                    "magic._pyc_": (
++                        "application/octet-stream",
++                        "text/x-bytecode.python",
++                        "application/x-bytecode.python",
++                    ),
++                    "test.pdf": "application/pdf",
++                    "test.gz": ("application/gzip", "application/x-gzip"),
++                    "test.snappy.parquet": "application/octet-stream",
++                    "text.txt": "text/plain",
++                    b"\xce\xbb".decode("utf-8"): "text/plain",
++                    b"\xce\xbb": "text/plain",
++                },
++            )
+         finally:
+             os.unlink(dest)
+ 
+     def test_descriptions(self):
+         m = magic.Magic()
+-        os.environ['TZ'] = 'UTC'  # To get last modified date of test.gz in UTC
++        os.environ["TZ"] = "UTC"  # To get last modified date of test.gz in UTC
+         try:
+-            self.assert_values(m, {
+-                'magic._pyc_': 'python 2.4 byte-compiled',
+-                'test.pdf': ('PDF document, version 1.2',
+-                             'PDF document, version 1.2, 2 pages',
+-                             'PDF document, version 1.2, 2 page(s)'),
+-                'test.gz':
+-                    ('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'
+-                     ),
+-                'text.txt': 'ASCII text',
+-                'test.snappy.parquet': ('Apache Parquet', 'Par archive data'),
+-            }, buf_equals_file=False)
++            self.assert_values(
++                m,
++                {
++                    "magic._pyc_": "python 2.4 byte-compiled",
++                    "test.pdf": (
++                        "PDF document, version 1.2",
++                        "PDF document, version 1.2, 2 pages",
++                        "PDF document, version 1.2, 2 page(s)",
++                    ),
++                    "test.gz": (
++                        '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",
++                    ),
++                    "text.txt": "ASCII text",
++                    "test.snappy.parquet": ("Apache Parquet", "Par archive data"),
++                },
++                buf_equals_file=False,
++            )
+         finally:
+-            del os.environ['TZ']
++            del os.environ["TZ"]
+ 
+     def test_extension(self):
+         try:
+             m = magic.Magic(extension=True)
+-            self.assert_values(m, {
+-                # some versions return '' for the extensions of a gz file,
+-                # including w/ the command line.  Who knows...
+-                'test.gz': ('gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz', 'gz/tgz/tpz/zabw/svgz', '', '???'),
+-                'name_use.jpg': 'jpeg/jpg/jpe/jfif',
+-            })
++            self.assert_values(
++                m,
++                {
++                    # some versions return '' for the extensions of a gz file,
++                    # including w/ the command line.  Who knows...
++                    "test.gz": (
++                        "gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz",
++                        "gz/tgz/tpz/zabw/svgz",
++                        "",
++                        "???",
++                    ),
++                    "name_use.jpg": "jpeg/jpg/jpe/jfif",
++                },
++            )
+         except NotImplementedError:
+-            self.skipTest('MAGIC_EXTENSION not supported in this version')
++            self.skipTest("MAGIC_EXTENSION not supported in this version")
+ 
+     def test_unicode_result_nonraw(self):
+         m = magic.Magic(raw=False)
+-        src = os.path.join(MagicTest.TESTDATA_DIR, 'pgpunicode')
++        src = os.path.join(MagicTest.TESTDATA_DIR, "pgpunicode")
+         result = m.from_file(src)
+         # NOTE: This check is added as otherwise some magic files don't identify the test case as a PGP key.
+-        if 'PGP' in result:
++        if "PGP" in result:
+             assert r"PGP\011Secret Sub-key -" == result
+         else:
+             raise unittest.SkipTest("Magic file doesn't return expected type.")
+ 
+     def test_unicode_result_raw(self):
+         m = magic.Magic(raw=True)
+-        src = os.path.join(MagicTest.TESTDATA_DIR, 'pgpunicode')
++        src = os.path.join(MagicTest.TESTDATA_DIR, "pgpunicode")
+         result = m.from_file(src)
+-        if 'PGP' in result:
+-            assert b'PGP\tSecret Sub-key -' == result.encode('utf-8')
++        if "PGP" in result:
++            assert b"PGP\tSecret Sub-key -" == result.encode("utf-8")
+         else:
+             raise unittest.SkipTest("Magic file doesn't return expected type.")
+ 
+     def test_mime_encodings(self):
+         m = magic.Magic(mime_encoding=True)
+-        self.assert_values(m, {
+-            'text-iso8859-1.txt': 'iso-8859-1',
+-            'text.txt': 'us-ascii',
+-        })
++        self.assert_values(
++            m,
++            {
++                "text-iso8859-1.txt": "iso-8859-1",
++                "text.txt": "us-ascii",
++            },
++        )
+ 
+     def test_errors(self):
+         m = magic.Magic()
+-        self.assertRaises(IOError, m.from_file, 'nonexistent')
+-        self.assertRaises(magic.MagicException, magic.Magic,
+-                          magic_file='nonexistent')
+-        os.environ['MAGIC'] = 'nonexistent'
++        self.assertRaises(IOError, m.from_file, "nonexistent")
++        self.assertRaises(magic.MagicException, magic.Magic, magic_file="nonexistent")
++        os.environ["MAGIC"] = "nonexistent"
+         try:
+             self.assertRaises(magic.MagicException, magic.Magic)
+         finally:
+-            del os.environ['MAGIC']
++            del os.environ["MAGIC"]
+ 
+     def test_keep_going(self):
+-        filename = os.path.join(self.TESTDATA_DIR, 'keep-going.jpg')
++        filename = os.path.join(self.TESTDATA_DIR, "keep-going.jpg")
+ 
+         m = magic.Magic(mime=True)
+-        self.assertEqual(m.from_file(filename), 'image/jpeg')
++        self.assertEqual(m.from_file(filename), "image/jpeg")
+ 
+         try:
+             # this will throw if you have an "old" version of the library
+             # I'm otherwise not sure how to query if keep_going is supported
+             magic.version()
+             m = magic.Magic(mime=True, keep_going=True)
+-            self.assertEqual(m.from_file(filename),
+-                             'image/jpeg\\012- application/octet-stream')
++            self.assertEqual(
++                m.from_file(filename), "image/jpeg\\012- application/octet-stream"
++            )
+         except NotImplementedError:
+             pass
+ 
+     def test_rethrow(self):
+         old = magic.magic_buffer
+         try:
++
+             def t(x, y):
+                 raise magic.MagicException("passthrough")
+ 
+@@ -217,16 +246,47 @@
+ 
+     def test_name_count(self):
+         m = magic.Magic()
+-        with open(os.path.join(self.TESTDATA_DIR, 'name_use.jpg'), 'rb') as f:
++        with open(os.path.join(self.TESTDATA_DIR, "name_use.jpg"), "rb") as f:
+             m.from_buffer(f.read())
+ 
+     def test_pathlike(self):
+         if sys.version_info < (3, 6):
+             return
+         from pathlib import Path
+-        path  = Path(self.TESTDATA_DIR, "test.pdf")
++
++        path = Path(self.TESTDATA_DIR, "test.pdf")
+         m = magic.Magic(mime=True)
+-        self.assertEqual('application/pdf', m.from_file(path))
++        self.assertEqual("application/pdf", m.from_file(path))
++
++    def test_symlink(self):
++        # TODO: 3.0
++        if not hasattr(tempfile, "TemporaryDirectory"):
++            return
++
++        with tempfile.TemporaryDirectory() as tmp:
++            tmp_link = os.path.join(tmp, "test_link")
++            tmp_broken = os.path.join(tmp, "nonexistent")
++
++            os.symlink(
++                os.path.join(self.TESTDATA_DIR, "test.pdf"),
++                tmp_link,
++            )
++
++            os.symlink("/nonexistent", tmp_broken)
++
++            m = magic.Magic()
++            m_follow = magic.Magic(follow_symlinks=True)
++            self.assertTrue(m.from_file(tmp_link).startswith("symbolic link to "))
++            self.assertTrue(m_follow.from_file(tmp_link).startswith("PDF document"))
++
++            self.assertTrue(
++                m.from_file(tmp_broken).startswith(
++                    "broken symbolic link to /nonexistent"
++                )
++            )
++
++            self.assertRaises(IOError, m_follow.from_file, tmp_broken)
++
+ 
+-if __name__ == '__main__':
++if __name__ == "__main__":
+     unittest.main()

+ 16 - 0
debian/patches/cherry-picked/0.4.27-20-g64ed0bd.typing-stubs-add-magic-init-extension-follow-symlinks-args.patch

@@ -0,0 +1,16 @@
+Subject: Typing stubs: add Magic.__init__ extension & follow_symlinks args
+Origin: upstream, commit 0.4.27-20-g64ed0bd <https://github.com/ahupp/python-magic/commit/0.4.27-20-g64ed0bd>
+Author: Robert Scott <code@humanleg.org.uk>
+Date: Sat Oct 7 16:35:09 2023 +0100
+
+--- a/magic/__init__.pyi
++++ b/magic/__init__.pyi
+@@ -11,7 +11,7 @@
+     flags: int = ...
+     cookie: Any = ...
+     lock: threading.Lock = ...
+-    def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ...) -> None: ...
++    def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ..., extension: bool = ..., follow_symlinks: bool = ...) -> None: ...
+     def from_buffer(self, buf: Union[bytes, str]) -> Text: ...
+     def from_file(self, filename: Union[bytes, str, PathLike]) -> Text: ...
+     def from_descriptor(self, fd: int, mime: bool = ...) -> Text: ...

+ 96 - 0
debian/patches/cherry-picked/0.4.27-21-gfd279e0.magic-init-add-kwargs-to-enable-disable-different-types-of-magic-detection.patch

@@ -0,0 +1,96 @@
+Subject: Magic.__init__: add kwargs to enable/disable different types of magic detection
+Origin: upstream, commit 0.4.27-21-gfd279e0 <https://github.com/ahupp/python-magic/commit/0.4.27-21-gfd279e0>
+Author: Robert Scott <code@humanleg.org.uk>
+Date: Sat Oct 7 18:18:08 2023 +0100
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -40,7 +40,10 @@
+ 
+     def __init__(self, mime=False, magic_file=None, mime_encoding=False,
+                  keep_going=False, uncompress=False, raw=False, extension=False,
+-                 follow_symlinks=False):
++                 follow_symlinks=False, check_tar=True, check_soft=True,
++                 check_apptype=True, check_elf=True, check_text=True,
++                 check_cdf=True, check_csv=True, check_encoding=True,
++                 check_json=True, check_simh=True):
+         """
+         Create a new libmagic wrapper.
+ 
+@@ -69,6 +72,27 @@
+         if follow_symlinks:
+             self.flags |= MAGIC_SYMLINK
+ 
++        if not check_tar:
++            self.flags |= MAGIC_NO_CHECK_TAR
++        if not check_soft:
++            self.flags |= MAGIC_NO_CHECK_SOFT
++        if not check_apptype:
++            self.flags |= MAGIC_NO_CHECK_APPTYPE
++        if not check_elf:
++            self.flags |= MAGIC_NO_CHECK_ELF
++        if not check_text:
++            self.flags |= MAGIC_NO_CHECK_TEXT
++        if not check_cdf:
++            self.flags |= MAGIC_NO_CHECK_CDF
++        if not check_csv:
++            self.flags |= MAGIC_NO_CHECK_CSV
++        if not check_encoding:
++            self.flags |= MAGIC_NO_CHECK_ENCODING
++        if not check_json:
++            self.flags |= MAGIC_NO_CHECK_JSON
++        if not check_simh:
++            self.flags |= MAGIC_NO_CHECK_SIMH
++
+         self.cookie = magic_open(self.flags)
+         self.lock = threading.Lock()
+ 
+@@ -411,10 +435,16 @@
+ MAGIC_NO_CHECK_SOFT = 0x004000  # Don't check magic entries
+ MAGIC_NO_CHECK_APPTYPE = 0x008000  # Don't check application type
+ MAGIC_NO_CHECK_ELF = 0x010000  # Don't check for elf details
+-MAGIC_NO_CHECK_ASCII = 0x020000  # Don't check for ascii files
+-MAGIC_NO_CHECK_TROFF = 0x040000  # Don't check ascii/troff
+-MAGIC_NO_CHECK_FORTRAN = 0x080000  # Don't check ascii/fortran
+-MAGIC_NO_CHECK_TOKENS = 0x100000  # Don't check ascii/tokens
++MAGIC_NO_CHECK_TEXT = 0x020000  # Don't check for ascii files
++MAGIC_NO_CHECK_ASCII = 0x020000  # Deprecated alias for MAGIC_NO_CHECK_TEXT
++MAGIC_NO_CHECK_TROFF = 0x040000  # Don't check ascii/troff (deprecated)
++MAGIC_NO_CHECK_FORTRAN = 0x080000  # Don't check ascii/fortran (deprecated)
++MAGIC_NO_CHECK_TOKENS = 0x100000  # Don't check ascii/tokens (deprecated)
++MAGIC_NO_CHECK_CDF = 0x0040000  # Don't check for CDF files
++MAGIC_NO_CHECK_CSV = 0x0080000  # Don't check for CSV files
++MAGIC_NO_CHECK_ENCODING = 0x0200000  # Don't check text encodings
++MAGIC_NO_CHECK_JSON = 0x0400000 # Don't check for JSON files
++MAGIC_NO_CHECK_SIMH = 0x0800000 # Don't check for SIMH tape files
+ 
+ MAGIC_PARAM_INDIR_MAX = 0  # Recursion limit for indirect magic
+ MAGIC_PARAM_NAME_MAX = 1  # Use count limit for name/use magic
+--- a/magic/__init__.pyi
++++ b/magic/__init__.pyi
+@@ -11,7 +11,7 @@
+     flags: int = ...
+     cookie: Any = ...
+     lock: threading.Lock = ...
+-    def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ..., extension: bool = ..., follow_symlinks: bool = ...) -> None: ...
++    def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ..., extension: bool = ..., follow_symlinks: bool = ..., check_tar: bool = ..., check_soft: bool = ..., check_apptype: bool = ..., check_elf: bool = ..., check_text: bool = ..., check_encoding: bool = ..., check_json: bool = ..., check_simh: bool = ...) -> None: ...
+     def from_buffer(self, buf: Union[bytes, str]) -> Text: ...
+     def from_file(self, filename: Union[bytes, str, PathLike]) -> Text: ...
+     def from_descriptor(self, fd: int, mime: bool = ...) -> Text: ...
+@@ -74,10 +74,16 @@
+ MAGIC_NO_CHECK_SOFT: int
+ MAGIC_NO_CHECK_APPTYPE: int
+ MAGIC_NO_CHECK_ELF: int
++MAGIC_NO_CHECK_TEXT: int
+ MAGIC_NO_CHECK_ASCII: int
+ MAGIC_NO_CHECK_TROFF: int
+ MAGIC_NO_CHECK_FORTRAN: int
++MAGIC_NO_CHECK_CDF: int
++MAGIC_NO_CHECK_CSV: int
+ MAGIC_NO_CHECK_TOKENS: int
++MAGIC_NO_CHECK_ENCODING: int
++MAGIC_NO_CHECK_JSON: int
++MAGIC_NO_CHECK_SIMH: int
+ MAGIC_PARAM_INDIR_MAX: int
+ MAGIC_PARAM_NAME_MAX: int
+ MAGIC_PARAM_ELF_PHNUM_MAX: int

+ 206 - 0
debian/patches/cherry-picked/0.4.27-22-g54d86fd.python-magic-tests-add-test-files-for-elf-and-json-use-to-test-flags.patch

@@ -0,0 +1,206 @@
+Subject: Python-magic tests: add test files for elf and json, use to test flags
+Origin: upstream, commit 0.4.27-22-g54d86fd <https://github.com/ahupp/python-magic/commit/0.4.27-22-g54d86fd>
+Author: Robert Scott <code@humanleg.org.uk>
+Date: Sat Oct 7 18:42:23 2023 +0100
+
+    elf-NetBSD-x86_64-echo is from
+    https://github.com/JonathanSalwan/binary-samples under an MIT license
+
+    incidentally this exposes that the ELF builtin magic detector
+    only works on files, falling back to the soft magic for buffers
+
+
+    Note for Debian: test/testdata/elf-NetBSD-x86_64-echo.gz.b64 is
+    upstream's test/testdata/elf-NetBSD-x86_64-echo¹, gzip'ed and
+    base64-encoded so it fits in a patch. Unpacking is done in
+    debian/rules and debian/tests/run-testsuite
+
+    ¹ sha256sum 17ebd33e39aeda51701f48f925340b09596602bbe6bc02a7ec94183797095618
+
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -96,6 +96,10 @@
+             self.assert_values(
+                 m,
+                 {
++                    "elf-NetBSD-x86_64-echo": (
++                        "application/x-pie-executable",
++                        "application/x-sharedlib",
++                    ),
+                     "magic._pyc_": (
+                         "application/octet-stream",
+                         "text/x-bytecode.python",
+@@ -107,7 +111,9 @@
+                     "text.txt": "text/plain",
+                     b"\xce\xbb".decode("utf-8"): "text/plain",
+                     b"\xce\xbb": "text/plain",
++                    "test.json": "application/json",
+                 },
++                buf_equals_file=False,
+             )
+         finally:
+             os.unlink(dest)
+@@ -119,6 +125,88 @@
+             self.assert_values(
+                 m,
+                 {
++                    "elf-NetBSD-x86_64-echo": (
++                        "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++                        "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++                    ),
++                    "magic._pyc_": "python 2.4 byte-compiled",
++                    "test.pdf": (
++                        "PDF document, version 1.2",
++                        "PDF document, version 1.2, 2 pages",
++                        "PDF document, version 1.2, 2 page(s)",
++                    ),
++                    "test.gz": (
++                        '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",
++                    ),
++                    "text.txt": "ASCII text",
++                    "test.snappy.parquet": ("Apache Parquet", "Par archive data"),
++                    "test.json": "JSON text data",
++                },
++                buf_equals_file=False,
++            )
++        finally:
++            del os.environ["TZ"]
++
++    def test_descriptions_no_soft(self):
++        m = magic.Magic(check_soft=False)
++        self.assert_values(
++            m,
++            {
++                "elf-NetBSD-x86_64-echo": (
++                    "data",
++                    "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++                ),
++                "magic._pyc_": "data",
++                "test.pdf": "ASCII text",
++                "test.gz": "data",
++                "text.txt": "ASCII text",
++                "test.snappy.parquet": "data",
++                "test.json": "JSON text data",
++            },
++            buf_equals_file=False,
++        )
++
++    def test_descriptions_no_elf(self):
++        m = magic.Magic(check_elf=False)
++        self.assert_values(
++            m,
++            {
++                "elf-NetBSD-x86_64-echo": "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++            },
++            buf_equals_file=True,
++        )
++
++    def test_descriptions_no_json(self):
++        m = magic.Magic(check_elf=False)
++        self.assert_values(
++            m,
++            {
++                "test.json": "data",
++            },
++            buf_equals_file=True,
++        )
++
++    def test_descriptions_no_json(self):
++        m = magic.Magic(check_json=False)
++        os.environ["TZ"] = "UTC"  # To get last modified date of test.gz in UTC
++        try:
++            self.assert_values(
++                m,
++                {
++                    "elf-NetBSD-x86_64-echo": (
++                        "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++                        "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++                    ),
+                     "magic._pyc_": "python 2.4 byte-compiled",
+                     "test.pdf": (
+                         "PDF document, version 1.2",
+--- /dev/null
++++ b/test/testdata/test.json
+@@ -0,0 +1,7 @@
++[
++  {
++    "one": 2,
++    "three": null,
++    "four": [5, "six", false]
++  }
++]
+--- /dev/null
++++ b/test/testdata/elf-NetBSD-x86_64-echo.gz.b64
+@@ -0,0 +1,62 @@
++H4sIAKxQHWoCA+Vae3gTVRa/Sdo0lJIGWksF0QEKFIU0aSl9YLHpi8Htiz4AP5EhTaZNIE1KZlpa
++ULZaitZSrKCo67dS+XywPpFdBXSh5SnrKhREEBZYQGBTKkvlLSjZeyd30pkhQ/3Wz/1n5+vk3POb
++c8499zH3nnumv8/OzVEqFIC/VGAyQFyHxsenY1w3zC8CsWSggb/Dwb1ADflggZyUdijEVOOvB4Ag
++VFBiQEIjgJgqBDQYyF/kADEFgPDrIV9jtT40VkuI6Apc7zqlWE+J9QqxXiGW52k9dqxe0r4gfEdi
++e1I6DohpEKaFZ1grKreG+XgpjQFiyusVYT259n2L/eMp359xDnsZXUtb4hxWPe0opxgXACHYLpLJ
++p9mM4izUsA/j+DahsSs0z+T0B8I7Gtu6Cz9XYz4K3lrBsOrgHSYY08GYRsK7P/jlV7BgDiEf0VCH
++wrsfxkPwOAyCdzjGBvZhMwzLS69BnN8DQI/EwWgZ+dH+mSO+JnM+DAY2HSGaJ1Nl5B+TsW/l7ESD
++DomdA5yf/cCJELH8fBk7T8jgT8vgy2X6cCX2p1Piz6vwHhFA/h2Z9g6QqbdDBj/JtTcafKoTW9st
++I3+Ekx98m/xeGfnz2P63EnkA3xeLnnHpjfGAomvtLKDK7U47oCiGZh0ui9lBJxogZ6XddIWdYWk3
++Ve42V9KU3VnugniV21XhhDygHq6hirBIpsPMMDQDyssd1YwNSTEUw7rtzgoGQLO9OhRTx8AqHKAK
++PmTLEZADaGeN3e1yQsZSa0bemB32hUg4sAfMgrLqcmBmfc6j5sAnqEhbzawZCpQxqHazG0FOK7dC
++wHUjXDy+/Ponnc+7MV8lwXm+E9tRC9YudJ0Q4GoB7hHgAwR4jwAPF+DXBbhO+L7i+kMEax+3ygtw
++lQCPFeDCV8ogwEMFeLIAFy4V6QI8TLhPCXDhe1UowIXzcqYAjxTgcwR4VKD9sOF7jcemRIUdmu0A
++eBMHaQjgHRUJf8PvS4clxNuQaNcJL7xGhSIedVFXJ8crEY+W764Ojr8RAnnUVV3rOP4i4tFQdrVx
++/DnEoyW6q5XjTyEeDUdXPccfQTxyt6uK4/cjHk2Trjkc/wXi0VLeVcjx90O+vNU7Kh7TVBElG073
++oDaSTYfIpj1k05Eu1JTSYg5r3B++5BLqhKavyZbgfVCBbNKRLeMPoVJzho5syoZUSTbrONH1SLRl
++wDRObiDZDMI/0ZENHYol+9mI+htx1T1kk8IPVZ8nG9JeVMPeZ6eRjVfDl6AV78nJCzcWfsOO2TSc
++M3XXQdhvW1DftaMOMnZ4vrrl9bajzvU0wFLD4iAFq91E+IT3QcHufZ5z8IHnCvwhW9LyIeQ5jIAJ
++8Kd5kYZsLoUeJ3huQpWmzz2vcWLBq6Eb0PHriDRpuiyw2zZF+IzeAy101SHgXh8wEgE2CNSnbeS8
++V2wv3hX8PiwqYIOOBiMojGxOK4aIZzlnf9jgINRfKrKxg9V4O8mG7Zpu2Olpz2HhlrQ9yM9pUPjR
++7fVpc3rNlmKzLZxkBNmSGMS5mvZHpJCMrDekzeQeDoLoBhV82PAQYIM9Yb6aG1W+mhuue31Vd2u6
++Lzy63VRqKsFj3HSFbJ7soX9G4okm2LVGryeJ4x6DvVUNJ8FVNnKTimt82ir4/NJb4Uvegmy28TzZ
++PP40bFpuy5svo+fNCUiYhHLzFdxoxSE7sLVkwyTAnmhufANKNXgUTVyhsaPWRDY3cpothQqy6UVU
++3AUIn53qjdmN59kCsmUzgj1/+cnrvdq4Fq0IbIxvBpyE0KRGtME9sSG36Ww7mgaeoxDscsPhgc3o
+++Ilrhs60mXsd8yHa8D6qWlE7OFDNod3Pky0fo3I7Wpo8rcjWIqglXQ8UXMdz60HvTkNU2hkGFnyr
++Wn5pbi5RUDaXynay7jqiygX3G9pN2J3ElIISKJLpcrurq9g7iXBXVh3cuewWwmF3zoMPa2g3Y3c5
++UV2VZtZi8y+h451gFIOaNlQ1KQavxXNuer1zIM2B7UDnidHQ7WcEMSMXxy4sgt2hUwwNC9G0wm66
++B/juW1A3BnWbSatbqjRpoxtUWWjLQrYfRPvEDa93HTKg1eVoox8O779AUw8eGjLp/oSYEXx8jWKt
++VXAKxCE7GVpdizJDG71MZdISS4NM2tiG4CytAfyfXF58yfEgwDkNCPbmi4I4m9vvQ3rjPm4/7y8+
++z6QrxbG+ARf42KAHP+cn0DVM+wvic/5MIrz8e7yOEB07eyTzKkRyRvGoxXisWnze68C0n6R+OA1d
++QCD6I+ZVv/F48fHZfyunxg2LwnQ0phMxzcF0OqblmNZguhTTVZrAceGvv6ZkZqYSsb7zKeEsiyfi
++DcZkQ0J80lgiUZ+oN4AY37NUwuJmDfricTWEUZ+ApIxxhqQ4g5EwxKcmpqQaEom5LtpdQWTXVhEx
++Yq3xFldlpcupt3DKxglIe2KcAf4lEcb4VENSaoK8th3XaURahjhDMqeVnGow3kmrDAbtTqwZ79OE
++DicYkGZCEnQ4sCZtsbl4N1OwmylxsG2wNoMBekowdI3ZGaBCGOPfwdEJso46f3Hz0mNHjiUyXVV1
++bnuFjSViLWMJY0pyyjj4m5JAlNhoAh6EaCfLEK5ygoVsqdPObRRsHUIy4Xmm3OV22s16gjA5HARn
++hiHcNEO7a2irHs2GH/YqhWE997JF4nU8Gb7kw+HT2iMlK14v2J4euat9wYy2bvWy9SbzyLEflLlD
++E5u3jYvd8dTJuI7h77QuCcrMyCC2vq6LiY1vzHy9KjpI2bjth2OfrarJm7342vEnLhxb8FJofeWX
++i8vnmOd9c2/mNt3IEdWNHxHMx9PB2fjOJ0y7p1eSyu9tX7Xl/Xv6vMPMpacrv1/JLFMtPXM68xvb
++hut3D1htjZpmj7GfWnvxKcuV9WsfnZhwIHvmjUP6797oWfjOrLGssdS4d1z1u6+tzHl+wbxLB+de
++Orh59YERbTvXU0X7jr4y+d3jW29sbnW9naKPPnZy1AfPLqIGX9tSml81Zc/Iz9M21TMPtg5/q/Zy
++at3okacvZnxieHHGigv247u1OWePPZLlnPz46h8PMDlXf3eTuZnnPLHrVuurtevbFy+v3nUzvTMy
++bYyn1Xix7YJ+wvE//GxcMXtr5O+5xT57z1btNiJMfWLyF3smDf1nekSE5fEG9azDuzWJkQeuX75l
++CYl7IerGxxOWf1f19clzf33j5OzLd415RV0y1v7a38Ytbnxg56w/0c3Mrm7L/DOrD695c//i+Fdd
++T347KeLU+y/NHvK291/DjuWVr/08s92ueWbY0vlbZhXsKCizuk61HnVojIorJ1aGHzv79LkhG15m
++h87ckRf9wPo1H+54dsXjHUmFA6Z3//3M4qUHHIdjnZteadv7dvWMj5ZNfXPLzvCk/s/YuLfCSpdV
++V8AZ0nb5OfnVRMHdkbeth6F4F2sNE8sP4+Sj/PuIeI9R9G4sIlzpz/+JcRUYFxAP8u+DYjzYv/+J
++cbV/nxTjIf79Soxr/PuaGL89j+TDQ0FPQLw/aNMEwsP8eWQxfns+zYdrxYdkP357//twHdgYEB/o
++z3uK8UEgOSAeAciAeGTA/VEFowo+jyHG5eZDb95PjPfm8cT43QHnqAoMkcGHyuD3yODDbsMSuHxD
++GPgEB1RxeDVNlsmPTZbJi2bJyBfJ5P3myuRFq2Xkm2TstyJ/lAOBQTJea2TypZMUgfOlYxS+fpDO
++2w9l6v1MBt8pg8fK2P9SJr+6Tya/elgmv+qR6bcUGX9uyeBqReD86iCID1QOvi2/d59CJh+OcGUY
++OIgFYxS98ytQPnaijB2TQiYfS2U9km/Km5oJKGpKfimVTVI5Raa8bIrMKgLUlNyCDFMuVZCTU5xd
++QpWYMnKzKVBptjt/w9xtZklBEZU7tbiEys7Poqj/STZXlLSlrIyLspmdVgftT/NS/oyuL8krTPs6
++4TlXz9RVsuYySFm3j9r4EneqrwJ6p4ul9U6aLWOsersVhmtiqMpcC/Q2M+wCvbXOCc35KOsGejft
++MCMGl6ocLLIK60ZFfYULFqCb8JcbDb3bxfmop224qTaru5cDegvrcjPQuo/Mtbi5mlCWASBjPvs+
++E7BXoDyM4Tl3LXwICvTFpfkzKAvsc32Fs5riIgSUofj1p5KhOJbwb88y3zWl52X+GonPmLya9Lth
++tEQ+SMJPlOjzcQVPI/vQn4LP3ErJOZyn70m+wWkkdvLwGVwpOaf3SOyocds1kvNyKT4bKyXnfp5e
++66P/HsO+KCXndJ52yPjP11+B9TMk536e9gj0owLozxd8axbmOXiqlfirk/AOiT4fb/F0nYw+TxdI
++9Pm4jKfSvUEantVL9Pl9iqejVHf2f6nU//5i2lf7l2H9eCBJGIX1focM5D8/D16QvH9y38/l5v8a
++iT4fX/K0tY/+ew/r893U+x0+cHul+n+W6PPxavIv1P9Uos/HtaQ2sLyUb8djpwLS/3cQ/5+DWqLP
+++7VIUj8fJ3fiRKBBpn6N4PutIkCejq/A1of+Pok+H1fadL1x6J3afwhjvD4fN36qC7z+SvWP4vql
++7eT1h/eRL40LsKah6x9Yv0lx5/XvjIy+FQdV5j7Wzx4Z/d1YP0p55/fnhoz+8cjA81cqO1AmN6rG
++R5l+fbRftPcK24Xr7wzuXQeHB1i/+8nU34GPXjl91P8fRGXhJFAlAAA=

+ 26 - 0
debian/patches/cherry-picked/0.4.27-23-g8eecfb7.travis-ci-test-on-python-3-13-beta.patch

@@ -0,0 +1,26 @@
+Subject: Travis CI: Test on Python 3.13 beta
+Origin: upstream, commit 0.4.27-23-g8eecfb7 <https://github.com/ahupp/python-magic/commit/0.4.27-23-g8eecfb7>
+Author: Christian Clauss <cclauss@me.com>
+Date: Sat May 11 08:19:57 2024 +0200
+
+    The Python 3.13 release notes mention `python-magic` as one of the alternatives for `imghdr` which was removed from the Standard Library so let's ensure that its tests pass on Python 3.13 beta.
+
+    https://www.python.org/downloads/release/python-3130b1/
+
+    May raise `ModuleNotFoundError: No module named 'imghdr'` because Python 3.13 removes it from the Standard Library.
+    * https://docs.python.org/3/library/imghdr.html
+
+    > imghdr: use the projects [filetype](https://pypi.org/project/filetype/), [puremagic](https://pypi.org/project/puremagic/), or [python-magic](https://pypi.org/project/python-magic/) instead. (Contributed by Victor Stinner in [gh-104773](https://github.com/python/cpython/issues/104773).)
+
+    https://docs.python.org/3.13/whatsnew/3.13.html#pep-594-dead-batteries-and-other-module-removals
+
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -12,6 +12,7 @@
+   - "3.10"
+   - "3.11"
+   - "3.12"
++  - "3.13"
+ 
+ install:
+   - pip install coverage coveralls codecov

+ 39 - 0
debian/patches/cherry-picked/0.4.27-24-g7ee4180.delete-travis-yml.patch

@@ -0,0 +1,39 @@
+Subject: Delete .travis.yml
+Origin: upstream, commit 0.4.27-24-g7ee4180 <https://github.com/ahupp/python-magic/commit/0.4.27-24-g7ee4180>
+Author: Christian Clauss <cclauss@me.com>
+Date: Thu May 16 06:35:14 2024 +0200
+
+    As discussed at https://github.com/ahupp/python-magic/pull/317#issuecomment-2111634995 this file is useless without a paid subscription to Travis CI.
+
+    GitHub Actions is free to open source projects but Travis CI is not.
+    *  #318
+
+--- a/.travis.yml
++++ /dev/null
+@@ -1,26 +0,0 @@
+-language: python
+-dist: xenial
+-cache: pip
+-
+-python:
+-  - "2.7"
+-  - "3.5"
+-  - "3.6"
+-  - "3.7"
+-  - "3.8"
+-  - "3.9"
+-  - "3.10"
+-  - "3.11"
+-  - "3.12"
+-  - "3.13"
+-
+-install:
+-  - pip install coverage coveralls codecov
+-  - pip install .
+-
+-script:
+-  - LC_ALL=en_US.UTF-8 coverage run -m unittest test
+-
+-after_success:
+-  - coveralls
+-  - codecov

+ 86 - 0
debian/patches/cherry-picked/0.4.27-25-ge578995.github-action-to-replace-travis-ci.patch

@@ -0,0 +1,86 @@
+Subject: GitHub Action to replace Travis CI
+Origin: upstream, commit 0.4.27-25-ge578995 <https://github.com/ahupp/python-magic/commit/0.4.27-25-ge578995>
+Author: Christian Clauss <cclauss@me.com>
+Date: Sat May 11 08:31:58 2024 +0200
+
+--- /dev/null
++++ b/.github/workflows/ci.yml
+@@ -0,0 +1,31 @@
++name: ci
++on: [push, pull_request]
++jobs:
++  ci:
++    strategy:
++      fail-fast: false
++      matrix:
++        os: ['ubuntu-latest']
++        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
++        include:
++          - os: macos-latest
++            python-version: '3.13'
++          # - os: windows-latest  # TODO: Fix the Windows test that runs in an infinite loop.
++          #   python-version: '3.13'
++    runs-on: ${{ matrix.os }}
++    steps:
++      - uses: actions/checkout@v4
++      - uses: actions/setup-python@v5
++        with:
++          python-version: ${{ matrix.python-version }}
++          allow-prereleases: true
++      - 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.
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -1,5 +1,11 @@
+-import tempfile
+ import os
++import os.path
++import shutil
++import sys
++import tempfile
++import unittest
++
++import pytest
+ 
+ # for output which reports a local time
+ os.environ["TZ"] = "GMT"
+@@ -9,12 +15,8 @@
+     # necessary for some tests
+     raise Exception("must run `export LC_ALL=en_US.UTF-8` before running test suite")
+ 
+-import shutil
+-import os.path
+-import unittest
+-
+ import magic
+-import sys
++
+ 
+ # magic_descriptor is broken (?) in centos 7, so don't run those tests
+ SKIP_FROM_DESCRIPTOR = bool(os.environ.get("SKIP_FROM_DESCRIPTOR"))
+@@ -118,6 +120,8 @@
+         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
+@@ -157,6 +161,8 @@
+         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(

+ 16 - 0
debian/patches/cherry-picked/0.4.27-26-gab1b2a4.update-ci-yml.patch

@@ -0,0 +1,16 @@
+Subject: Update ci.yml
+Origin: upstream, commit 0.4.27-26-gab1b2a4 <https://github.com/ahupp/python-magic/commit/0.4.27-26-gab1b2a4>
+Author: Christian Clauss <cclauss@me.com>
+Date: Thu May 16 17:37:31 2024 +0200
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -10,7 +10,7 @@
+         include:
+           - os: macos-latest
+             python-version: '3.13'
+-          # - os: windows-latest  # TODO: Fix the Windows test that runs in an infinite loop.
++          # - os: windows-latest  # TODO: Fix the Windows test that runs in an infinite loop
+           #   python-version: '3.13'
+     runs-on: ${{ matrix.os }}
+     steps:

+ 17 - 0
debian/patches/cherry-picked/0.4.27-27-gaa49677.update-readme-md.patch

@@ -0,0 +1,17 @@
+Subject: Update README.md
+Origin: upstream, commit 0.4.27-27-gaa49677 <https://github.com/ahupp/python-magic/commit/0.4.27-27-gaa49677>
+Author: Adam Hupp <adam@hupp.org>
+Date: Thu May 16 09:06:59 2024 -0700
+
+    Remove travis build badge
+
+--- a/README.md
++++ b/README.md
+@@ -1,6 +1,6 @@
+ # python-magic
+ [![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)
++[![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

+ 18 - 0
debian/patches/cherry-picked/0.4.27-28-geae08a3.readme-md-add-a-badge-for-github-actions.patch

@@ -0,0 +1,18 @@
+Subject: README.md: Add a badge for GitHub Actions
+Origin: upstream, commit 0.4.27-28-geae08a3 <https://github.com/ahupp/python-magic/commit/0.4.27-28-geae08a3>
+Author: Christian Clauss <cclauss@me.com>
+Date: Thu May 16 18:16:22 2024 +0200
+
+    https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/adding-a-workflow-status-badge
+
+    [![Tests](https://github.com/ahupp/python-magic/actions/workflows/ci.yml/badge.svg)](https://github.com/ahupp/python-magic/actions/workflows/ci.yml)
+
+--- a/README.md
++++ b/README.md
+@@ -1,5 +1,6 @@
+ # python-magic
+ [![PyPI version](https://badge.fury.io/py/python-magic.svg)](https://badge.fury.io/py/python-magic)
++[![Tests](https://github.com/ahupp/python-magic/actions/workflows/ci.yml/badge.svg)](https://github.com/ahupp/python-magic/actions/workflows/ci.yml)
+ [![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

+ 15 - 0
debian/patches/cherry-picked/0.4.27-29-gfc7ebc0.update-readme-md.patch

@@ -0,0 +1,15 @@
+Subject: Update README.md
+Origin: upstream, commit 0.4.27-29-gfc7ebc0 <https://github.com/ahupp/python-magic/commit/0.4.27-29-gfc7ebc0>
+Author: Christian Clauss <cclauss@me.com>
+Date: Thu May 16 18:17:01 2024 +0200
+
+--- a/README.md
++++ b/README.md
+@@ -1,6 +1,6 @@
+ # python-magic
+ [![PyPI version](https://badge.fury.io/py/python-magic.svg)](https://badge.fury.io/py/python-magic)
+-[![Tests](https://github.com/ahupp/python-magic/actions/workflows/ci.yml/badge.svg)](https://github.com/ahupp/python-magic/actions/workflows/ci.yml)
++[![ci](https://github.com/ahupp/python-magic/actions/workflows/ci.yml/badge.svg)](https://github.com/ahupp/python-magic/actions/workflows/ci.yml)
+ [![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

+ 16 - 0
debian/patches/cherry-picked/0.4.27-3-gcc0c587.corrected-the-command-for-the-test-for-python3.patch

@@ -0,0 +1,16 @@
+Subject: Corrected the command for the test for python3
+Origin: upstream, commit 0.4.27-3-gcc0c587 <https://github.com/ahupp/python-magic/commit/0.4.27-3-gcc0c587>
+Author: ekko <gar001300@gmail.com>
+Date: Sat Oct 22 00:45:54 2022 +0530
+
+--- a/README.md
++++ b/README.md
+@@ -116,7 +116,7 @@
+ To run against a specific python version:
+ 
+ ```
+-LC_ALL=en_US.UTF-8 python3 test/test.py
++LC_ALL=en_US.UTF-8 python3 test/python_magic_test.py
+ ```
+ 
+ ## libmagic python API compatibility

+ 25 - 0
debian/patches/cherry-picked/0.4.27-30-g1217005.fix-typos-discovered-by-codespell.patch

@@ -0,0 +1,25 @@
+Subject: Fix typos discovered by codespell
+Origin: upstream, commit 0.4.27-30-g1217005 <https://github.com/ahupp/python-magic/commit/0.4.27-30-g1217005>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Wed May 22 14:10:24 2024 +0200
+
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -31,7 +31,7 @@
+ 
+ Changes to 0.4.23
+ 
+-- Include a `py.typed` sentinal to enable type checking
++- Include a `py.typed` sentinel to enable type checking
+ - Improve fix for attribute error during destruction
+ - Cleanup library loading logic
+ - Add new homebrew library dir for OSX
+@@ -76,7 +76,7 @@
+ 
+ - add MAGIC_MIME_TYPE constant, use that in preference to MAGIC_MIME internally.
+   This sets up for a breaking change in a future major version bump where
+-  MAGIC_MIME will change to mathch magic.h.
++  MAGIC_MIME will change to match magic.h.
+ - add magic.version() function to return library version
+ - add setparam/getparam to control internal behavior
+ - increase internal limits with setparam to prevent spurious error on some jpeg files

+ 108 - 0
debian/patches/cherry-picked/0.4.27-31-gcf21065.clean-up-loader-py.patch

@@ -0,0 +1,108 @@
+Subject: Clean up loader.py
+Origin: upstream, commit 0.4.27-31-gcf21065 <https://github.com/ahupp/python-magic/commit/0.4.27-31-gcf21065>
+Author: Christian Clauss <cclauss@me.com>
+Date: Wed May 22 16:15:04 2024 +0200
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -4,47 +4,65 @@
+ import glob
+ import os.path
+ 
+-def _lib_candidates():
+ 
+-  yield find_library('magic')
++def _lib_candidates_linux():
++    """Yield possible libmagic library names on Linux.
++
++    This is necessary because alpine is bad
++    """
++    yield "libmagic.so.1"
+ 
+-  if sys.platform == 'darwin':
+ 
++def _lib_candidates_macos():
++    """Yield possible libmagic library names on macOS."""
+     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')
+-
+-  elif sys.platform in ('win32', 'cygwin'):
+-
+-    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 './%s.dll' % (i,)
+-      yield find_library(i)
+-
+-  elif sys.platform == 'linux':
+-    # This is necessary because alpine is bad
+-    yield 'libmagic.so.1'
++        "/opt/homebrew/lib",
++        "/opt/local/lib",
++        "/usr/local/lib",
++    ] + glob.glob("/usr/local/Cellar/libmagic/*/lib")
++    for path in paths:
++        yield os.path.join(path, "libmagic.dylib")
++
++
++def _lib_candidates_windows():
++    """Yield possible libmagic library names on Windows."""
++    prefixes = (
++        "libmagic",
++        "magic1",
++        "magic-1",
++        "cygmagic-1",
++        "libmagic-1",
++        "msys-magic-1",
++    )
++    for prefix in prefixes:
++        # find_library searches in %PATH% but not the current directory,
++        # so look for both
++        yield "./%s.dll" % (prefix,)
++        yield find_library(prefix)
++
++
++def _lib_candidates():
++    yield find_library("magic")
++
++    func = {
++        "cygwin": _lib_candidates_windows,
++        "darwin": _lib_candidates_macos,
++        "linux": _lib_candidates_linux,
++        "win32": _lib_candidates_windows,
++    }[sys.platform]
++    # When we drop legacy Python, we can just `yield from func()`
++    for path in func():
++        yield path
+ 
+ 
+ def load_lib():
++    for lib in _lib_candidates():
++        # find_library returns None when lib not found
++        if lib:
++            try:
++                return ctypes.CDLL(lib)
++            except OSError:
++                pass
+ 
+-  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')
+-
++    raise ImportError("failed to find libmagic.  Check your installation")

+ 24 - 0
debian/patches/cherry-picked/0.4.27-32-g0a2fda3.handle-unknown-platforms-gracefully-in-loader-py.patch

@@ -0,0 +1,24 @@
+Subject: Handle unknown platforms gracefully in loader.py
+Origin: upstream, commit 0.4.27-32-g0a2fda3 <https://github.com/ahupp/python-magic/commit/0.4.27-32-g0a2fda3>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun May 26 01:01:34 2024 -0700
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -49,7 +49,9 @@
+         "darwin": _lib_candidates_macos,
+         "linux": _lib_candidates_linux,
+         "win32": _lib_candidates_windows,
+-    }[sys.platform]
++    }.get(sys.platform)
++    if func is None:
++        raise ImportError("python-magic: Unsupported platform: " + sys.platform)
+     # When we drop legacy Python, we can just `yield from func()`
+     for path in func():
+         yield path
+@@ -65,4 +67,4 @@
+                 pass
+ 
+     # It is better to raise an ImportError since we are importing magic module
+-    raise ImportError("failed to find libmagic.  Check your installation")
++    raise ImportError("python-magic: failed to find libmagic.  Check your installation")

+ 17 - 0
debian/patches/cherry-picked/0.4.27-33-g4b776d7.rename-no-json-test-to-avoid-duplicate-function-definitions.patch

@@ -0,0 +1,17 @@
+Subject: Rename no_json test to avoid duplicate function definitions
+Origin: upstream, commit 0.4.27-33-g4b776d7 <https://github.com/ahupp/python-magic/commit/0.4.27-33-g4b776d7>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun May 26 01:11:45 2024 -0700
+
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -202,7 +202,8 @@
+             buf_equals_file=True,
+         )
+ 
+-    def test_descriptions_no_json(self):
++    def test_descriptions_no_json_unchanged(self):
++        # verify non-json results are unchanged
+         m = magic.Magic(check_json=False)
+         os.environ["TZ"] = "UTC"  # To get last modified date of test.gz in UTC
+         try:

+ 28 - 0
debian/patches/cherry-picked/0.4.27-34-g339eac0.smartos-support-adapted-from-132.patch

@@ -0,0 +1,28 @@
+Subject: Smartos support, adapted from #132
+Origin: upstream, commit 0.4.27-34-g339eac0 <https://github.com/ahupp/python-magic/commit/0.4.27-34-g339eac0>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun May 26 01:15:00 2024 -0700
+
+--- a/README.md
++++ b/README.md
+@@ -75,6 +75,10 @@
+ - When using Homebrew: `brew install libmagic`
+ - When using macports: `port install file`
+ 
++### SmartOS:
++- Install libmagic for source https://github.com/threatstack/libmagic/
++- Depending on your ./configure --prefix settings set your LD_LIBRARY_PATH to <prefix>/lib
++
+ ### Troubleshooting
+ 
+ - 'MagicException: could not find any magic files!': some
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -49,6 +49,7 @@
+         "darwin": _lib_candidates_macos,
+         "linux": _lib_candidates_linux,
+         "win32": _lib_candidates_windows,
++        "sunos5": _lib_candidates_linux, 
+     }.get(sys.platform)
+     if func is None:
+         raise ImportError("python-magic: Unsupported platform: " + sys.platform)

+ 38 - 0
debian/patches/cherry-picked/0.4.27-35-ga9e6276.log-warning-on-ctypes-load-error-adapted-from-279.patch

@@ -0,0 +1,38 @@
+Subject: Log warning on ctypes load error, adapted from #279
+Origin: upstream, commit 0.4.27-35-ga9e6276 <https://github.com/ahupp/python-magic/commit/0.4.27-35-ga9e6276>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun May 26 01:21:47 2024 -0700
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -3,7 +3,9 @@
+ import sys
+ import glob
+ import os.path
++import logging
+ 
++logger = logging.getLogger(__name__)
+ 
+ def _lib_candidates_linux():
+     """Yield possible libmagic library names on Linux.
+@@ -61,11 +63,15 @@
+ def load_lib():
+     for lib in _lib_candidates():
+         # find_library returns None when lib not found
+-        if lib:
+-            try:
+-                return ctypes.CDLL(lib)
+-            except OSError:
+-                pass
++        if lib is None:
++            continue
++        if not os.path.exists(lib):
++            continue
++
++        try:
++            return ctypes.CDLL(lib)
++        except OSError:
++            logger.warning("Failed to load: " + lib, exc_info=True)
+ 
+     # It is better to raise an ImportError since we are importing magic module
+     raise ImportError("python-magic: failed to find libmagic.  Check your installation")

+ 29 - 0
debian/patches/cherry-picked/0.4.27-36-g067399b.update-readme-md.patch

@@ -0,0 +1,29 @@
+Subject: Update README.md
+Origin: upstream, commit 0.4.27-36-g067399b <https://github.com/ahupp/python-magic/commit/0.4.27-36-g067399b>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun Jun 9 17:31:24 2024 -0700
+
+--- a/README.md
++++ b/README.md
+@@ -62,19 +62,13 @@
+ sudo apt-get install libmagic1
+ ```
+ 
+-### Windows
+-
+-You'll need DLLs for libmagic.  @julian-r maintains a pypi package with the DLLs, you can fetch it with:
+-
+-```
+-pip install python-magic-bin
+-```
+-
+ ### OSX
+ 
+ - When using Homebrew: `brew install libmagic`
+ - When using 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.
++
+ ### SmartOS:
+ - Install libmagic for source https://github.com/threatstack/libmagic/
+ - Depending on your ./configure --prefix settings set your LD_LIBRARY_PATH to <prefix>/lib

+ 446 - 0
debian/patches/cherry-picked/0.4.27-37-g42980e5.simplify-tests-into-something-more-delarative.patch

@@ -0,0 +1,446 @@
+Subject: Simplify tests into something more delarative
+Origin: upstream, commit 0.4.27-37-g42980e5 <https://github.com/ahupp/python-magic/commit/0.4.27-37-g42980e5>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun May 26 18:06:37 2024 -0700
+
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -1,3 +1,5 @@
++from dataclasses import dataclass
++from enum import Enum
+ import os
+ import os.path
+ import shutil
+@@ -17,11 +19,140 @@
+ 
+ import magic
+ 
++@dataclass
++class TestFile:
++    file_name: str
++    mime_results: list[str]
++    text_results: list[str]
++    no_check_elf_results: list[str] | None
++    buf_equals_file: bool = True
+ 
+ # magic_descriptor is broken (?) in centos 7, so don't run those tests
+ SKIP_FROM_DESCRIPTOR = bool(os.environ.get("SKIP_FROM_DESCRIPTOR"))
+ 
+ 
++COMMON_PLAIN = [
++    {},
++    {"check_soft": True},
++    {"check_soft": False},
++    {"check_json": True},
++    {"check_json": False},
++]
++
++NO_SOFT = {"check_soft": False}
++
++COMMON_MIME = [{"mime": True, **k} for k in COMMON_PLAIN]
++
++CASES = {
++    "magic._pyc_": [
++        (COMMON_MIME, [
++            "application/octet-stream",
++            "text/x-bytecode.python",
++            "application/x-bytecode.python",
++        ]),
++        (COMMON_PLAIN, ["python 2.4 byte-compiled"]),
++        (NO_SOFT, ["data"]),
++    ],
++    "test.pdf": [
++        (COMMON_MIME, ["application/pdf"]),
++        (COMMON_PLAIN, [
++            "PDF document, version 1.2",
++            "PDF document, version 1.2, 2 pages",
++            "PDF document, version 1.2, 2 page(s)",
++        ]),
++        (NO_SOFT, ["ASCII text"]),
++    ],
++    "test.gz": [
++        (COMMON_MIME, ["application/gzip", "application/x-gzip"]),
++        (COMMON_PLAIN, [
++            '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',
++        ]),
++        ({"extension": True}, [
++            # some versions return '' for the extensions of a gz file,
++            # including w/ the command line.  Who knows...
++            "gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz",
++            "gz/tgz/tpz/zabw/svgz",
++            "",
++            "???",
++        ]),
++        (NO_SOFT, ["data"]),
++    ],
++    "test.snappy.parquet": [
++        (COMMON_MIME, ["application/octet-stream"]),
++        (COMMON_PLAIN, ["Apache Parquet", "Par archive data"]),
++        (NO_SOFT, ["data"]),
++    ],
++    "test.json": [
++        # TODO: soft, no_json
++        (COMMON_MIME, ["application/json"]),
++        (COMMON_PLAIN, ["JSON text data"]),
++        ({"mime": True, "check_json": False}, [
++            "data",
++        ]),
++        (NO_SOFT, ["JSON text data"])
++    ],
++    "elf-NetBSD-x86_64-echo": [
++        # TODO: soft, no elf
++        (COMMON_PLAIN, [
++            "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++            "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++        ]),
++        (COMMON_MIME, [
++            "application/x-pie-executable",
++            "application/x-sharedlib",
++        ]),
++        ({"check_elf": False}, [
++            "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++        ]),
++        # TODO: sometimes
++        #  "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++
++        (NO_SOFT, ["data"]),
++    ],
++    "test.txt": [
++        (COMMON_MIME, ["text/plain"]),
++        (COMMON_PLAIN, ["ASCII text"]),
++        ({"mime_encoding": True}, [
++            "us-ascii",
++        ]),
++        (NO_SOFT, ["ASCII text"]),
++    ],
++    "text-iso8859-1.txt": [
++        ({"mime_encoding": True}, [
++            "iso-8859-1",
++        ]),
++    ],
++    b"\xce\xbb": [
++        (COMMON_MIME, ["text/plain"]),
++    ],
++    "b\xce\xbb".decode("utf-8"): [
++        (COMMON_MIME, ["text/plain"]),
++    ],
++    "name_use.jpg": [
++        ({"extension": True}, [
++            "jpeg/jpg/jpe/jfif"
++        ]),
++    ],
++    "keep-going.jpg": [
++        (COMMON_MIME, [
++            "image/jpeg"
++        ]),
++        ({"mime": True, "keep_going": True}, [
++            "image/jpeg\\012- application/octet-stream",
++        ])
++    ],
++    "test.py": [
++        (COMMON_MIME, [
++            "text/x-python",
++            "text/x-script.python",
++        ])
++    ]
++}
++
+ class MagicTest(unittest.TestCase):
+     TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
+ 
+@@ -34,26 +165,6 @@
+     def test_fs_encoding(self):
+         self.assertEqual("utf-8", sys.getfilesystemencoding().lower())
+ 
+-    def assert_values(self, m, expected_values, buf_equals_file=True):
+-        for filename, expected_value in expected_values.items():
+-            try:
+-                filename = os.path.join(self.TESTDATA_DIR, filename)
+-            except TypeError:
+-                filename = os.path.join(self.TESTDATA_DIR.encode("utf-8"), filename)
+-
+-            if type(expected_value) is not tuple:
+-                expected_value = (expected_value,)
+-
+-            with open(filename, "rb") as f:
+-                buf_value = m.from_buffer(f.read())
+-
+-            file_value = m.from_file(filename)
+-
+-            if buf_equals_file:
+-                self.assertEqual(buf_value, file_value)
+-
+-            for value in (buf_value, file_value):
+-                self.assertIn(value, expected_value)
+ 
+     def test_from_file_str_and_bytes(self):
+         filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
+@@ -63,203 +174,34 @@
+             "application/pdf", magic.from_file(filename.encode("utf-8"), mime=True)
+         )
+ 
+-    def test_from_descriptor_str_and_bytes(self):
+-        if SKIP_FROM_DESCRIPTOR:
+-            self.skipTest("magic_descriptor is broken in this version of libmagic")
+ 
+-        filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
+-        with open(filename) as f:
+-            self.assertEqual(
+-                "application/pdf", magic.from_descriptor(f.fileno(), mime=True)
+-            )
+-            self.assertEqual(
+-                "application/pdf", magic.from_descriptor(f.fileno(), mime=True)
+-            )
+-
+-    def test_from_buffer_str_and_bytes(self):
+-        if SKIP_FROM_DESCRIPTOR:
+-            self.skipTest("magic_descriptor is broken in this version of libmagic")
+-        m = magic.Magic(mime=True)
+-
+-        self.assertTrue(
+-            m.from_buffer('#!/usr/bin/env python\nprint("foo")')
+-            in ("text/x-python", "text/x-script.python")
+-        )
+-        self.assertTrue(
+-            m.from_buffer(b'#!/usr/bin/env python\nprint("foo")')
+-            in ("text/x-python", "text/x-script.python")
+-        )
+-
+-    def test_mime_types(self):
++    def test_all_cases(self):
++        # TODO:
++        # * MAGIC_EXTENSION not supported
++        # * keep_going not supported
++        # * buffer checks
+         dest = os.path.join(MagicTest.TESTDATA_DIR, b"\xce\xbb".decode("utf-8"))
+         shutil.copyfile(os.path.join(MagicTest.TESTDATA_DIR, "lambda"), dest)
++        os.environ["TZ"] = "UTC"
+         try:
+-            m = magic.Magic(mime=True)
+-            self.assert_values(
+-                m,
+-                {
+-                    "elf-NetBSD-x86_64-echo": (
+-                        "application/x-pie-executable",
+-                        "application/x-sharedlib",
+-                    ),
+-                    "magic._pyc_": (
+-                        "application/octet-stream",
+-                        "text/x-bytecode.python",
+-                        "application/x-bytecode.python",
+-                    ),
+-                    "test.pdf": "application/pdf",
+-                    "test.gz": ("application/gzip", "application/x-gzip"),
+-                    "test.snappy.parquet": "application/octet-stream",
+-                    "text.txt": "text/plain",
+-                    b"\xce\xbb".decode("utf-8"): "text/plain",
+-                    b"\xce\xbb": "text/plain",
+-                    "test.json": "application/json",
+-                },
+-                buf_equals_file=False,
+-            )
+-        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
+-        try:
+-            self.assert_values(
+-                m,
+-                {
+-                    "elf-NetBSD-x86_64-echo": (
+-                        "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
+-                        "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
+-                    ),
+-                    "magic._pyc_": "python 2.4 byte-compiled",
+-                    "test.pdf": (
+-                        "PDF document, version 1.2",
+-                        "PDF document, version 1.2, 2 pages",
+-                        "PDF document, version 1.2, 2 page(s)",
+-                    ),
+-                    "test.gz": (
+-                        '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",
+-                    ),
+-                    "text.txt": "ASCII text",
+-                    "test.snappy.parquet": ("Apache Parquet", "Par archive data"),
+-                    "test.json": "JSON text data",
+-                },
+-                buf_equals_file=False,
+-            )
++            for file_name, cases in CASES:
++                filename = os.path.join(self.TESTDATA_DIR, file_name)
++                for flags, outputs in cases:
++                    m = magic.Magic(**flags)
++                    with open(filename) as f:
++                        self.assertIn(m.from_descriptor(f.fileno()), outputs)
++
++                    self.assertIn(m.from_file(filename), outputs)
++
++                    fname_bytes = filename.encode("utf-8")
++                    self.assertIn(m.from_file(fname_bytes), outputs)
++
++                    with open(file_name, "rb") as f:
++                        buf_result = m.from_buffer(f.read(1024))
++                        self.assertIn(buf_result, outputs)
+         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(
+-            m,
+-            {
+-                "elf-NetBSD-x86_64-echo": (
+-                    "data",
+-                    "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
+-                ),
+-                "magic._pyc_": "data",
+-                "test.pdf": "ASCII text",
+-                "test.gz": "data",
+-                "text.txt": "ASCII text",
+-                "test.snappy.parquet": "data",
+-                "test.json": "JSON text data",
+-            },
+-            buf_equals_file=False,
+-        )
+-
+-    def test_descriptions_no_elf(self):
+-        m = magic.Magic(check_elf=False)
+-        self.assert_values(
+-            m,
+-            {
+-                "elf-NetBSD-x86_64-echo": "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
+-            },
+-            buf_equals_file=True,
+-        )
+-
+-    def test_descriptions_no_json(self):
+-        m = magic.Magic(check_elf=False)
+-        self.assert_values(
+-            m,
+-            {
+-                "test.json": "data",
+-            },
+-            buf_equals_file=True,
+-        )
+-
+-    def test_descriptions_no_json_unchanged(self):
+-        # verify non-json results are unchanged
+-        m = magic.Magic(check_json=False)
+-        os.environ["TZ"] = "UTC"  # To get last modified date of test.gz in UTC
+-        try:
+-            self.assert_values(
+-                m,
+-                {
+-                    "elf-NetBSD-x86_64-echo": (
+-                        "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
+-                        "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
+-                    ),
+-                    "magic._pyc_": "python 2.4 byte-compiled",
+-                    "test.pdf": (
+-                        "PDF document, version 1.2",
+-                        "PDF document, version 1.2, 2 pages",
+-                        "PDF document, version 1.2, 2 page(s)",
+-                    ),
+-                    "test.gz": (
+-                        '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",
+-                    ),
+-                    "text.txt": "ASCII text",
+-                    "test.snappy.parquet": ("Apache Parquet", "Par archive data"),
+-                },
+-                buf_equals_file=False,
+-            )
+-        finally:
+-            del os.environ["TZ"]
+-
+-    def test_extension(self):
+-        try:
+-            m = magic.Magic(extension=True)
+-            self.assert_values(
+-                m,
+-                {
+-                    # some versions return '' for the extensions of a gz file,
+-                    # including w/ the command line.  Who knows...
+-                    "test.gz": (
+-                        "gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz",
+-                        "gz/tgz/tpz/zabw/svgz",
+-                        "",
+-                        "???",
+-                    ),
+-                    "name_use.jpg": "jpeg/jpg/jpe/jfif",
+-                },
+-            )
+-        except NotImplementedError:
+-            self.skipTest("MAGIC_EXTENSION not supported in this version")
++            os.unlink(dest)
+ 
+     def test_unicode_result_nonraw(self):
+         m = magic.Magic(raw=False)
+@@ -280,15 +222,6 @@
+         else:
+             raise unittest.SkipTest("Magic file doesn't return expected type.")
+ 
+-    def test_mime_encodings(self):
+-        m = magic.Magic(mime_encoding=True)
+-        self.assert_values(
+-            m,
+-            {
+-                "text-iso8859-1.txt": "iso-8859-1",
+-                "text.txt": "us-ascii",
+-            },
+-        )
+ 
+     def test_errors(self):
+         m = magic.Magic()
+@@ -300,22 +233,6 @@
+         finally:
+             del os.environ["MAGIC"]
+ 
+-    def test_keep_going(self):
+-        filename = os.path.join(self.TESTDATA_DIR, "keep-going.jpg")
+-
+-        m = magic.Magic(mime=True)
+-        self.assertEqual(m.from_file(filename), "image/jpeg")
+-
+-        try:
+-            # this will throw if you have an "old" version of the library
+-            # I'm otherwise not sure how to query if keep_going is supported
+-            magic.version()
+-            m = magic.Magic(mime=True, keep_going=True)
+-            self.assertEqual(
+-                m.from_file(filename), "image/jpeg\\012- application/octet-stream"
+-            )
+-        except NotImplementedError:
+-            pass
+ 
+     def test_rethrow(self):
+         old = magic.magic_buffer

+ 197 - 0
debian/patches/cherry-picked/0.4.27-38-g36ecbf9.update-magic-compat-py.patch

@@ -0,0 +1,197 @@
+Subject: Update magic/compat.py
+Origin: upstream, commit 0.4.27-38-g36ecbf9 <https://github.com/ahupp/python-magic/commit/0.4.27-38-g36ecbf9>
+Author: Adam Hupp <adam@hupp.org>
+Date: Mon Aug 5 09:24:16 2024 -0700
+
+    This pulls changes from https://github.com/file/file, commit
+    512840337ead1076519332d24fefcaa8fac36e06
+
+--- a/.gitignore
++++ b/.gitignore
+@@ -11,3 +11,4 @@
+ *.pyc
+ *~
+ dist/
++.vscode/
+--- a/magic/compat.py
++++ b/magic/compat.py
+@@ -4,14 +4,12 @@
+ Python bindings for libmagic
+ '''
+ 
+-import ctypes
+-
++import threading
+ from collections import namedtuple
+ 
+ from ctypes import *
+ from ctypes.util import find_library
+ 
+-
+ from . import loader
+ 
+ _libraries = {}
+@@ -45,13 +43,19 @@
+ 
+ MAGIC_NO_CHECK_BUILTIN = NO_CHECK_BUILTIN = 4173824
+ 
++MAGIC_PARAM_INDIR_MAX = PARAM_INDIR_MAX = 0
++MAGIC_PARAM_NAME_MAX = PARAM_NAME_MAX = 1
++MAGIC_PARAM_ELF_PHNUM_MAX = PARAM_ELF_PHNUM_MAX = 2
++MAGIC_PARAM_ELF_SHNUM_MAX = PARAM_ELF_SHNUM_MAX = 3
++MAGIC_PARAM_ELF_NOTES_MAX = PARAM_ELF_NOTES_MAX = 4
++MAGIC_PARAM_REGEX_MAX = PARAM_REGEX_MAX = 5
++MAGIC_PARAM_BYTES_MAX = PARAM_BYTES_MAX = 6
++
+ FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name'))
+ 
+ 
+ class magic_set(Structure):
+     pass
+-
+-
+ magic_set._fields_ = []
+ magic_t = POINTER(magic_set)
+ 
+@@ -103,6 +107,14 @@
+ _errno.restype = c_int
+ _errno.argtypes = [magic_t]
+ 
++_getparam = _libraries['magic'].magic_getparam
++_getparam.restype = c_int
++_getparam.argtypes = [magic_t, c_int, c_void_p]
++
++_setparam = _libraries['magic'].magic_setparam
++_setparam.restype = c_int
++_setparam.argtypes = [magic_t, c_int, c_void_p]
++
+ 
+ class Magic(object):
+     def __init__(self, ms):
+@@ -228,29 +240,81 @@
+         """
+         return _errno(self._magic_t)
+ 
++    def getparam(self, param):
++        """
++        Returns the param value if successful and -1 if the parameter
++        was unknown.
++        """
++        v = c_int()
++        i = _getparam(self._magic_t, param, byref(v))
++        if i == -1:
++            return -1
++        return v.value
++
++    def setparam(self, param, value):
++        """
++        Returns 0 if successful and -1 if the parameter was unknown.
++        """
++        v = c_int(value)
++        return _setparam(self._magic_t, param, byref(v))
++
+ 
+ def open(flags):
+     """
+     Returns a magic object on success and None on failure.
+     Flags argument as for setflags.
+     """
+-    return Magic(_open(flags))
++    magic_t = _open(flags)
++    if magic_t is None:
++        return None
++    return Magic(magic_t)
+ 
+ 
+ # Objects used by `detect_from_` functions
+-mime_magic = Magic(_open(MAGIC_MIME))
+-mime_magic.load()
+-none_magic = Magic(_open(MAGIC_NONE))
+-none_magic.load()
++class error(Exception):
++    pass
+ 
++class MagicDetect(object):
++    def __init__(self):
++        self.mime_magic = open(MAGIC_MIME)
++        if self.mime_magic is None:
++            raise error
++        if self.mime_magic.load() == -1:
++            self.mime_magic.close()
++            self.mime_magic = None
++            raise error
++        self.none_magic = open(MAGIC_NONE)
++        if self.none_magic is None:
++            self.mime_magic.close()
++            self.mime_magic = None
++            raise error
++        if self.none_magic.load() == -1:
++            self.none_magic.close()
++            self.none_magic = None
++            self.mime_magic.close()
++            self.mime_magic = None
++            raise error
++
++    def __del__(self):
++        if self.mime_magic is not None:
++            self.mime_magic.close()
++        if self.none_magic is not None:
++            self.none_magic.close()
++
++threadlocal = threading.local()
++
++def _detect_make():
++    v = getattr(threadlocal, "magic_instance", None)
++    if v is None:
++        v = MagicDetect()
++        setattr(threadlocal, "magic_instance", v)
++    return v
+ 
+ def _create_filemagic(mime_detected, type_detected):
+-    splat = mime_detected.split('; ')
+-    mime_type = splat[0]
+-    if len(splat) == 2:
+-        mime_encoding = splat[1]
+-    else:
+-        mime_encoding = ''
++    try:
++        mime_type, mime_encoding = mime_detected.split('; ')
++    except ValueError:
++        raise ValueError(mime_detected)
+ 
+     return FileMagic(name=type_detected, mime_type=mime_type,
+                      encoding=mime_encoding.replace('charset=', ''))
+@@ -261,9 +325,9 @@
+ 
+     Returns a `FileMagic` namedtuple.
+     '''
+-
+-    return _create_filemagic(mime_magic.file(filename),
+-                             none_magic.file(filename))
++    x = _detect_make()
++    return _create_filemagic(x.mime_magic.file(filename),
++                             x.none_magic.file(filename))
+ 
+ 
+ def detect_from_fobj(fobj):
+@@ -273,8 +337,9 @@
+     '''
+ 
+     file_descriptor = fobj.fileno()
+-    return _create_filemagic(mime_magic.descriptor(file_descriptor),
+-                             none_magic.descriptor(file_descriptor))
++    x = _detect_make()
++    return _create_filemagic(x.mime_magic.descriptor(file_descriptor),
++                             x.none_magic.descriptor(file_descriptor))
+ 
+ 
+ def detect_from_content(byte_content):
+@@ -283,5 +348,6 @@
+     Returns a `FileMagic` namedtuple.
+     '''
+ 
+-    return _create_filemagic(mime_magic.buffer(byte_content),
+-                             none_magic.buffer(byte_content))
++    x = _detect_make()
++    return _create_filemagic(x.mime_magic.buffer(byte_content),
++                             x.none_magic.buffer(byte_content))

+ 391 - 0
debian/patches/cherry-picked/0.4.27-39-ga3ed086.unbreak-various-things.patch

@@ -0,0 +1,391 @@
+Subject: Unbreak various things
+Origin: upstream, commit 0.4.27-39-ga3ed086 <https://github.com/ahupp/python-magic/commit/0.4.27-39-ga3ed086>
+Author: Adam Hupp <adam@hupp.org>
+Date: Tue Feb 18 10:55:05 2025 -0800
+
+     * A merge to reduce error spam during loading broke .so
+       loading in at least some (maybe all?) cases, where find_library
+       doesn't return an absolute path.
+     * Prematurely pushed some in-progress test changes that were super broken, all fixed now.
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -7,6 +7,7 @@
+ 
+ logger = logging.getLogger(__name__)
+ 
++
+ def _lib_candidates_linux():
+     """Yield possible libmagic library names on Linux.
+ 
+@@ -51,7 +52,7 @@
+         "darwin": _lib_candidates_macos,
+         "linux": _lib_candidates_linux,
+         "win32": _lib_candidates_windows,
+-        "sunos5": _lib_candidates_linux, 
++        "sunos5": _lib_candidates_linux,
+     }.get(sys.platform)
+     if func is None:
+         raise ImportError("python-magic: Unsupported platform: " + sys.platform)
+@@ -61,17 +62,20 @@
+ 
+ 
+ def load_lib():
++    exc = []
+     for lib in _lib_candidates():
+         # find_library returns None when lib not found
+         if lib is None:
+             continue
+-        if not os.path.exists(lib):
+-            continue
+ 
+         try:
+             return ctypes.CDLL(lib)
+-        except OSError:
+-            logger.warning("Failed to load: " + lib, exc_info=True)
++        except OSError as e:
++            exc.append(e)
++
++    msg = "\n".join([str(e) for e in exc])
+ 
+     # It is better to raise an ImportError since we are importing magic module
+-    raise ImportError("python-magic: failed to find libmagic.  Check your installation")
++    raise ImportError(
++        "python-magic: failed to find libmagic.  Check your installation: \n" + msg
++    )
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -5,6 +5,7 @@
+ import shutil
+ import sys
+ import tempfile
++from typing import List, Union
+ import unittest
+ 
+ import pytest
+@@ -19,140 +20,162 @@
+ 
+ import magic
+ 
++
+ @dataclass
+ class TestFile:
+     file_name: str
+-    mime_results: list[str]
+-    text_results: list[str]
+-    no_check_elf_results: list[str] | None
++    mime_results: List[str]
++    text_results: List[str]
++    no_check_elf_results: Union[List[str], None]
+     buf_equals_file: bool = True
+ 
++
+ # magic_descriptor is broken (?) in centos 7, so don't run those tests
+ SKIP_FROM_DESCRIPTOR = bool(os.environ.get("SKIP_FROM_DESCRIPTOR"))
+ 
+ 
+-COMMON_PLAIN = [
+-    {},
+-    {"check_soft": True},
+-    {"check_soft": False},
+-    {"check_json": True},
+-    {"check_json": False},
+-]
+-
+-NO_SOFT = {"check_soft": False}
+-
+-COMMON_MIME = [{"mime": True, **k} for k in COMMON_PLAIN]
++COMMON_PLAIN = [{}]
++NO_SOFT = [{"check_soft": False}]
++COMMON_MIME = [{"mime": True}]
+ 
+ CASES = {
+-    "magic._pyc_": [
+-        (COMMON_MIME, [
+-            "application/octet-stream",
+-            "text/x-bytecode.python",
+-            "application/x-bytecode.python",
+-        ]),
++    b"magic._pyc_": [
++        (
++            COMMON_MIME,
++            [
++                "application/octet-stream",
++                "text/x-bytecode.python",
++                "application/x-bytecode.python",
++            ],
++        ),
+         (COMMON_PLAIN, ["python 2.4 byte-compiled"]),
+         (NO_SOFT, ["data"]),
+     ],
+-    "test.pdf": [
++    b"test.pdf": [
+         (COMMON_MIME, ["application/pdf"]),
+-        (COMMON_PLAIN, [
+-            "PDF document, version 1.2",
+-            "PDF document, version 1.2, 2 pages",
+-            "PDF document, version 1.2, 2 page(s)",
+-        ]),
++        (
++            COMMON_PLAIN,
++            [
++                "PDF document, version 1.2",
++                "PDF document, version 1.2, 2 pages",
++                "PDF document, version 1.2, 2 page(s)",
++            ],
++        ),
+         (NO_SOFT, ["ASCII text"]),
+     ],
+-    "test.gz": [
++    b"test.gz": [
+         (COMMON_MIME, ["application/gzip", "application/x-gzip"]),
+-        (COMMON_PLAIN, [
+-            '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',
+-        ]),
+-        ({"extension": True}, [
+-            # some versions return '' for the extensions of a gz file,
+-            # including w/ the command line.  Who knows...
+-            "gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz",
+-            "gz/tgz/tpz/zabw/svgz",
+-            "",
+-            "???",
+-        ]),
++        (
++            COMMON_PLAIN,
++            [
++                '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',
++            ],
++        ),
++        (
++            [{"extension": True}],
++            [
++                # some versions return '' for the extensions of a gz file,
++                # including w/ the command line.  Who knows...
++                "gz/tgz/tpz/zabw/svgz/adz/kmy/xcfgz",
++                "gz/tgz/tpz/zabw/svgz",
++                "",
++                "???",
++            ],
++        ),
+         (NO_SOFT, ["data"]),
+     ],
+-    "test.snappy.parquet": [
++    b"test.snappy.parquet": [
+         (COMMON_MIME, ["application/octet-stream"]),
+         (COMMON_PLAIN, ["Apache Parquet", "Par archive data"]),
+         (NO_SOFT, ["data"]),
+     ],
+-    "test.json": [
+-        # TODO: soft, no_json
++    b"test.json": [
+         (COMMON_MIME, ["application/json"]),
+         (COMMON_PLAIN, ["JSON text data"]),
+-        ({"mime": True, "check_json": False}, [
+-            "data",
+-        ]),
+-        (NO_SOFT, ["JSON text data"])
++        (
++            [{"mime": True, "check_json": False}],
++            [
++                "text/plain",
++            ],
++        ),
++        (NO_SOFT, ["JSON text data"]),
+     ],
+-    "elf-NetBSD-x86_64-echo": [
++    b"elf-NetBSD-x86_64-echo": [
+         # TODO: soft, no elf
+-        (COMMON_PLAIN, [
+-            "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
+-            "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
+-        ]),
+-        (COMMON_MIME, [
+-            "application/x-pie-executable",
+-            "application/x-sharedlib",
+-        ]),
+-        ({"check_elf": False}, [
+-            "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
+-        ]),
++        (
++            COMMON_PLAIN,
++            [
++                "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++                "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
++            ],
++        ),
++        (
++            COMMON_MIME,
++            [
++                "application/x-pie-executable",
++                "application/x-sharedlib",
++            ],
++        ),
++        (
++            [{"check_elf": False}],
++            [
++                "ELF 64-bit LSB shared object, x86-64, version 1 (SYSV)",
++            ],
++        ),
+         # TODO: sometimes
+         #  "ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld.elf_so, for NetBSD 8.0, not stripped",
+-
+         (NO_SOFT, ["data"]),
+     ],
+-    "test.txt": [
++    b"text.txt": [
+         (COMMON_MIME, ["text/plain"]),
+         (COMMON_PLAIN, ["ASCII text"]),
+-        ({"mime_encoding": True}, [
+-            "us-ascii",
+-        ]),
++        (
++            [{"mime_encoding": True}],
++            [
++                "us-ascii",
++            ],
++        ),
+         (NO_SOFT, ["ASCII text"]),
+     ],
+-    "text-iso8859-1.txt": [
+-        ({"mime_encoding": True}, [
+-            "iso-8859-1",
+-        ]),
++    b"text-iso8859-1.txt": [
++        (
++            [{"mime_encoding": True}],
++            [
++                "iso-8859-1",
++            ],
++        ),
+     ],
+     b"\xce\xbb": [
+         (COMMON_MIME, ["text/plain"]),
+     ],
+-    "b\xce\xbb".decode("utf-8"): [
+-        (COMMON_MIME, ["text/plain"]),
++    b"name_use.jpg": [
++        ([{"extension": True}], ["jpeg/jpg/jpe/jfif"]),
++    ],
++    b"keep-going.jpg": [
++        (COMMON_MIME, ["image/jpeg"]),
++        (
++            [{"mime": True, "keep_going": True}],
++            [
++                "image/jpeg\\012- application/octet-stream",
++            ],
++        ),
++    ],
++    b"../../magic/loader.py": [
++        (
++            COMMON_MIME,
++            [
++                "text/x-python",
++                "text/x-script.python",
++            ],
++        )
+     ],
+-    "name_use.jpg": [
+-        ({"extension": True}, [
+-            "jpeg/jpg/jpe/jfif"
+-        ]),
+-    ],
+-    "keep-going.jpg": [
+-        (COMMON_MIME, [
+-            "image/jpeg"
+-        ]),
+-        ({"mime": True, "keep_going": True}, [
+-            "image/jpeg\\012- application/octet-stream",
+-        ])
+-    ],
+-    "test.py": [
+-        (COMMON_MIME, [
+-            "text/x-python",
+-            "text/x-script.python",
+-        ])
+-    ]
+ }
+ 
++
+ class MagicTest(unittest.TestCase):
+     TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
+ 
+@@ -165,7 +188,6 @@
+     def test_fs_encoding(self):
+         self.assertEqual("utf-8", sys.getfilesystemencoding().lower())
+ 
+-
+     def test_from_file_str_and_bytes(self):
+         filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
+ 
+@@ -174,7 +196,6 @@
+             "application/pdf", magic.from_file(filename.encode("utf-8"), mime=True)
+         )
+ 
+-
+     def test_all_cases(self):
+         # TODO:
+         # * MAGIC_EXTENSION not supported
+@@ -184,21 +205,24 @@
+         shutil.copyfile(os.path.join(MagicTest.TESTDATA_DIR, "lambda"), dest)
+         os.environ["TZ"] = "UTC"
+         try:
+-            for file_name, cases in CASES:
+-                filename = os.path.join(self.TESTDATA_DIR, file_name)
+-                for flags, outputs in cases:
+-                    m = magic.Magic(**flags)
+-                    with open(filename) as f:
+-                        self.assertIn(m.from_descriptor(f.fileno()), outputs)
+-
+-                    self.assertIn(m.from_file(filename), outputs)
+-
+-                    fname_bytes = filename.encode("utf-8")
+-                    self.assertIn(m.from_file(fname_bytes), outputs)
+-
+-                    with open(file_name, "rb") as f:
+-                        buf_result = m.from_buffer(f.read(1024))
+-                        self.assertIn(buf_result, outputs)
++            for filename, cases in CASES.items():
++                filename = os.path.join(self.TESTDATA_DIR.encode("utf-8"), filename)
++                print("test case ", filename, file=sys.stderr)
++                for flag_variants, outputs in cases:
++                    for flags in flag_variants:
++                        print("flags", flags, file=sys.stderr)
++                        m = magic.Magic(**flags)
++                        with open(filename) as f:
++                            self.assertIn(m.from_descriptor(f.fileno()), outputs)
++
++                        self.assertIn(m.from_file(filename), outputs)
++
++                        fname_str = filename.decode("utf-8")
++                        self.assertIn(m.from_file(fname_str), outputs)
++
++                        with open(filename, "rb") as f:
++                            buf_result = m.from_buffer(f.read(1024))
++                            self.assertIn(buf_result, outputs)
+         finally:
+             del os.environ["TZ"]
+             os.unlink(dest)
+@@ -222,7 +246,6 @@
+         else:
+             raise unittest.SkipTest("Magic file doesn't return expected type.")
+ 
+-
+     def test_errors(self):
+         m = magic.Magic()
+         self.assertRaises(IOError, m.from_file, "nonexistent")
+@@ -233,7 +256,6 @@
+         finally:
+             del os.environ["MAGIC"]
+ 
+-
+     def test_rethrow(self):
+         old = magic.magic_buffer
+         try:

+ 111 - 0
debian/patches/cherry-picked/0.4.27-40-g5a89644.add-support-for-python-3-13.patch

@@ -0,0 +1,111 @@
+Subject: Add support for python 3.13
+Origin: upstream, commit 0.4.27-40-g5a89644 <https://github.com/ahupp/python-magic/commit/0.4.27-40-g5a89644>
+Author: Adam Hupp <adam@hupp.org>
+Date: Wed Feb 19 12:30:05 2025 -0800
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -5,11 +5,11 @@
+     strategy:
+       fail-fast: false
+       matrix:
+-        os: ['ubuntu-latest']
+-        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
++        os: ["ubuntu-latest"]
++        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
+         include:
+           - os: macos-latest
+-            python-version: '3.13'
++            python-version: "3.13"
+           # - os: windows-latest  # TODO: Fix the Windows test that runs in an infinite loop
+           #   python-version: '3.13'
+     runs-on: ${{ matrix.os }}
+@@ -28,4 +28,4 @@
+         run: pip install python-magic-bin
+       - run: LC_ALL=en_US.UTF-8 pytest
+         shell: bash
+-        timeout-minutes: 15  # Limit Windows infinite loop.
++        timeout-minutes: 15 # Limit Windows infinite loop.
+--- a/setup.py
++++ b/setup.py
+@@ -8,41 +8,43 @@
+ 
+ def read(file_name):
+     """Read a text file and return the content as a string."""
+-    with io.open(os.path.join(os.path.dirname(__file__), file_name),
+-                 encoding='utf-8') as f:
++    with io.open(
++        os.path.join(os.path.dirname(__file__), file_name), encoding="utf-8"
++    ) as f:
+         return f.read()
+ 
++
+ setuptools.setup(
+-    name='python-magic',
+-    description='File type identification using libmagic',
+-    author='Adam Hupp',
+-    author_email='adam@hupp.org',
++    name="python-magic",
++    description="File type identification using libmagic",
++    author="Adam Hupp",
++    author_email="adam@hupp.org",
+     url="http://github.com/ahupp/python-magic",
+-    version='0.4.28',
+-    long_description=read('README.md'),
+-    long_description_content_type='text/markdown',
+-    packages=['magic'],
++    version="0.4.28",
++    long_description=read("README.md"),
++    long_description_content_type="text/markdown",
++    packages=["magic"],
+     package_data={
+-        'magic': ['py.typed', '*.pyi', '**/*.pyi'],
++        "magic": ["py.typed", "*.pyi", "**/*.pyi"],
+     },
+     keywords="mime magic file",
+     license="MIT",
+-    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
++    python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
+     classifiers=[
+-        'Intended Audience :: Developers',
+-        'License :: OSI Approved :: MIT License',
+-        'Programming Language :: Python',
+-        'Programming Language :: Python :: 2.7',
+-        'Programming Language :: Python :: 3',
+-        'Programming Language :: Python :: 3.5',
+-        'Programming Language :: Python :: 3.6',
+-        'Programming Language :: Python :: 3.7',
+-        'Programming Language :: Python :: 3.8',
+-        'Programming Language :: Python :: 3.9',
+-        'Programming Language :: Python :: 3.10',
+-        'Programming Language :: Python :: 3.11',
+-        'Programming Language :: Python :: 3.12',
+-        'Programming Language :: Python :: Implementation :: CPython',
++        "Intended Audience :: Developers",
++        "License :: OSI Approved :: MIT License",
++        "Programming Language :: Python",
++        "Programming Language :: Python :: 2.7",
++        "Programming Language :: Python :: 3",
++        "Programming Language :: Python :: 3.5",
++        "Programming Language :: Python :: 3.6",
++        "Programming Language :: Python :: 3.7",
++        "Programming Language :: Python :: 3.8",
++        "Programming Language :: Python :: 3.9",
++        "Programming Language :: Python :: 3.10",
++        "Programming Language :: Python :: 3.11",
++        "Programming Language :: Python :: 3.12",
++        "Programming Language :: Python :: 3.13",
++        "Programming Language :: Python :: Implementation :: CPython",
+     ],
+ )
+-
+--- a/tox.ini
++++ b/tox.ini
+@@ -9,6 +9,7 @@
+     py310,
+     py311,
+     py312,
++    py313,
+     mypy
+ 
+ [testenv]

+ 267 - 0
debian/patches/cherry-picked/0.4.27-41-g62bd3c6.format-with-ruff.patch

@@ -0,0 +1,267 @@
+Subject: Format with ruff
+Origin: upstream, commit 0.4.27-41-g62bd3c6 <https://github.com/ahupp/python-magic/commit/0.4.27-41-g62bd3c6>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sat Mar 1 17:10:13 2025 -0800
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -38,12 +38,27 @@
+     Magic is a wrapper around the libmagic C library.
+     """
+ 
+-    def __init__(self, mime=False, magic_file=None, mime_encoding=False,
+-                 keep_going=False, uncompress=False, raw=False, extension=False,
+-                 follow_symlinks=False, check_tar=True, check_soft=True,
+-                 check_apptype=True, check_elf=True, check_text=True,
+-                 check_cdf=True, check_csv=True, check_encoding=True,
+-                 check_json=True, check_simh=True):
++    def __init__(
++        self,
++        mime=False,
++        magic_file=None,
++        mime_encoding=False,
++        keep_going=False,
++        uncompress=False,
++        raw=False,
++        extension=False,
++        follow_symlinks=False,
++        check_tar=True,
++        check_soft=True,
++        check_apptype=True,
++        check_elf=True,
++        check_text=True,
++        check_cdf=True,
++        check_csv=True,
++        check_encoding=True,
++        check_json=True,
++        check_simh=True,
++    ):
+         """
+         Create a new libmagic wrapper.
+ 
+@@ -101,7 +116,9 @@
+         # MAGIC_EXTENSION was added in 523 or 524, so bail if
+         # it doesn't appear to be available
+         if extension and (not _has_version or version() < 524):
+-            raise NotImplementedError('MAGIC_EXTENSION is not supported in this version of libmagic')
++            raise NotImplementedError(
++                "MAGIC_EXTENSION is not supported in this version of libmagic"
++            )
+ 
+         # For https://github.com/ahupp/python-magic/issues/190
+         # libmagic has fixed internal limits that some files exceed, causing
+@@ -128,7 +145,7 @@
+                 # which is not what libmagic expects
+                 # NEXTBREAK: only take bytes
+                 if type(buf) == str and str != bytes:
+-                    buf = buf.encode('utf-8', errors='replace')
++                    buf = buf.encode("utf-8", errors="replace")
+                 return maybe_decode(magic_buffer(self.cookie, buf))
+             except MagicException as e:
+                 return self._handle509Bug(e)
+@@ -176,7 +193,7 @@
+         # incorrect fix for a threading problem, however I'm leaving
+         # it in because it's harmless and I'm slightly afraid to
+         # remove it.
+-        if hasattr(self, 'cookie') and self.cookie and magic_close:
++        if hasattr(self, "cookie") and self.cookie and magic_close:
+             magic_close(self.cookie)
+             self.cookie = None
+ 
+@@ -192,7 +209,7 @@
+ 
+ 
+ def from_file(filename, mime=False):
+-    """"
++    """
+     Accepts a filename and returns the detected filetype.  Return
+     value is the mimetype if mime=True, otherwise a human readable
+     name.
+@@ -230,7 +247,9 @@
+     m = _get_magic_type(mime)
+     return m.from_descriptor(fd)
+ 
++
+ from . import loader
++
+ libmagic = loader.load_lib()
+ 
+ magic_t = ctypes.c_void_p
+@@ -261,20 +280,23 @@
+     else:
+         # backslashreplace here because sometimes libmagic will return metadata in the charset
+         # of the file, which is unknown to us (e.g the title of a Word doc)
+-        return s.decode('utf-8', 'backslashreplace')
++        return s.decode("utf-8", "backslashreplace")
+ 
+ 
+ try:
+     from os import PathLike
++
+     def unpath(filename):
+         if isinstance(filename, PathLike):
+             return filename.__fspath__()
+         else:
+             return filename
+ except ImportError:
++
+     def unpath(filename):
+         return filename
+ 
++
+ def coerce_filename(filename):
+     if filename is None:
+         return None
+@@ -286,12 +308,11 @@
+     # then you'll get inconsistent behavior (crashes) depending on the user's
+     # LANG environment variable
+     # NEXTBREAK: remove
+-    is_unicode = (sys.version_info[0] <= 2 and
+-                 isinstance(filename, unicode)) or \
+-                 (sys.version_info[0] >= 3 and
+-                  isinstance(filename, str))
++    is_unicode = (sys.version_info[0] <= 2 and isinstance(filename, unicode)) or (
++        sys.version_info[0] >= 3 and isinstance(filename, str)
++    )
+     if is_unicode:
+-        return filename.encode('utf-8', 'surrogateescape')
++        return filename.encode("utf-8", "surrogateescape")
+     else:
+         return filename
+ 
+@@ -370,7 +391,7 @@
+ magic_compile.argtypes = [magic_t, c_char_p]
+ 
+ _has_param = False
+-if hasattr(libmagic, 'magic_setparam') and hasattr(libmagic, 'magic_getparam'):
++if hasattr(libmagic, "magic_setparam") and hasattr(libmagic, "magic_getparam"):
+     _has_param = True
+     _magic_setparam = libmagic.magic_setparam
+     _magic_setparam.restype = c_int
+@@ -443,8 +464,8 @@
+ MAGIC_NO_CHECK_CDF = 0x0040000  # Don't check for CDF files
+ MAGIC_NO_CHECK_CSV = 0x0080000  # Don't check for CSV files
+ MAGIC_NO_CHECK_ENCODING = 0x0200000  # Don't check text encodings
+-MAGIC_NO_CHECK_JSON = 0x0400000 # Don't check for JSON files
+-MAGIC_NO_CHECK_SIMH = 0x0800000 # Don't check for SIMH tape files
++MAGIC_NO_CHECK_JSON = 0x0400000  # Don't check for JSON files
++MAGIC_NO_CHECK_SIMH = 0x0800000  # Don't check for SIMH tape files
+ 
+ MAGIC_PARAM_INDIR_MAX = 0  # Recursion limit for indirect magic
+ MAGIC_PARAM_NAME_MAX = 1  # Use count limit for name/use magic
+@@ -468,22 +489,20 @@
+             warnings.warn(
+                 "Using compatibility mode with libmagic's python binding. "
+                 "See https://github.com/ahupp/python-magic/blob/master/COMPAT.md for details.",
+-                PendingDeprecationWarning)
++                PendingDeprecationWarning,
++            )
+ 
+             return fn(*args, **kwargs)
+ 
+         return _
+ 
+-    fn = ['detect_from_filename',
+-          'detect_from_content',
+-          'detect_from_fobj',
+-          'open']
++    fn = ["detect_from_filename", "detect_from_content", "detect_from_fobj", "open"]
+     for fname in fn:
+         to_module[fname] = deprecation_wrapper(compat.__dict__[fname])
+ 
+     # copy constants over, ensuring there's no conflicts
+     is_const_re = re.compile("^[A-Z_]+$")
+-    allowed_inconsistent = set(['MAGIC_MIME'])
++    allowed_inconsistent = set(["MAGIC_MIME"])
+     for name, value in compat.__dict__.items():
+         if is_const_re.match(name):
+             if name in to_module:
+--- a/magic/__init__.pyi
++++ b/magic/__init__.pyi
+@@ -11,7 +11,25 @@
+     flags: int = ...
+     cookie: Any = ...
+     lock: threading.Lock = ...
+-    def __init__(self, mime: bool = ..., magic_file: Optional[Any] = ..., mime_encoding: bool = ..., keep_going: bool = ..., uncompress: bool = ..., raw: bool = ..., extension: bool = ..., follow_symlinks: bool = ..., check_tar: bool = ..., check_soft: bool = ..., check_apptype: bool = ..., check_elf: bool = ..., check_text: bool = ..., check_encoding: bool = ..., check_json: bool = ..., check_simh: bool = ...) -> None: ...
++    def __init__(
++        self,
++        mime: bool = ...,
++        magic_file: Optional[Any] = ...,
++        mime_encoding: bool = ...,
++        keep_going: bool = ...,
++        uncompress: bool = ...,
++        raw: bool = ...,
++        extension: bool = ...,
++        follow_symlinks: bool = ...,
++        check_tar: bool = ...,
++        check_soft: bool = ...,
++        check_apptype: bool = ...,
++        check_elf: bool = ...,
++        check_text: bool = ...,
++        check_encoding: bool = ...,
++        check_json: bool = ...,
++        check_simh: bool = ...,
++    ) -> None: ...
+     def from_buffer(self, buf: Union[bytes, str]) -> Text: ...
+     def from_file(self, filename: Union[bytes, str, PathLike]) -> Text: ...
+     def from_descriptor(self, fd: int, mime: bool = ...) -> Text: ...
+--- /dev/null
++++ b/ruff.toml
+@@ -0,0 +1,3 @@
++exclude = ["magic/compat.py"]
++
++
+--- a/test/libmagic_test.py
++++ b/test/libmagic_test.py
+@@ -6,16 +6,20 @@
+ import os.path
+ 
+ # magic_descriptor is broken (?) in centos 7, so don't run those tests
+-SKIP_FROM_DESCRIPTOR = bool(os.environ.get('SKIP_FROM_DESCRIPTOR'))
++SKIP_FROM_DESCRIPTOR = bool(os.environ.get("SKIP_FROM_DESCRIPTOR"))
+ 
+-TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'testdata'))
++TESTDATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "testdata"))
+ 
+ 
+ class MagicTestCase(unittest.TestCase):
+-    filename = os.path.join(TESTDATA_DIR, 'test.pdf')
+-    expected_mime_type = 'application/pdf'
+-    expected_encoding = 'us-ascii'
+-    expected_name = ('PDF document, version 1.2', 'PDF document, version 1.2, 2 pages', 'PDF document, version 1.2, 2 page(s)')
++    filename = os.path.join(TESTDATA_DIR, "test.pdf")
++    expected_mime_type = "application/pdf"
++    expected_encoding = "us-ascii"
++    expected_name = (
++        "PDF document, version 1.2",
++        "PDF document, version 1.2, 2 pages",
++        "PDF document, version 1.2, 2 page(s)",
++    )
+ 
+     def assert_result(self, result):
+         self.assertEqual(result.mime_type, self.expected_mime_type)
+@@ -27,11 +31,9 @@
+         self.assert_result(result)
+ 
+     def test_detect_from_fobj(self):
+-
+         if SKIP_FROM_DESCRIPTOR:
+             self.skipTest("magic_descriptor is broken in this version of libmagic")
+ 
+-
+         with open(self.filename) as fobj:
+             result = magic.detect_from_fobj(fobj)
+         self.assert_result(result)
+@@ -41,10 +43,10 @@
+         # this avoids hitting a bug in python3+libfile bindings
+         # see https://github.com/ahupp/python-magic/issues/152
+         # for a similar issue
+-        with open(self.filename, 'rb') as fobj:
++        with open(self.filename, "rb") as fobj:
+             result = magic.detect_from_content(fobj.read(4096))
+         self.assert_result(result)
+ 
+ 
+-if __name__ == '__main__':
++if __name__ == "__main__":
+     unittest.main()

+ 23 - 0
debian/patches/cherry-picked/0.4.27-42-gfac6615.small-fix-to-readme-that-makes-pip-install-command-easier-to-see-find.patch

@@ -0,0 +1,23 @@
+Subject: Small Fix to ReadMe that makes pip install command easier to see/find
+Origin: upstream, commit 0.4.27-42-gfac6615 <https://github.com/ahupp/python-magic/commit/0.4.27-42-gfac6615>
+Author: Name <87663453+Dodf12@users.noreply.github.com>
+Date: Tue Jul 1 22:18:39 2025 -0700
+
+    I wasn't able to really find the pip command quickly, so I thought this addition would help with readability and help people find the pip install command easier
+
+--- a/README.md
++++ b/README.md
+@@ -45,8 +45,11 @@
+ 
+ ## Installation
+ 
+-The current stable version of python-magic is available on PyPI and
+-can be installed by running `pip install python-magic`.
++The current stable version of Python-Magic is available on PyPI and
++can be installed by running:
++```
++pip install python-magic
++```
+ 
+ Other sources:
+ 

+ 16 - 0
debian/patches/cherry-picked/0.4.27-43-g8361a33.update-readme-md.patch

@@ -0,0 +1,16 @@
+Subject: Update README.md
+Origin: upstream, commit 0.4.27-43-g8361a33 <https://github.com/ahupp/python-magic/commit/0.4.27-43-g8361a33>
+Author: Adam Hupp <adam@hupp.org>
+Date: Sun Jul 6 15:23:54 2025 -0700
+
+--- a/README.md
++++ b/README.md
+@@ -45,7 +45,7 @@
+ 
+ ## Installation
+ 
+-The current stable version of Python-Magic is available on PyPI and
++The current stable version of python-magic is available on PyPI and
+ can be installed by running:
+ ```
+ pip install python-magic

+ 16 - 0
debian/patches/cherry-picked/0.4.27-44-g7cbbc99.update-readme-md.patch

@@ -0,0 +1,16 @@
+Subject: Update README.md
+Origin: upstream, commit 0.4.27-44-g7cbbc99 <https://github.com/ahupp/python-magic/commit/0.4.27-44-g7cbbc99>
+Author: Adam Hupp <adam@hupp.org>
+Date: Thu Aug 14 20:10:59 2025 -0700
+
+--- a/README.md
++++ b/README.md
+@@ -73,7 +73,7 @@
+ 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.
+ 
+ ### SmartOS:
+-- Install libmagic for source https://github.com/threatstack/libmagic/
++- Install libmagic for source: https://github.com/file/file
+ - Depending on your ./configure --prefix settings set your LD_LIBRARY_PATH to <prefix>/lib
+ 
+ ### Troubleshooting

+ 36 - 0
debian/patches/cherry-picked/0.4.27-45-gf8fb0ee.add-python-3-14-to-the-testing.patch

@@ -0,0 +1,36 @@
+Subject: Add Python 3.14 to the testing
+Origin: upstream, commit 0.4.27-45-gf8fb0ee <https://github.com/ahupp/python-magic/commit/0.4.27-45-gf8fb0ee>
+Author: Christian Clauss <cclauss@me.com>
+Date: Wed Sep 24 13:55:15 2025 +0200
+
+    Python v3.14 -- October 7th
+    * https://www.python.org/download/pre-releases
+    * https://www.python.org/downloads/release/python-3140rc3
+    * https://docs.python.org/3.14/whatsnew/3.14.html
+
+    Like:
+    * #347
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -6,16 +6,16 @@
+       fail-fast: false
+       matrix:
+         os: ["ubuntu-latest"]
+-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
++        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+         include:
+           - os: macos-latest
+-            python-version: "3.13"
++            python-version: "3.x"
+           # - os: windows-latest  # TODO: Fix the Windows test that runs in an infinite loop
+           #   python-version: '3.13'
+     runs-on: ${{ matrix.os }}
+     steps:
+-      - uses: actions/checkout@v4
+-      - uses: actions/setup-python@v5
++      - uses: actions/checkout@v5
++      - uses: actions/setup-python@v6
+         with:
+           python-version: ${{ matrix.python-version }}
+           allow-prereleases: true

+ 25 - 0
debian/patches/cherry-picked/0.4.27-46-g07bd5dd.keep-github-actions-up-to-date-with-github-s-dependabot.patch

@@ -0,0 +1,25 @@
+Subject: Keep GitHub Actions up to date with GitHub's Dependabot
+Origin: upstream, commit 0.4.27-46-g07bd5dd <https://github.com/ahupp/python-magic/commit/0.4.27-46-g07bd5dd>
+Author: Christian Clauss <cclauss@me.com>
+Date: Wed Sep 24 14:18:52 2025 +0200
+
+    * [Keeping your software supply chain secure with Dependabot](https://docs.github.com/en/code-security/dependabot)
+    * [Keeping your actions up to date with Dependabot](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot)
+    * [Configuration options for the `dependabot.yml` file - package-ecosystem](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem)
+
+--- /dev/null
++++ b/.github/dependabot.yml
+@@ -0,0 +1,13 @@
++# Keep GitHub Actions up to date with GitHub's Dependabot...
++# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
++# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
++version: 2
++updates:
++  - package-ecosystem: github-actions
++    directory: /
++    groups:
++      github-actions:
++        patterns:
++          - "*"  # Group all Actions updates into a single larger pull request
++    schedule:
++      interval: weekly

+ 35 - 0
debian/patches/cherry-picked/0.4.27-47-g5cffa79.bump-actions-checkout-from-5-to-6-in-the-github-actions-group.patch

@@ -0,0 +1,35 @@
+Subject: Bump actions/checkout from 5 to 6 in the github-actions group
+Origin: upstream, commit 0.4.27-47-g5cffa79 <https://github.com/ahupp/python-magic/commit/0.4.27-47-g5cffa79>
+Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
+Date: Mon Nov 24 14:26:19 2025 +0000
+
+    Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).
+
+
+    Updates `actions/checkout` from 5 to 6
+    - [Release notes](https://github.com/actions/checkout/releases)
+    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
+    - [Commits](https://github.com/actions/checkout/compare/v5...v6)
+
+    ---
+    updated-dependencies:
+    - dependency-name: actions/checkout
+      dependency-version: '6'
+      dependency-type: direct:production
+      update-type: version-update:semver-major
+      dependency-group: github-actions
+    ...
+
+    Signed-off-by: dependabot[bot] <support@github.com>
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -14,7 +14,7 @@
+           #   python-version: '3.13'
+     runs-on: ${{ matrix.os }}
+     steps:
+-      - uses: actions/checkout@v5
++      - uses: actions/checkout@v6
+       - uses: actions/setup-python@v6
+         with:
+           python-version: ${{ matrix.python-version }}

+ 38 - 0
debian/patches/cherry-picked/0.4.27-48-gff3e049.drop-unused-imports.patch

@@ -0,0 +1,38 @@
+Subject: Drop unused imports
+Origin: upstream, commit 0.4.27-48-gff3e049 <https://github.com/ahupp/python-magic/commit/0.4.27-48-gff3e049>
+Author: Semyon Pupkov <mail@semyonpupkov.com>
+Date: Tue Mar 3 10:05:56 2026 +0500
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -18,11 +18,7 @@
+ 
+ import sys
+ import os
+-import glob
+-import ctypes
+-import ctypes.util
+ import threading
+-import logging
+ 
+ from ctypes import c_char_p, c_int, c_size_t, c_void_p, byref, POINTER
+ 
+@@ -252,7 +248,7 @@
+ 
+ libmagic = loader.load_lib()
+ 
+-magic_t = ctypes.c_void_p
++magic_t = c_void_p
+ 
+ 
+ def errorcheck_null(result, func, args):
+--- a/magic/compat.py
++++ b/magic/compat.py
+@@ -8,7 +8,6 @@
+ from collections import namedtuple
+ 
+ from ctypes import *
+-from ctypes.util import find_library
+ 
+ from . import loader
+ 

+ 35 - 0
debian/patches/cherry-picked/0.4.27-49-ga1fad43.fix-test-for-apache-parquet-files-for-file-5-47.patch

@@ -0,0 +1,35 @@
+Subject: Fix test for Apache Parquet files for file 5.47
+Origin: upstream, commit 0.4.27-49-ga1fad43 <https://github.com/ahupp/python-magic/commit/0.4.27-49-ga1fad43>
+Author: Adam Thompson-Sharpe <adamthompsonsharpe@gmail.com>
+Date: Wed May 6 12:15:43 2026 -0400
+
+    The output for Parquet files changed in 5.47. This commit edits the test
+    to accept both the old and new output.
+
+    ```sh
+    # Old
+    $ file example.parquet
+    example.parquet: Apache Parquet
+    $ file --mime example.parquet
+    example.parquet: application/octet-stream; charset=binary
+
+    # New
+    $ file example.parquet
+    example.parquet: Apache Parquet file
+    $ file --mime example.parquet
+    example.parquet: application/vnd.apache.parquet; charset=binary
+    ```
+
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -89,8 +89,8 @@
+         (NO_SOFT, ["data"]),
+     ],
+     b"test.snappy.parquet": [
+-        (COMMON_MIME, ["application/octet-stream"]),
+-        (COMMON_PLAIN, ["Apache Parquet", "Par archive data"]),
++        (COMMON_MIME, ["application/octet-stream", "application/vnd.apache.parquet"]),
++        (COMMON_PLAIN, ["Apache Parquet", "Apache Parquet file", "Par archive data"]),
+         (NO_SOFT, ["data"]),
+     ],
+     b"test.json": [

+ 37 - 0
debian/patches/cherry-picked/0.4.27-5-gcd3929f.added-path-for-local-homebrew-installation-267.patch

@@ -0,0 +1,37 @@
+Subject: Added path for local homebrew installation (#267)
+Origin: upstream, commit 0.4.27-5-gcd3929f <https://github.com/ahupp/python-magic/commit/0.4.27-5-gcd3929f>
+Author: Manuele <57706020+manvento@users.noreply.github.com>
+Date: Mon Oct 24 17:42:37 2022 +0200
+
+    * added path for local homebrew installation
+    * used brew --prefix to detect local path
+
+--- a/magic/loader.py
++++ b/magic/loader.py
+@@ -3,6 +3,7 @@
+ import sys
+ import glob
+ import os.path
++import subprocess
+ 
+ def _lib_candidates():
+ 
+@@ -13,8 +14,16 @@
+     paths = [
+       '/opt/local/lib',
+       '/usr/local/lib',
+-      '/opt/homebrew/lib',
+-    ] + glob.glob('/usr/local/Cellar/libmagic/*/lib')
++      '/opt/homebrew/lib'
++    ]
++
++    try:
++      local_brew_path = subprocess.check_output(['brew', '--prefix']).decode('UTF-8')
++      paths.append(f'{local_brew_path.strip()}/lib')
++    except:
++      pass
++
++    paths += glob.glob('/usr/local/Cellar/libmagic/*/lib')
+ 
+     for i in paths:
+       yield os.path.join(i, 'libmagic.dylib')

+ 28 - 0
debian/patches/cherry-picked/0.4.27-50-g71301b0.add-python-3-14-to-ci.patch

@@ -0,0 +1,28 @@
+Subject: Add python 3.14 to CI
+Origin: upstream, commit 0.4.27-50-g71301b0 <https://github.com/ahupp/python-magic/commit/0.4.27-50-g71301b0>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Tue Oct 14 14:09:18 2025 +0300
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -6,7 +6,7 @@
+       fail-fast: false
+       matrix:
+         os: ["ubuntu-latest"]
+-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
++        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.13t", "3.14", "3.14t"]
+         include:
+           - os: macos-latest
+             python-version: "3.x"
+--- a/tox.ini
++++ b/tox.ini
+@@ -10,6 +10,9 @@
+     py311,
+     py312,
+     py313,
++    py313t,
++    py314,
++    py314t,
+     mypy
+ 
+ [testenv]

+ 152 - 0
debian/patches/cherry-picked/0.4.27-51-g8e7d98e.move-lock-to-global-scope.patch

@@ -0,0 +1,152 @@
+Subject: Move lock to global scope
+Origin: upstream, commit 0.4.27-51-g8e7d98e <https://github.com/ahupp/python-magic/commit/0.4.27-51-g8e7d98e>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Tue Oct 14 14:23:53 2025 +0300
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -105,7 +105,6 @@
+             self.flags |= MAGIC_NO_CHECK_SIMH
+ 
+         self.cookie = magic_open(self.flags)
+-        self.lock = threading.Lock()
+ 
+         magic_load(self.cookie, magic_file)
+ 
+@@ -134,34 +133,31 @@
+         """
+         Identify the contents of `buf`
+         """
+-        with self.lock:
+-            try:
+-                # if we're on python3, convert buf to bytes
+-                # otherwise this string is passed as wchar*
+-                # which is not what libmagic expects
+-                # NEXTBREAK: only take bytes
+-                if type(buf) == str and str != bytes:
+-                    buf = buf.encode("utf-8", errors="replace")
+-                return maybe_decode(magic_buffer(self.cookie, buf))
+-            except MagicException as e:
+-                return self._handle509Bug(e)
++        try:
++            # if we're on python3, convert buf to bytes
++            # otherwise this string is passed as wchar*
++            # which is not what libmagic expects
++            # NEXTBREAK: only take bytes
++            if type(buf) == str and str != bytes:
++                buf = buf.encode("utf-8", errors="replace")
++            return maybe_decode(magic_buffer(self.cookie, buf))
++        except MagicException as e:
++            return self._handle509Bug(e)
+ 
+     def from_file(self, filename):
+         # raise FileNotFoundException or IOError if the file does not exist
+         os.stat(filename, follow_symlinks=self.flags & MAGIC_SYMLINK)
+ 
+-        with self.lock:
+-            try:
+-                return maybe_decode(magic_file(self.cookie, filename))
+-            except MagicException as e:
+-                return self._handle509Bug(e)
++        try:
++            return maybe_decode(magic_file(self.cookie, filename))
++        except MagicException as e:
++            return self._handle509Bug(e)
+ 
+     def from_descriptor(self, fd):
+-        with self.lock:
+-            try:
+-                return maybe_decode(magic_descriptor(self.cookie, fd))
+-            except MagicException as e:
+-                return self._handle509Bug(e)
++        try:
++            return maybe_decode(magic_descriptor(self.cookie, fd))
++        except MagicException as e:
++            return self._handle509Bug(e)
+ 
+     def _handle509Bug(self, e):
+         # libmagic 5.09 has a bug where it might fail to identify the
+@@ -313,6 +309,9 @@
+         return filename
+ 
+ 
++# libmagic is not thread-safe: guard for concurrent calls on a global scope
++LOCK = threading.Lock()
++
+ magic_open = libmagic.magic_open
+ magic_open.restype = magic_t
+ magic_open.argtypes = [c_int]
+@@ -336,7 +335,8 @@
+ 
+ 
+ def magic_file(cookie, filename):
+-    return _magic_file(cookie, coerce_filename(filename))
++    with LOCK:
++        return _magic_file(cookie, coerce_filename(filename))
+ 
+ 
+ _magic_buffer = libmagic.magic_buffer
+@@ -346,7 +346,8 @@
+ 
+ 
+ def magic_buffer(cookie, buf):
+-    return _magic_buffer(cookie, buf, len(buf))
++    with LOCK:
++        return _magic_buffer(cookie, buf, len(buf))
+ 
+ 
+ magic_descriptor = libmagic.magic_descriptor
+@@ -361,7 +362,8 @@
+ 
+ 
+ def magic_descriptor(cookie, fd):
+-    return _magic_descriptor(cookie, fd)
++    with LOCK:
++        return _magic_descriptor(cookie, fd)
+ 
+ 
+ _magic_load = libmagic.magic_load
+@@ -371,7 +373,8 @@
+ 
+ 
+ def magic_load(cookie, filename):
+-    return _magic_load(cookie, coerce_filename(filename))
++    with LOCK:
++        return _magic_load(cookie, coerce_filename(filename))
+ 
+ 
+ magic_setflags = libmagic.magic_setflags
+@@ -404,15 +407,16 @@
+     if not _has_param:
+         raise NotImplementedError("magic_setparam not implemented")
+     v = c_size_t(val)
+-    return _magic_setparam(cookie, param, byref(v))
++    with LOCK:
++        return _magic_setparam(cookie, param, byref(v))
+ 
+ 
+ def magic_getparam(cookie, param):
+     if not _has_param:
+         raise NotImplementedError("magic_getparam not implemented")
+     val = c_size_t()
+-    _magic_getparam(cookie, param, byref(val))
+-    return val.value
++    with LOCK:
++        return _magic_getparam(cookie, param, byref(val)).value
+ 
+ 
+ _has_version = False
+@@ -423,10 +427,11 @@
+     magic_version.argtypes = []
+ 
+ 
+-def version():
++def version(lock=None):
+     if not _has_version:
+         raise NotImplementedError("magic_version not implemented")
+-    return magic_version()
++    with LOCK:
++        return magic_version()
+ 
+ 
+ MAGIC_NONE = 0x000000  # No flags

+ 67 - 0
debian/patches/cherry-picked/0.4.27-52-g892543d.add-test.patch

@@ -0,0 +1,67 @@
+Subject: Add test
+Origin: upstream, commit 0.4.27-52-g892543d <https://github.com/ahupp/python-magic/commit/0.4.27-52-g892543d>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Tue Oct 14 14:39:45 2025 +0300
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -416,7 +416,8 @@
+         raise NotImplementedError("magic_getparam not implemented")
+     val = c_size_t()
+     with LOCK:
+-        return _magic_getparam(cookie, param, byref(val)).value
++        _magic_getparam(cookie, param, byref(val))
++    return val.value
+ 
+ 
+ _has_version = False
+@@ -427,7 +428,7 @@
+     magic_version.argtypes = []
+ 
+ 
+-def version(lock=None):
++def version():
+     if not _has_version:
+         raise NotImplementedError("magic_version not implemented")
+     with LOCK:
+--- a/test/python_magic_test.py
++++ b/test/python_magic_test.py
+@@ -10,6 +10,12 @@
+ 
+ import pytest
+ 
++try:
++    from concurrent.futures import ThreadPoolExecutor
++    HAS_CONCURRENT_FUTURES = True
++except ImportError:  # python 2.7
++    HAS_CONCURRENT_FUTURES = False
++
+ # for output which reports a local time
+ os.environ["TZ"] = "GMT"
+ 
+@@ -321,6 +327,25 @@
+ 
+             self.assertRaises(IOError, m_follow.from_file, tmp_broken)
+ 
++    @unittest.skipIf(not HAS_CONCURRENT_FUTURES, "concurrent.futures not available in Python 2.7")
++    def test_thread_safety(self):
++        """Test that concurrent from_file calls don't crash (would SEGV without global lock)"""
++        filename = os.path.join(self.TESTDATA_DIR, "test.pdf")
++
++        m = magic.Magic(mime=True)
++
++        def check_file(_):
++            result = m.from_file(filename)
++            self.assertEqual(result, "application/pdf")
++            return result
++
++        with ThreadPoolExecutor(100) as executor:
++            results = list(executor.map(check_file, range(100)))
++
++        # All calls should complete successfully
++        self.assertEqual(len(results), 100)
++        self.assertTrue(all(r == "application/pdf" for r in results))
++
+ 
+ if __name__ == "__main__":
+     unittest.main()

+ 26 - 0
debian/patches/cherry-picked/0.4.27-53-gf3cef27.apply-suggestions-from-code-review.patch

@@ -0,0 +1,26 @@
+Subject: Apply suggestions from code review
+Origin: upstream, commit 0.4.27-53-gf3cef27 <https://github.com/ahupp/python-magic/commit/0.4.27-53-gf3cef27>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Tue Oct 14 13:44:09 2025 +0200
+
+--- a/.github/workflows/ci.yml
++++ b/.github/workflows/ci.yml
+@@ -6,7 +6,7 @@
+       fail-fast: false
+       matrix:
+         os: ["ubuntu-latest"]
+-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.13t", "3.14", "3.14t"]
++        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]
+         include:
+           - os: macos-latest
+             python-version: "3.x"
+--- a/tox.ini
++++ b/tox.ini
+@@ -10,7 +10,6 @@
+     py311,
+     py312,
+     py313,
+-    py313t,
+     py314,
+     py314t,
+     mypy

+ 150 - 0
debian/patches/cherry-picked/0.4.27-54-g4043553.revert-move-lock-to-global-scope.patch

@@ -0,0 +1,150 @@
+Subject: Revert "Move lock to global scope"
+Origin: upstream, commit 0.4.27-54-g4043553 <https://github.com/ahupp/python-magic/commit/0.4.27-54-g4043553>
+Author: ddelange <14880945+ddelange@users.noreply.github.com>
+Date: Fri Oct 17 20:04:26 2025 +0300
+Bug-Debian: https://bugs.debian.org/4043553
+
+    This reverts commit f2ac98d8aa7464165984068de9e484d0321cd4f3.
+
+--- a/magic/__init__.py
++++ b/magic/__init__.py
+@@ -105,6 +105,7 @@
+             self.flags |= MAGIC_NO_CHECK_SIMH
+ 
+         self.cookie = magic_open(self.flags)
++        self.lock = threading.Lock()
+ 
+         magic_load(self.cookie, magic_file)
+ 
+@@ -133,31 +134,34 @@
+         """
+         Identify the contents of `buf`
+         """
+-        try:
+-            # if we're on python3, convert buf to bytes
+-            # otherwise this string is passed as wchar*
+-            # which is not what libmagic expects
+-            # NEXTBREAK: only take bytes
+-            if type(buf) == str and str != bytes:
+-                buf = buf.encode("utf-8", errors="replace")
+-            return maybe_decode(magic_buffer(self.cookie, buf))
+-        except MagicException as e:
+-            return self._handle509Bug(e)
++        with self.lock:
++            try:
++                # if we're on python3, convert buf to bytes
++                # otherwise this string is passed as wchar*
++                # which is not what libmagic expects
++                # NEXTBREAK: only take bytes
++                if type(buf) == str and str != bytes:
++                    buf = buf.encode("utf-8", errors="replace")
++                return maybe_decode(magic_buffer(self.cookie, buf))
++            except MagicException as e:
++                return self._handle509Bug(e)
+ 
+     def from_file(self, filename):
+         # raise FileNotFoundException or IOError if the file does not exist
+         os.stat(filename, follow_symlinks=self.flags & MAGIC_SYMLINK)
+ 
+-        try:
+-            return maybe_decode(magic_file(self.cookie, filename))
+-        except MagicException as e:
+-            return self._handle509Bug(e)
++        with self.lock:
++            try:
++                return maybe_decode(magic_file(self.cookie, filename))
++            except MagicException as e:
++                return self._handle509Bug(e)
+ 
+     def from_descriptor(self, fd):
+-        try:
+-            return maybe_decode(magic_descriptor(self.cookie, fd))
+-        except MagicException as e:
+-            return self._handle509Bug(e)
++        with self.lock:
++            try:
++                return maybe_decode(magic_descriptor(self.cookie, fd))
++            except MagicException as e:
++                return self._handle509Bug(e)
+ 
+     def _handle509Bug(self, e):
+         # libmagic 5.09 has a bug where it might fail to identify the
+@@ -309,9 +313,6 @@
+         return filename
+ 
+ 
+-# libmagic is not thread-safe: guard for concurrent calls on a global scope
+-LOCK = threading.Lock()
+-
+ magic_open = libmagic.magic_open
+ magic_open.restype = magic_t
+ magic_open.argtypes = [c_int]
+@@ -335,8 +336,7 @@
+ 
+ 
+ def magic_file(cookie, filename):
+-    with LOCK:
+-        return _magic_file(cookie, coerce_filename(filename))
++    return _magic_file(cookie, coerce_filename(filename))
+ 
+ 
+ _magic_buffer = libmagic.magic_buffer
+@@ -346,8 +346,7 @@
+ 
+ 
+ def magic_buffer(cookie, buf):
+-    with LOCK:
+-        return _magic_buffer(cookie, buf, len(buf))
++    return _magic_buffer(cookie, buf, len(buf))
+ 
+ 
+ magic_descriptor = libmagic.magic_descriptor
+@@ -362,8 +361,7 @@
+ 
+ 
+ def magic_descriptor(cookie, fd):
+-    with LOCK:
+-        return _magic_descriptor(cookie, fd)
++    return _magic_descriptor(cookie, fd)
+ 
+ 
+ _magic_load = libmagic.magic_load
+@@ -373,8 +371,7 @@
+ 
+ 
+ def magic_load(cookie, filename):
+-    with LOCK:
+-        return _magic_load(cookie, coerce_filename(filename))
++    return _magic_load(cookie, coerce_filename(filename))
+ 
+ 
+ magic_setflags = libmagic.magic_setflags
+@@ -407,16 +404,14 @@
+     if not _has_param:
+         raise NotImplementedError("magic_setparam not implemented")
+     v = c_size_t(val)
+-    with LOCK:
+-        return _magic_setparam(cookie, param, byref(v))
++    return _magic_setparam(cookie, param, byref(v))
+ 
+ 
+ def magic_getparam(cookie, param):
+     if not _has_param:
+         raise NotImplementedError("magic_getparam not implemented")
+     val = c_size_t()
+-    with LOCK:
+-        _magic_getparam(cookie, param, byref(val))
++    _magic_getparam(cookie, param, byref(val))
+     return val.value
+ 
+ 
+@@ -431,8 +426,7 @@
+ def version():
+     if not _has_version:
+         raise NotImplementedError("magic_version not implemented")
+-    with LOCK:
+-        return magic_version()
++    return magic_version()
+ 
+ 
+ MAGIC_NONE = 0x000000  # No flags

+ 27 - 0
debian/patches/cherry-picked/0.4.27-6-gea2150d.add-python-3-10-to-tox-environment-list.patch

@@ -0,0 +1,27 @@
+Subject: Add python 3.10 to tox environment list
+Origin: upstream, commit 0.4.27-6-gea2150d <https://github.com/ahupp/python-magic/commit/0.4.27-6-gea2150d>
+Author: Adam Hupp <adam@hupp.org>
+Date: Mon Oct 24 08:11:21 2022 -0700
+
+--- a/tox.ini
++++ b/tox.ini
+@@ -7,16 +7,17 @@
+     py37,
+     py38,
+     py39,
++    py310,
+     coverage-report,
+     mypy
+ 
+ [testenv]
+ commands =
+-    coverage run -m pytest 
++    coverage run -m pytest
+ 
+ setenv =
+   COVERAGE_FILE=.coverage.{envname}
+-  LC_ALL=en_US.UTF-8   
++  LC_ALL=en_US.UTF-8
+ deps =
+     .[test]
+     coverage

+ 38 - 0
debian/patches/cherry-picked/0.4.27-7-g05fde96.further-update-readme-for-test-running-changes.patch

@@ -0,0 +1,38 @@
+Subject: Further update README for test running changes
+Origin: upstream, commit 0.4.27-7-g05fde96 <https://github.com/ahupp/python-magic/commit/0.4.27-7-g05fde96>
+Author: Adam Hupp <adam@hupp.org>
+Date: Mon Oct 24 08:19:55 2022 -0700
+
+--- a/README.md
++++ b/README.md
+@@ -101,22 +101,23 @@
+ 
+ ## Running the tests
+ 
+-To run the tests across a variety of linux distributions (depends on Docker):
++We use the `tox` test runner which can be installed with `python -m pip install tox`.
++
++To run tests locally across all available python versions:
+ 
+ ```
+-./test_docker.sh
++python -m tox
+ ```
+ 
+-To run tests locally across all available python versions:
++Or to run just against a single version:
+ 
+ ```
+-./test/run.py
++python -m tox py
+ ```
+-
+-To run against a specific python version:
++To run the tests across a variety of linux distributions (depends on Docker):
+ 
+ ```
+-LC_ALL=en_US.UTF-8 python3 test/python_magic_test.py
++./test/run_all_docker_test.sh
+ ```
+ 
+ ## libmagic python API compatibility

+ 110 - 0
debian/patches/cherry-picked/0.4.27-8-g3794a39.docker-test-cleanup.patch

@@ -0,0 +1,110 @@
+Subject: Docker test cleanup
+Origin: upstream, commit 0.4.27-8-g3794a39 <https://github.com/ahupp/python-magic/commit/0.4.27-8-g3794a39>
+Author: Adam Hupp <adam@hupp.org>
+Date: Mon Oct 24 08:20:54 2022 -0700
+
+--- a/test/docker/alpine
++++ b/test/docker/alpine
+@@ -3,5 +3,3 @@
+ WORKDIR /python-magic
+ COPY . .
+ RUN python3 -m pip install tox
+-CMD python3 -m tox
+-
+--- a/test/docker/archlinux
++++ b/test/docker/archlinux
+@@ -1,5 +1,6 @@
+ FROM archlinux:latest
+ RUN yes | pacman -Syyu --overwrite '*'
+-RUN yes | pacman -S python python2 file which
+-COPY . /python-magic
+-CMD cd /python-magic/test && python3 ./run.py
++RUN yes | pacman -S python python-pip file which
++WORKDIR /python-magic
++COPY . .
++RUN python3 -m pip install tox
+--- a/test/docker/bionic
++++ b/test/docker/bionic
+@@ -1,9 +1,8 @@
+ FROM ubuntu:bionic
+-WORKDIR /python-magic
+-COPY . .
+ RUN apt-get update
+ RUN apt-get -y install python python3 locales python3-pip libmagic1
+ RUN locale-gen en_US.UTF-8
+-RUN python3 -m pip install tox
+-CMD python3 -m tox
+ 
++WORKDIR /python-magic
++COPY . .
++RUN python3 -m pip install tox
+--- a/test/docker/centos7
++++ b/test/docker/centos7
+@@ -1,9 +1,8 @@
+ FROM centos:7
+ RUN yum -y update
+ RUN yum -y install file-devel python3 python2 which
++ENV SKIP_FROM_DESCRIPTOR=1
++
+ WORKDIR /python-magic
+ COPY . .
+ RUN python3 -m pip install tox
+-ENV SKIP_FROM_DESCRIPTOR=1 
+-CMD python3 -m tox
+-
+--- a/test/docker/centos8
++++ b/test/docker/centos8
+@@ -4,8 +4,7 @@
+ RUN yum reinstall glibc-common -y && \
+   localedef -i en_US -f UTF-8 en_US.UTF-8 && \
+   echo "LANG=en_US.UTF-8" > /etc/locale.conf
++
+ WORKDIR /python-magic
+ COPY . .
+ RUN python3 -m pip install tox
+-CMD python3 -m tox
+-
+--- a/test/docker/focal
++++ b/test/docker/focal
+@@ -1,9 +1,10 @@
+ FROM ubuntu:focal
+-WORKDIR /python-magic
+-COPY . .
+ RUN apt-get update
+ RUN apt-get -y install python python3 locales python3-pip libmagic1
+ RUN locale-gen en_US.UTF-8
++
++WORKDIR /python-magic
++COPY . .
+ RUN python3 -m pip install tox
+-CMD python3 -m tox
++
+ 
+--- a/test/docker/xenial
++++ b/test/docker/xenial
+@@ -1,9 +1,8 @@
+ FROM ubuntu:xenial
+-WORKDIR /python-magic
+-COPY . .
+ RUN apt-get update
+ RUN apt-get -y install python python3 locales python3-pip libmagic1
+ RUN locale-gen en_US.UTF-8
+-RUN python3 -m pip install tox
+-CMD python3 -m tox
+ 
++WORKDIR /python-magic
++COPY . .
++RUN python3 -m pip install tox
+--- a/test/run_all_docker_test.sh
++++ b/test/run_all_docker_test.sh
+@@ -6,8 +6,8 @@
+ ROOT=$(dirname $0)/..
+ cd $ROOT
+ 
+-for f in test/docker/*; do 
++for f in test/docker/*; do
+     H=$(docker build -q -f ${f} .)
+-    docker run --rm $H
++    docker run --rm $H python3 -m tox
+ done
+ 

+ 12 - 5
debian/patches/2022-12-23.adjust-for-5.43.patch

@@ -1,11 +1,11 @@
-Subject: Adjust for changes in file 5.43+
-Author: Christoph Biedl <debian.axhn@manchmal.in-ulm.de>
-Date: 2022-12-23
-Forwarded: https://github.com/ahupp/python-magic/issues/283
+Subject: Update test for upstream added gzip extensions
+Origin: upstream, commit 0.4.27-9-g4ffcd59 <https://github.com/ahupp/python-magic/commit/0.4.27-9-g4ffcd59>
+Author: Adam Hupp <adam@hupp.org>
+Date: Mon Jan 9 12:55:15 2023 -0800
 
 
 --- a/test/python_magic_test.py
 --- a/test/python_magic_test.py
 +++ b/test/python_magic_test.py
 +++ b/test/python_magic_test.py
-@@ -135,7 +135,7 @@
+@@ -134,7 +134,7 @@
              self.assert_values(m, {
              self.assert_values(m, {
                  # some versions return '' for the extensions of a gz file,
                  # some versions return '' for the extensions of a gz file,
                  # including w/ the command line.  Who knows...
                  # including w/ the command line.  Who knows...
@@ -14,3 +14,10 @@ Forwarded: https://github.com/ahupp/python-magic/issues/283
                  'name_use.jpg': 'jpeg/jpg/jpe/jfif',
                  'name_use.jpg': 'jpeg/jpg/jpe/jfif',
              })
              })
          except NotImplementedError:
          except NotImplementedError:
+@@ -227,6 +227,5 @@
+         m = magic.Magic(mime=True)
+         self.assertEqual('application/pdf', m.from_file(path))
+ 
+-
+ if __name__ == '__main__':
+     unittest.main()

+ 52 - 2
debian/patches/series

@@ -1,7 +1,57 @@
 # cherry-picked from upstream. Keep in chronological order
 # cherry-picked from upstream. Keep in chronological order
-cherry-pick/1690968587.0.4.27-16-g545a2a5.fix-test-suite-with-file-5-45.patch
+cherry-picked/0.4.27-1-gf3ab085.add-magic-1-dll-to-the-list-of-dll-files-to-search-for-on-windows.patch
+cherry-picked/0.4.27-3-gcc0c587.corrected-the-command-for-the-test-for-python3.patch
+cherry-picked/0.4.27-5-gcd3929f.added-path-for-local-homebrew-installation-267.patch
+cherry-picked/0.4.27-6-gea2150d.add-python-3-10-to-tox-environment-list.patch
+cherry-picked/0.4.27-7-g05fde96.further-update-readme-for-test-running-changes.patch
+cherry-picked/0.4.27-8-g3794a39.docker-test-cleanup.patch
+cherry-picked/0.4.27-9-g4ffcd59.update-test-for-upstream-added-gzip-extensions.patch
+cherry-picked/0.4.27-10-gb805925.dont-run-coverage-by-default-in-tox-config.patch
+cherry-picked/0.4.27-11-gc7a2e7b.remove-python3-ism-from-loader.patch
+cherry-picked/0.4.27-12-gc7642f0.chore-tests-add-python-3-10-and-3-11-in-ci-runs-tox-trove-classifier-284.patch
+cherry-picked/0.4.27-13-ge0052c5.bump-to-0-4-28.patch
+cherry-picked/0.4.27-14-g7cde785.revert-remove-python3-ism-from-loader.patch
+cherry-picked/0.4.27-15-g3ab9608.revert-added-path-for-local-homebrew-installation-267.patch
+cherry-picked/0.4.27-16-g545a2a5.fix-test-suite-with-file-5-45.patch
+cherry-picked/0.4.27-17-g0cc3cf8.chore-python-add-python-3-12-in-test-matrix.patch
+cherry-picked/0.4.27-18-g7229954.fix-dont-raise-filenotfoundexception-on-symlinks.patch
+cherry-picked/0.4.27-19-g2a01b18.add-magic-symlink-support-and-tests-for-same.patch
+cherry-picked/0.4.27-20-g64ed0bd.typing-stubs-add-magic-init-extension-follow-symlinks-args.patch
+cherry-picked/0.4.27-21-gfd279e0.magic-init-add-kwargs-to-enable-disable-different-types-of-magic-detection.patch
+cherry-picked/0.4.27-22-g54d86fd.python-magic-tests-add-test-files-for-elf-and-json-use-to-test-flags.patch
+cherry-picked/0.4.27-23-g8eecfb7.travis-ci-test-on-python-3-13-beta.patch
+cherry-picked/0.4.27-24-g7ee4180.delete-travis-yml.patch
+cherry-picked/0.4.27-25-ge578995.github-action-to-replace-travis-ci.patch
+cherry-picked/0.4.27-26-gab1b2a4.update-ci-yml.patch
+cherry-picked/0.4.27-27-gaa49677.update-readme-md.patch
+cherry-picked/0.4.27-28-geae08a3.readme-md-add-a-badge-for-github-actions.patch
+cherry-picked/0.4.27-29-gfc7ebc0.update-readme-md.patch
+cherry-picked/0.4.27-30-g1217005.fix-typos-discovered-by-codespell.patch
+cherry-picked/0.4.27-31-gcf21065.clean-up-loader-py.patch
+cherry-picked/0.4.27-32-g0a2fda3.handle-unknown-platforms-gracefully-in-loader-py.patch
+cherry-picked/0.4.27-33-g4b776d7.rename-no-json-test-to-avoid-duplicate-function-definitions.patch
+cherry-picked/0.4.27-34-g339eac0.smartos-support-adapted-from-132.patch
+cherry-picked/0.4.27-35-ga9e6276.log-warning-on-ctypes-load-error-adapted-from-279.patch
+cherry-picked/0.4.27-36-g067399b.update-readme-md.patch
+cherry-picked/0.4.27-37-g42980e5.simplify-tests-into-something-more-delarative.patch
+cherry-picked/0.4.27-38-g36ecbf9.update-magic-compat-py.patch
+cherry-picked/0.4.27-39-ga3ed086.unbreak-various-things.patch
+cherry-picked/0.4.27-40-g5a89644.add-support-for-python-3-13.patch
+cherry-picked/0.4.27-41-g62bd3c6.format-with-ruff.patch
+cherry-picked/0.4.27-42-gfac6615.small-fix-to-readme-that-makes-pip-install-command-easier-to-see-find.patch
+cherry-picked/0.4.27-43-g8361a33.update-readme-md.patch
+cherry-picked/0.4.27-44-g7cbbc99.update-readme-md.patch
+cherry-picked/0.4.27-45-gf8fb0ee.add-python-3-14-to-the-testing.patch
+cherry-picked/0.4.27-46-g07bd5dd.keep-github-actions-up-to-date-with-github-s-dependabot.patch
+cherry-picked/0.4.27-47-g5cffa79.bump-actions-checkout-from-5-to-6-in-the-github-actions-group.patch
+cherry-picked/0.4.27-48-gff3e049.drop-unused-imports.patch
+cherry-picked/0.4.27-49-ga1fad43.fix-test-for-apache-parquet-files-for-file-5-47.patch
+cherry-picked/0.4.27-50-g71301b0.add-python-3-14-to-ci.patch
+cherry-picked/0.4.27-51-g8e7d98e.move-lock-to-global-scope.patch
+cherry-picked/0.4.27-52-g892543d.add-test.patch
+cherry-picked/0.4.27-53-gf3cef27.apply-suggestions-from-code-review.patch
+cherry-picked/0.4.27-54-g4043553.revert-move-lock-to-global-scope.patch
 
 
 # patches that should go upstream
 # patches that should go upstream
-2022-12-23.adjust-for-5.43.patch
 
 
 # modifications for Debian
 # modifications for Debian

+ 2 - 0
debian/rules

@@ -7,7 +7,9 @@ libmagic_package := $(shell dpkg-query '-f$${Depends}' -W libmagic-dev | awk '{p
 
 
 override_dh_auto_test:
 override_dh_auto_test:
 ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
 ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
+	base64 -d test/testdata/elf-NetBSD-x86_64-echo.gz.b64 | gunzip >test/testdata/elf-NetBSD-x86_64-echo
 	LC_ALL=en_US.UTF-8 $(DH_OVERRIDDEN_COMMAND)
 	LC_ALL=en_US.UTF-8 $(DH_OVERRIDDEN_COMMAND)
+	rm test/testdata/elf-NetBSD-x86_64-echo
 endif
 endif
 
 
 override_dh_gencontrol:
 override_dh_gencontrol:

+ 2 - 0
debian/tests/run-testsuite

@@ -2,5 +2,7 @@
 
 
 set -e
 set -e
 
 
+base64 -d test/testdata/elf-NetBSD-x86_64-echo.gz.b64 | gunzip >test/testdata/elf-NetBSD-x86_64-echo
+
 export LC_ALL=en_US.UTF-8
 export LC_ALL=en_US.UTF-8
 python3 test/python_magic_test.py
 python3 test/python_magic_test.py