prompt: 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()
  
  ```
  
golden_diff: 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
  
verification_info: {"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"}]}