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()

```

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):

{"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"}]}