We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Dependencies on non pure Python modules
Hi,

Sorry for [x-posting](https://discuss.flexget.com/t/dependencies-on-non-pure-python-modules/5086). This is kind of a development issue so it might fit here better than in the forum. Feel free to just close this and reply on Discourse.

When upgrading Flexget I stumbled upon the fact that now it depends on Pillow, as per:

https://github.com/Flexget/Flexget/pull/2621

My Flexget runs on an embedded aarch64 device so every time you add a dep on a module that links against C libraries (Pillow depends on zlib and libjpeg) I have to cross compile the necessary native extensions, distribute them etc. Either that or manually installing a skimmed `requirements.txt` and finally installing Flexget passing `--no-dependencies` to `pip install`.

Does adding a tray icon justify this hassle for users? No saying that’s wrong of course, just trying to bring to your attention this use case and the potential annoyance for users.

Could perhaps these things be made optional at install/build time by relaxing the hard dependency?

Thanks.
Dependencies on non pure Python modules
Hi,

Sorry for [x-posting](https://discuss.flexget.com/t/dependencies-on-non-pure-python-modules/5086). This is kind of a development issue so it might fit here better than in the forum. Feel free to just close this and reply on Discourse.

When upgrading Flexget I stumbled upon the fact that now it depends on Pillow, as per:

https://github.com/Flexget/Flexget/pull/2621

My Flexget runs on an embedded aarch64 device so every time you add a dep on a module that links against C libraries (Pillow depends on zlib and libjpeg) I have to cross compile the necessary native extensions, distribute them etc. Either that or manually installing a skimmed `requirements.txt` and finally installing Flexget passing `--no-dependencies` to `pip install`.

Does adding a tray icon justify this hassle for users? No saying that’s wrong of course, just trying to bring to your attention this use case and the potential annoyance for users.

Could perhaps these things be made optional at install/build time by relaxing the hard dependency?

Thanks.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `flexget/tray_icon.py`
Content:
```
1 import logging
2 import webbrowser
3 from functools import partial, wraps
4 from pathlib import Path
5 from typing import List, Optional
6 
7 from loguru import logger
8 
9 from flexget import __version__
10 
11 logger = logger.bind(name='tray_icon')
12 
13 try:
14     # If we are running outside of a graphical environment, these imports will fail
15     from PIL import Image
16     from pystray import Icon, Menu, MenuItem
17 
18     _import_success = True
19 except Exception as e:
20     logger.debug('Could not import pystray: {}', e)
21     _import_success = False
22 
23 
24 def check_if_tray_is_active(f):
25     @wraps(f)
26     def wrapped(self, *args, **kwargs):
27         if not self.active:
28             return
29         return f(self, *args, **kwargs)
30 
31     return wrapped
32 
33 
34 image_path = Path(__file__).parent / 'resources' / 'flexget.png'
35 
36 
37 class TrayIcon:
38     def __init__(self, path_to_image: Path = image_path):
39         # Silence PIL noisy logging
40         logging.getLogger('PIL.PngImagePlugin').setLevel(logging.INFO)
41         logging.getLogger('PIL.Image').setLevel(logging.INFO)
42 
43         self.path_to_image: Path = path_to_image
44         self.icon: Optional['Icon'] = None
45         self._menu: Optional['Menu'] = None
46         self.menu_items: List['MenuItem'] = []
47 
48         self.active: bool = _import_success
49         self.running: bool = False
50 
51         self.add_core_menu_items()
52 
53     @check_if_tray_is_active
54     def add_menu_item(
55         self,
56         text: str = None,
57         action: callable = None,
58         menu_item: 'MenuItem' = None,
59         index: int = None,
60         **kwargs,
61     ):
62         """
63         Add a menu item byt passing its text and function, or pass a created MenuItem. Force position by sending index
64         """
65         if not any(v for v in (menu_item, text)):
66             raise ValueError(f"Either 'text' or 'menu_item' are required")
67 
68         menu_item = menu_item or MenuItem(text=text, action=action, **kwargs)
69         if index is not None:
70             self.menu_items.insert(index, menu_item)
71         else:
72             self.menu_items.append(menu_item)
73 
74     @check_if_tray_is_active
75     def add_menu_separator(self, index: int = None):
76         self.add_menu_item(menu_item=Menu.SEPARATOR, index=index)
77 
78     def add_core_menu_items(self):
79         open_web = partial(webbrowser.open)
80         self.add_menu_item(text=f'Flexget {__version__}', enabled=False)
81         self.add_menu_separator()
82         self.add_menu_item(text='Homepage', action=partial(open_web, 'https://flexget.com/'))
83         self.add_menu_item(text='Forum', action=partial(open_web, 'https://discuss.flexget.com/'))
84 
85     @property
86     def menu(self) -> 'Menu':
87         # This is lazy loaded since we'd like to delay the menu build until the tray is requested to run
88         if not self._menu:
89             self._menu = Menu(*self.menu_items)
90         return self._menu
91 
92     @check_if_tray_is_active
93     def run(self):
94         """Run the tray icon. Must be run from the main thread and is blocking"""
95         try:
96             logger.verbose('Starting tray icon')
97             self.icon = Icon('Flexget', Image.open(self.path_to_image), menu=self.menu)
98             self.running = True
99             self.icon.run()
100         except Exception as e:
101             logger.warning('Could not run tray icon: {}', e)
102             self.running = False
103 
104     @check_if_tray_is_active
105     def stop(self):
106         if not self.running:
107             return
108 
109         logger.verbose('Stopping tray icon')
110         self.icon.stop()
111         self.running = False
112 
113 
114 tray_icon = TrayIcon()
115
```
--- 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/flexget/tray_icon.py b/flexget/tray_icon.py
--- a/flexget/tray_icon.py
+++ b/flexget/tray_icon.py
@@ -17,7 +17,7 @@
 
     _import_success = True
 except Exception as e:
-    logger.debug('Could not import pystray: {}', e)
+    logger.debug('Could not load tray icon: {}', e)
     _import_success = False

{"golden_diff": "diff --git a/flexget/tray_icon.py b/flexget/tray_icon.py\n--- a/flexget/tray_icon.py\n+++ b/flexget/tray_icon.py\n@@ -17,7 +17,7 @@\n \n     _import_success = True\n except Exception as e:\n-    logger.debug('Could not import pystray: {}', e)\n+    logger.debug('Could not load tray icon: {}', e)\n     _import_success = False\n", "issue": "Dependencies on non pure Python modules\nHi,\r\n\r\nSorry for [x-posting](https://discuss.flexget.com/t/dependencies-on-non-pure-python-modules/5086). This is kind of a development issue so it might fit here better than in the forum. Feel free to just close this and reply on Discourse.\r\n\r\nWhen upgrading Flexget I stumbled upon the fact that now it depends on Pillow, as per:\r\n\r\nhttps://github.com/Flexget/Flexget/pull/2621\r\n\r\nMy Flexget runs on an embedded aarch64 device so every time you add a dep on a module that links against C libraries (Pillow depends on zlib and libjpeg) I have to cross compile the necessary native extensions, distribute them etc. Either that or manually installing a skimmed `requirements.txt` and finally installing Flexget passing `--no-dependencies` to `pip install`.\r\n\r\nDoes adding a tray icon justify this hassle for users? No saying that\u2019s wrong of course, just trying to bring to your attention this use case and the potential annoyance for users.\r\n\r\nCould perhaps these things be made optional at install/build time by relaxing the hard dependency?\r\n\r\nThanks.\nDependencies on non pure Python modules\nHi,\r\n\r\nSorry for [x-posting](https://discuss.flexget.com/t/dependencies-on-non-pure-python-modules/5086). This is kind of a development issue so it might fit here better than in the forum. Feel free to just close this and reply on Discourse.\r\n\r\nWhen upgrading Flexget I stumbled upon the fact that now it depends on Pillow, as per:\r\n\r\nhttps://github.com/Flexget/Flexget/pull/2621\r\n\r\nMy Flexget runs on an embedded aarch64 device so every time you add a dep on a module that links against C libraries (Pillow depends on zlib and libjpeg) I have to cross compile the necessary native extensions, distribute them etc. Either that or manually installing a skimmed `requirements.txt` and finally installing Flexget passing `--no-dependencies` to `pip install`.\r\n\r\nDoes adding a tray icon justify this hassle for users? No saying that\u2019s wrong of course, just trying to bring to your attention this use case and the potential annoyance for users.\r\n\r\nCould perhaps these things be made optional at install/build time by relaxing the hard dependency?\r\n\r\nThanks.\n", "before_files": [{"content": "import logging\nimport webbrowser\nfrom functools import partial, wraps\nfrom pathlib import Path\nfrom typing import List, Optional\n\nfrom loguru import logger\n\nfrom flexget import __version__\n\nlogger = logger.bind(name='tray_icon')\n\ntry:\n    # If we are running outside of a graphical environment, these imports will fail\n    from PIL import Image\n    from pystray import Icon, Menu, MenuItem\n\n    _import_success = True\nexcept Exception as e:\n    logger.debug('Could not import pystray: {}', e)\n    _import_success = False\n\n\ndef check_if_tray_is_active(f):\n    @wraps(f)\n    def wrapped(self, *args, **kwargs):\n        if not self.active:\n            return\n        return f(self, *args, **kwargs)\n\n    return wrapped\n\n\nimage_path = Path(__file__).parent / 'resources' / 'flexget.png'\n\n\nclass TrayIcon:\n    def __init__(self, path_to_image: Path = image_path):\n        # Silence PIL noisy logging\n        logging.getLogger('PIL.PngImagePlugin').setLevel(logging.INFO)\n        logging.getLogger('PIL.Image').setLevel(logging.INFO)\n\n        self.path_to_image: Path = path_to_image\n        self.icon: Optional['Icon'] = None\n        self._menu: Optional['Menu'] = None\n        self.menu_items: List['MenuItem'] = []\n\n        self.active: bool = _import_success\n        self.running: bool = False\n\n        self.add_core_menu_items()\n\n    @check_if_tray_is_active\n    def add_menu_item(\n        self,\n        text: str = None,\n        action: callable = None,\n        menu_item: 'MenuItem' = None,\n        index: int = None,\n        **kwargs,\n    ):\n        \"\"\"\n        Add a menu item byt passing its text and function, or pass a created MenuItem. Force position by sending index\n        \"\"\"\n        if not any(v for v in (menu_item, text)):\n            raise ValueError(f\"Either 'text' or 'menu_item' are required\")\n\n        menu_item = menu_item or MenuItem(text=text, action=action, **kwargs)\n        if index is not None:\n            self.menu_items.insert(index, menu_item)\n        else:\n            self.menu_items.append(menu_item)\n\n    @check_if_tray_is_active\n    def add_menu_separator(self, index: int = None):\n        self.add_menu_item(menu_item=Menu.SEPARATOR, index=index)\n\n    def add_core_menu_items(self):\n        open_web = partial(webbrowser.open)\n        self.add_menu_item(text=f'Flexget {__version__}', enabled=False)\n        self.add_menu_separator()\n        self.add_menu_item(text='Homepage', action=partial(open_web, 'https://flexget.com/'))\n        self.add_menu_item(text='Forum', action=partial(open_web, 'https://discuss.flexget.com/'))\n\n    @property\n    def menu(self) -> 'Menu':\n        # This is lazy loaded since we'd like to delay the menu build until the tray is requested to run\n        if not self._menu:\n            self._menu = Menu(*self.menu_items)\n        return self._menu\n\n    @check_if_tray_is_active\n    def run(self):\n        \"\"\"Run the tray icon. Must be run from the main thread and is blocking\"\"\"\n        try:\n            logger.verbose('Starting tray icon')\n            self.icon = Icon('Flexget', Image.open(self.path_to_image), menu=self.menu)\n            self.running = True\n            self.icon.run()\n        except Exception as e:\n            logger.warning('Could not run tray icon: {}', e)\n            self.running = False\n\n    @check_if_tray_is_active\n    def stop(self):\n        if not self.running:\n            return\n\n        logger.verbose('Stopping tray icon')\n        self.icon.stop()\n        self.running = False\n\n\ntray_icon = TrayIcon()\n", "path": "flexget/tray_icon.py"}], "after_files": [{"content": "import logging\nimport webbrowser\nfrom functools import partial, wraps\nfrom pathlib import Path\nfrom typing import List, Optional\n\nfrom loguru import logger\n\nfrom flexget import __version__\n\nlogger = logger.bind(name='tray_icon')\n\ntry:\n    # If we are running outside of a graphical environment, these imports will fail\n    from PIL import Image\n    from pystray import Icon, Menu, MenuItem\n\n    _import_success = True\nexcept Exception as e:\n    logger.debug('Could not load tray icon: {}', e)\n    _import_success = False\n\n\ndef check_if_tray_is_active(f):\n    @wraps(f)\n    def wrapped(self, *args, **kwargs):\n        if not self.active:\n            return\n        return f(self, *args, **kwargs)\n\n    return wrapped\n\n\nimage_path = Path(__file__).parent / 'resources' / 'flexget.png'\n\n\nclass TrayIcon:\n    def __init__(self, path_to_image: Path = image_path):\n        # Silence PIL noisy logging\n        logging.getLogger('PIL.PngImagePlugin').setLevel(logging.INFO)\n        logging.getLogger('PIL.Image').setLevel(logging.INFO)\n\n        self.path_to_image: Path = path_to_image\n        self.icon: Optional['Icon'] = None\n        self._menu: Optional['Menu'] = None\n        self.menu_items: List['MenuItem'] = []\n\n        self.active: bool = _import_success\n        self.running: bool = False\n\n        self.add_core_menu_items()\n\n    @check_if_tray_is_active\n    def add_menu_item(\n        self,\n        text: str = None,\n        action: callable = None,\n        menu_item: 'MenuItem' = None,\n        index: int = None,\n        **kwargs,\n    ):\n        \"\"\"\n        Add a menu item byt passing its text and function, or pass a created MenuItem. Force position by sending index\n        \"\"\"\n        if not any(v for v in (menu_item, text)):\n            raise ValueError(f\"Either 'text' or 'menu_item' are required\")\n\n        menu_item = menu_item or MenuItem(text=text, action=action, **kwargs)\n        if index is not None:\n            self.menu_items.insert(index, menu_item)\n        else:\n            self.menu_items.append(menu_item)\n\n    @check_if_tray_is_active\n    def add_menu_separator(self, index: int = None):\n        self.add_menu_item(menu_item=Menu.SEPARATOR, index=index)\n\n    def add_core_menu_items(self):\n        open_web = partial(webbrowser.open)\n        self.add_menu_item(text=f'Flexget {__version__}', enabled=False)\n        self.add_menu_separator()\n        self.add_menu_item(text='Homepage', action=partial(open_web, 'https://flexget.com/'))\n        self.add_menu_item(text='Forum', action=partial(open_web, 'https://discuss.flexget.com/'))\n\n    @property\n    def menu(self) -> 'Menu':\n        # This is lazy loaded since we'd like to delay the menu build until the tray is requested to run\n        if not self._menu:\n            self._menu = Menu(*self.menu_items)\n        return self._menu\n\n    @check_if_tray_is_active\n    def run(self):\n        \"\"\"Run the tray icon. Must be run from the main thread and is blocking\"\"\"\n        try:\n            logger.verbose('Starting tray icon')\n            self.icon = Icon('Flexget', Image.open(self.path_to_image), menu=self.menu)\n            self.running = True\n            self.icon.run()\n        except Exception as e:\n            logger.warning('Could not run tray icon: {}', e)\n            self.running = False\n\n    @check_if_tray_is_active\n    def stop(self):\n        if not self.running:\n            return\n\n        logger.verbose('Stopping tray icon')\n        self.icon.stop()\n        self.running = False\n\n\ntray_icon = TrayIcon()\n", "path": "flexget/tray_icon.py"}]}