prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  python-magic dependency conflicts with file-magic (official python bindings for libmagic)
  **Describe the bug**
  
  I'm the Lutris packager for Mageia.
  
  Lutris 0.5.8 added a dependency on `python-magic`, which is https://github.com/ahupp/python-magic
  
  `python-magic` provides the `magic.py` module, which conflicts with the official Python bindings for libmagic provided by the `file` package (`python3-file-magic` on Mageia - previously `python3-magic` but I renamed it to make room for the conflicting `python-magic` package).
  
  Long story short, those seem to be two competing implementations for the `magic` module and they can't be installed next to each other. Which means that once packaged in a distro, you can't install packaged software which independently require `file-magic` and `python-magic`.
  Downstream issue (`rpmlint` and `lutris` can't be installed together): https://bugs.mageia.org/show_bug.cgi?id=27619
  
  Upstream issue (8 years old, made some progress 2 years ago but still not resolved): https://github.com/ahupp/python-magic/issues/21
  
  That's an unfortunate upstream issue and not directly related to Lutris but it does make packaging trickier. I'm not sure what the best solution would be here, but it might be worth checking if Lutris could use `python-magic` OR `file-magic`, whichever is installed? This would let distros settle on one fork as the main dependency for their packages.
  
  **Steps to reproduce**
  
  - Try to install a package that depends on `file`'s libmagic Python bindings together with Lutris that requires https://github.com/ahupp/python-magic
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lutris/util/game_finder.py`
  Content:
  ```
  1 """Automatically detects game executables in a folder"""
  2 import os
  3 
  4 from lutris.util import system
  5 from lutris.util.log import logger
  6 
  7 try:
  8     import magic
  9     MAGIC_AVAILABLE = True
  10 except ImportError:
  11     MAGIC_AVAILABLE = False
  12     magic = None
  13 
  14 
  15 if not hasattr(magic, "from_file"):
  16     logger.error("Your version of python-magic is too old.")
  17     MAGIC_AVAILABLE = False
  18 
  19 
  20 def is_excluded_elf(filename):
  21     excluded = (
  22         "xdg-open",
  23         "uninstall"
  24     )
  25     _fn = filename.lower()
  26     for exclude in excluded:
  27         if exclude in _fn:
  28             return True
  29     return False
  30 
  31 
  32 def find_linux_game_executable(path, make_executable=False):
  33     """Looks for a binary or shell script that launches the game in a directory"""
  34     if not MAGIC_AVAILABLE:
  35         logger.warning("Magic not available. Not finding Linux executables")
  36         return ""
  37 
  38     for base, _dirs, files in os.walk(path):
  39         candidates = {}
  40         for _file in files:
  41             if is_excluded_elf(_file):
  42                 continue
  43             abspath = os.path.join(base, _file)
  44             file_type = magic.from_file(abspath)
  45             if "ASCII text executable" in file_type:
  46                 candidates["shell"] = abspath
  47             if "Bourne-Again shell script" in file_type:
  48                 candidates["bash"] = abspath
  49             if "64-bit LSB executable" in file_type:
  50                 candidates["64bit"] = abspath
  51             if "32-bit LSB executable" in file_type:
  52                 candidates["32bit"] = abspath
  53         if candidates:
  54             if make_executable:
  55                 for file_type in candidates:
  56                     system.make_executable(candidates[file_type])
  57             return (
  58                 candidates.get("shell")
  59                 or candidates.get("bash")
  60                 or candidates.get("64bit")
  61                 or candidates.get("32bit")
  62             )
  63     logger.error("Couldn't find a Linux executable in %s", path)
  64     return ""
  65 
  66 
  67 def is_excluded_dir(path):
  68     excluded = (
  69         "Internet Explorer",
  70         "Windows NT",
  71         "Common Files",
  72         "Windows Media Player",
  73         "windows",
  74         "ProgramData",
  75         "users",
  76         "GameSpy Arcade"
  77     )
  78     skip = False
  79     for dir_name in path.split("/"):
  80         if dir_name in excluded:
  81             skip = True
  82     return skip
  83 
  84 
  85 def is_excluded_exe(filename):
  86     excluded = (
  87         "unins000",
  88         "uninstal",
  89         "update",
  90         "config.exe",
  91         "gsarcade.exe",
  92         "dosbox.exe",
  93     )
  94     _fn = filename.lower()
  95     for exclude in excluded:
  96         if exclude in _fn:
  97             return True
  98     return False
  99 
  100 
  101 def find_windows_game_executable(path):
  102     if not MAGIC_AVAILABLE:
  103         logger.warning("Magic not available. Not finding Windows executables")
  104         return ""
  105 
  106     for base, _dirs, files in os.walk(path):
  107         candidates = {}
  108         if is_excluded_dir(base):
  109             continue
  110         for _file in files:
  111             if is_excluded_exe(_file):
  112                 continue
  113             abspath = os.path.join(base, _file)
  114             if os.path.islink(abspath):
  115                 continue
  116             file_type = magic.from_file(abspath)
  117             if "MS Windows shortcut" in file_type:
  118                 candidates["link"] = abspath
  119             elif "PE32+ executable (GUI) x86-64" in file_type:
  120                 candidates["64bit"] = abspath
  121             elif "PE32 executable (GUI) Intel 80386" in file_type:
  122                 candidates["32bit"] = abspath
  123         if candidates:
  124             return (
  125                 candidates.get("link")
  126                 or candidates.get("64bit")
  127                 or candidates.get("32bit")
  128             )
  129     logger.error("Couldn't find a Windows executable in %s", path)
  130     return ""
  131
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/lutris/util/game_finder.py b/lutris/util/game_finder.py
  --- a/lutris/util/game_finder.py
  +++ b/lutris/util/game_finder.py
  @@ -13,8 +13,12 @@
   
   
   if not hasattr(magic, "from_file"):
  -    logger.error("Your version of python-magic is too old.")
  -    MAGIC_AVAILABLE = False
  +    if hasattr(magic, "detect_from_filename"):
  +        magic.from_file = magic.detect_from_filename
  +        MAGIC_AVAILABLE = True
  +    else:
  +        logger.error("Your version of python-magic is too old.")
  +        MAGIC_AVAILABLE = False
   
   
   def is_excluded_elf(filename):
  
verification_info: {"golden_diff": "diff --git a/lutris/util/game_finder.py b/lutris/util/game_finder.py\n--- a/lutris/util/game_finder.py\n+++ b/lutris/util/game_finder.py\n@@ -13,8 +13,12 @@\n \n \n if not hasattr(magic, \"from_file\"):\n-    logger.error(\"Your version of python-magic is too old.\")\n-    MAGIC_AVAILABLE = False\n+    if hasattr(magic, \"detect_from_filename\"):\n+        magic.from_file = magic.detect_from_filename\n+        MAGIC_AVAILABLE = True\n+    else:\n+        logger.error(\"Your version of python-magic is too old.\")\n+        MAGIC_AVAILABLE = False\n \n \n def is_excluded_elf(filename):\n", "issue": "python-magic dependency conflicts with file-magic (official python bindings for libmagic)\n**Describe the bug**\r\n\r\nI'm the Lutris packager for Mageia.\r\n\r\nLutris 0.5.8 added a dependency on `python-magic`, which is https://github.com/ahupp/python-magic\r\n\r\n`python-magic` provides the `magic.py` module, which conflicts with the official Python bindings for libmagic provided by the `file` package (`python3-file-magic` on Mageia - previously `python3-magic` but I renamed it to make room for the conflicting `python-magic` package).\r\n\r\nLong story short, those seem to be two competing implementations for the `magic` module and they can't be installed next to each other. Which means that once packaged in a distro, you can't install packaged software which independently require `file-magic` and `python-magic`.\r\nDownstream issue (`rpmlint` and `lutris` can't be installed together): https://bugs.mageia.org/show_bug.cgi?id=27619\r\n\r\nUpstream issue (8 years old, made some progress 2 years ago but still not resolved): https://github.com/ahupp/python-magic/issues/21\r\n\r\nThat's an unfortunate upstream issue and not directly related to Lutris but it does make packaging trickier. I'm not sure what the best solution would be here, but it might be worth checking if Lutris could use `python-magic` OR `file-magic`, whichever is installed? This would let distros settle on one fork as the main dependency for their packages.\r\n\r\n**Steps to reproduce**\r\n\r\n- Try to install a package that depends on `file`'s libmagic Python bindings together with Lutris that requires https://github.com/ahupp/python-magic\n", "before_files": [{"content": "\"\"\"Automatically detects game executables in a folder\"\"\"\nimport os\n\nfrom lutris.util import system\nfrom lutris.util.log import logger\n\ntry:\n    import magic\n    MAGIC_AVAILABLE = True\nexcept ImportError:\n    MAGIC_AVAILABLE = False\n    magic = None\n\n\nif not hasattr(magic, \"from_file\"):\n    logger.error(\"Your version of python-magic is too old.\")\n    MAGIC_AVAILABLE = False\n\n\ndef is_excluded_elf(filename):\n    excluded = (\n        \"xdg-open\",\n        \"uninstall\"\n    )\n    _fn = filename.lower()\n    for exclude in excluded:\n        if exclude in _fn:\n            return True\n    return False\n\n\ndef find_linux_game_executable(path, make_executable=False):\n    \"\"\"Looks for a binary or shell script that launches the game in a directory\"\"\"\n    if not MAGIC_AVAILABLE:\n        logger.warning(\"Magic not available. Not finding Linux executables\")\n        return \"\"\n\n    for base, _dirs, files in os.walk(path):\n        candidates = {}\n        for _file in files:\n            if is_excluded_elf(_file):\n                continue\n            abspath = os.path.join(base, _file)\n            file_type = magic.from_file(abspath)\n            if \"ASCII text executable\" in file_type:\n                candidates[\"shell\"] = abspath\n            if \"Bourne-Again shell script\" in file_type:\n                candidates[\"bash\"] = abspath\n            if \"64-bit LSB executable\" in file_type:\n                candidates[\"64bit\"] = abspath\n            if \"32-bit LSB executable\" in file_type:\n                candidates[\"32bit\"] = abspath\n        if candidates:\n            if make_executable:\n                for file_type in candidates:\n                    system.make_executable(candidates[file_type])\n            return (\n                candidates.get(\"shell\")\n                or candidates.get(\"bash\")\n                or candidates.get(\"64bit\")\n                or candidates.get(\"32bit\")\n            )\n    logger.error(\"Couldn't find a Linux executable in %s\", path)\n    return \"\"\n\n\ndef is_excluded_dir(path):\n    excluded = (\n        \"Internet Explorer\",\n        \"Windows NT\",\n        \"Common Files\",\n        \"Windows Media Player\",\n        \"windows\",\n        \"ProgramData\",\n        \"users\",\n        \"GameSpy Arcade\"\n    )\n    skip = False\n    for dir_name in path.split(\"/\"):\n        if dir_name in excluded:\n            skip = True\n    return skip\n\n\ndef is_excluded_exe(filename):\n    excluded = (\n        \"unins000\",\n        \"uninstal\",\n        \"update\",\n        \"config.exe\",\n        \"gsarcade.exe\",\n        \"dosbox.exe\",\n    )\n    _fn = filename.lower()\n    for exclude in excluded:\n        if exclude in _fn:\n            return True\n    return False\n\n\ndef find_windows_game_executable(path):\n    if not MAGIC_AVAILABLE:\n        logger.warning(\"Magic not available. Not finding Windows executables\")\n        return \"\"\n\n    for base, _dirs, files in os.walk(path):\n        candidates = {}\n        if is_excluded_dir(base):\n            continue\n        for _file in files:\n            if is_excluded_exe(_file):\n                continue\n            abspath = os.path.join(base, _file)\n            if os.path.islink(abspath):\n                continue\n            file_type = magic.from_file(abspath)\n            if \"MS Windows shortcut\" in file_type:\n                candidates[\"link\"] = abspath\n            elif \"PE32+ executable (GUI) x86-64\" in file_type:\n                candidates[\"64bit\"] = abspath\n            elif \"PE32 executable (GUI) Intel 80386\" in file_type:\n                candidates[\"32bit\"] = abspath\n        if candidates:\n            return (\n                candidates.get(\"link\")\n                or candidates.get(\"64bit\")\n                or candidates.get(\"32bit\")\n            )\n    logger.error(\"Couldn't find a Windows executable in %s\", path)\n    return \"\"\n", "path": "lutris/util/game_finder.py"}], "after_files": [{"content": "\"\"\"Automatically detects game executables in a folder\"\"\"\nimport os\n\nfrom lutris.util import system\nfrom lutris.util.log import logger\n\ntry:\n    import magic\n    MAGIC_AVAILABLE = True\nexcept ImportError:\n    MAGIC_AVAILABLE = False\n    magic = None\n\n\nif not hasattr(magic, \"from_file\"):\n    if hasattr(magic, \"detect_from_filename\"):\n        magic.from_file = magic.detect_from_filename\n        MAGIC_AVAILABLE = True\n    else:\n        logger.error(\"Your version of python-magic is too old.\")\n        MAGIC_AVAILABLE = False\n\n\ndef is_excluded_elf(filename):\n    excluded = (\n        \"xdg-open\",\n        \"uninstall\"\n    )\n    _fn = filename.lower()\n    for exclude in excluded:\n        if exclude in _fn:\n            return True\n    return False\n\n\ndef find_linux_game_executable(path, make_executable=False):\n    \"\"\"Looks for a binary or shell script that launches the game in a directory\"\"\"\n    if not MAGIC_AVAILABLE:\n        logger.warning(\"Magic not available. Not finding Linux executables\")\n        return \"\"\n\n    for base, _dirs, files in os.walk(path):\n        candidates = {}\n        for _file in files:\n            if is_excluded_elf(_file):\n                continue\n            abspath = os.path.join(base, _file)\n            file_type = magic.from_file(abspath)\n            if \"ASCII text executable\" in file_type:\n                candidates[\"shell\"] = abspath\n            if \"Bourne-Again shell script\" in file_type:\n                candidates[\"bash\"] = abspath\n            if \"64-bit LSB executable\" in file_type:\n                candidates[\"64bit\"] = abspath\n            if \"32-bit LSB executable\" in file_type:\n                candidates[\"32bit\"] = abspath\n        if candidates:\n            if make_executable:\n                for file_type in candidates:\n                    system.make_executable(candidates[file_type])\n            return (\n                candidates.get(\"shell\")\n                or candidates.get(\"bash\")\n                or candidates.get(\"64bit\")\n                or candidates.get(\"32bit\")\n            )\n    logger.error(\"Couldn't find a Linux executable in %s\", path)\n    return \"\"\n\n\ndef is_excluded_dir(path):\n    excluded = (\n        \"Internet Explorer\",\n        \"Windows NT\",\n        \"Common Files\",\n        \"Windows Media Player\",\n        \"windows\",\n        \"ProgramData\",\n        \"users\",\n        \"GameSpy Arcade\"\n    )\n    skip = False\n    for dir_name in path.split(\"/\"):\n        if dir_name in excluded:\n            skip = True\n    return skip\n\n\ndef is_excluded_exe(filename):\n    excluded = (\n        \"unins000\",\n        \"uninstal\",\n        \"update\",\n        \"config.exe\",\n        \"gsarcade.exe\",\n        \"dosbox.exe\",\n    )\n    _fn = filename.lower()\n    for exclude in excluded:\n        if exclude in _fn:\n            return True\n    return False\n\n\ndef find_windows_game_executable(path):\n    if not MAGIC_AVAILABLE:\n        logger.warning(\"Magic not available. Not finding Windows executables\")\n        return \"\"\n\n    for base, _dirs, files in os.walk(path):\n        candidates = {}\n        if is_excluded_dir(base):\n            continue\n        for _file in files:\n            if is_excluded_exe(_file):\n                continue\n            abspath = os.path.join(base, _file)\n            if os.path.islink(abspath):\n                continue\n            file_type = magic.from_file(abspath)\n            if \"MS Windows shortcut\" in file_type:\n                candidates[\"link\"] = abspath\n            elif \"PE32+ executable (GUI) x86-64\" in file_type:\n                candidates[\"64bit\"] = abspath\n            elif \"PE32 executable (GUI) Intel 80386\" in file_type:\n                candidates[\"32bit\"] = abspath\n        if candidates:\n            return (\n                candidates.get(\"link\")\n                or candidates.get(\"64bit\")\n                or candidates.get(\"32bit\")\n            )\n    logger.error(\"Couldn't find a Windows executable in %s\", path)\n    return \"\"\n", "path": "lutris/util/game_finder.py"}]}