prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Issue 2.7.2: Form plugin
  ### Expected behaviour:
  No error while using 2.5.2 version
  ### Actual behaviour:
  Got an error while running task that using form plugin
  ### Steps to reproduce:
  Running task with form plugin
  
  #### Config:
  ```yaml
   avistaz_subs:
      form:
        url: https://avistaz.to/auth/login
        username: "{{secrets.avistaz.usr}}"
        password: "{{secrets.avistaz.pwd}}"
        userfield: email_username
        passfield: password
      html:
        url: "https://avistaz.to/subtitles?type=2&search=720p&language=0&subtitle=45&page={{i}}"
        title_from: url
        links_re:
          - '\.(rar|r0+[01](/01)|zip|srt)'
        increment:
          from: 0
          to: 1
        #dump: result.html
      regexp:
        accept:
          - someregex
      #disable: builtins
      download: yes
      decompress: true
      template: [notify_me]
  ```
  #### Log:
  Generated new crash log
  
  ### Additional information:
  
  - Flexget Version: 2.7.2
  - Python Version: 2.7.9
  - Installation method: easy_install upgrade flexget
  - OS and version: osmc raspberry pi
  - Link to crash log: http://pastebin.com/XHL3dzQH
  
  --- 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/plugins/operate/formlogin.py`
  Content:
  ```
  1 from __future__ import unicode_literals, division, absolute_import
  2 from builtins import *  # noqa pylint: disable=unused-import, redefined-builtin
  3 
  4 import logging
  5 import io
  6 import os
  7 import socket
  8 
  9 try:
  10     import mechanize
  11 except ImportError:
  12     mechanize = None
  13 
  14 from flexget import plugin
  15 from flexget.event import event
  16 from flexget.utils.soup import get_soup
  17 
  18 log = logging.getLogger('formlogin')
  19 
  20 
  21 if mechanize:
  22     class SanitizeHandler(mechanize.BaseHandler):
  23         def http_response(self, request, response):
  24             if not hasattr(response, "seek"):
  25                 response = mechanize.response_seek_wrapper(response)
  26             # Run HTML through BeautifulSoup for sanitizing
  27             if 'html' in response.info().get('content-type', ''):
  28                 soup = get_soup(response.get_data())
  29                 response.set_data(soup.prettify(encoding=soup.original_encoding))
  30             return response
  31 
  32 
  33 class FormLogin(object):
  34     """
  35     Login on form
  36     """
  37 
  38     schema = {
  39         'type': 'object',
  40         'properties': {
  41             'url': {'type': 'string', 'format': 'url'},
  42             'username': {'type': 'string'},
  43             'password': {'type': 'string'},
  44             'userfield': {'type': 'string'},
  45             'passfield': {'type': 'string'}
  46         },
  47         'required': ['url', 'username', 'password'],
  48         'additionalProperties': False
  49     }
  50 
  51     def on_task_start(self, task, config):
  52         if not mechanize:
  53             raise plugin.PluginError('mechanize required (python module), please install it.', log)
  54 
  55         userfield = config.get('userfield', 'username')
  56         passfield = config.get('passfield', 'password')
  57 
  58         url = config['url']
  59         username = config['username']
  60         password = config['password']
  61 
  62         br = mechanize.Browser()
  63         br.add_handler(SanitizeHandler())
  64         br.set_handle_robots(False)
  65         try:
  66             br.open(url)
  67         except Exception:
  68             # TODO: improve error handling
  69             log.debug('Exception posting login form.', exc_info=True)
  70             raise plugin.PluginError('Unable to post login form', log)
  71 
  72         # br.set_debug_redirects(True)
  73         # br.set_debug_responses(True)
  74         # br.set_debug_http(True)
  75 
  76         try:
  77             for form in br.forms():
  78                 loginform = form
  79 
  80                 try:
  81                     loginform[userfield] = username
  82                     loginform[passfield] = password
  83                     break
  84                 except Exception:
  85                     pass
  86             else:
  87                 received = os.path.join(task.manager.config_base, 'received')
  88                 if not os.path.isdir(received):
  89                     os.mkdir(received)
  90                 filename = os.path.join(received, '%s.formlogin.html' % task.name)
  91                 with io.open(filename, 'wb') as f:
  92                     f.write(br.response().get_data())
  93                 log.critical('I have saved the login page content to %s for you to view', filename)
  94                 raise plugin.PluginError('Unable to find login fields', log)
  95         except socket.timeout:
  96             raise plugin.PluginError('Timed out on url %s' % url)
  97 
  98         br.form = loginform
  99 
  100         br.submit()
  101 
  102         cookiejar = br._ua_handlers["_cookies"].cookiejar
  103 
  104         # Add cookiejar to our requests session
  105         task.requests.add_cookiejar(cookiejar)
  106 
  107 
  108 @event('plugin.register')
  109 def register_plugin():
  110     plugin.register(FormLogin, 'form', api_ver=2)
  111
  ```
  --- 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/plugins/operate/formlogin.py b/flexget/plugins/operate/formlogin.py
  --- a/flexget/plugins/operate/formlogin.py
  +++ b/flexget/plugins/operate/formlogin.py
  @@ -7,29 +7,17 @@
   import socket
   
   try:
  -    import mechanize
  +    import mechanicalsoup
   except ImportError:
  -    mechanize = None
  +    mechanicalsoup = None
  +import requests
   
   from flexget import plugin
   from flexget.event import event
  -from flexget.utils.soup import get_soup
   
   log = logging.getLogger('formlogin')
   
   
  -if mechanize:
  -    class SanitizeHandler(mechanize.BaseHandler):
  -        def http_response(self, request, response):
  -            if not hasattr(response, "seek"):
  -                response = mechanize.response_seek_wrapper(response)
  -            # Run HTML through BeautifulSoup for sanitizing
  -            if 'html' in response.info().get('content-type', ''):
  -                soup = get_soup(response.get_data())
  -                response.set_data(soup.prettify(encoding=soup.original_encoding))
  -            return response
  -
  -
   class FormLogin(object):
       """
       Login on form
  @@ -49,8 +37,8 @@
       }
   
       def on_task_start(self, task, config):
  -        if not mechanize:
  -            raise plugin.PluginError('mechanize required (python module), please install it.', log)
  +        if not mechanicalsoup:
  +            raise plugin.PluginError('mechanicalsoup required (python module), please install it.', log)
   
           userfield = config.get('userfield', 'username')
           passfield = config.get('passfield', 'password')
  @@ -59,29 +47,28 @@
           username = config['username']
           password = config['password']
   
  -        br = mechanize.Browser()
  -        br.add_handler(SanitizeHandler())
  -        br.set_handle_robots(False)
  +        br = mechanicalsoup.StatefulBrowser(session=task.requests)
  +
           try:
  -            br.open(url)
  -        except Exception:
  +            response = br.open(url)
  +        except requests.RequestException:
               # TODO: improve error handling
  -            log.debug('Exception posting login form.', exc_info=True)
  -            raise plugin.PluginError('Unable to post login form', log)
  +            log.debug('Exception getting login page.', exc_info=True)
  +            raise plugin.PluginError('Unable to get login page', log)
   
  -        # br.set_debug_redirects(True)
  -        # br.set_debug_responses(True)
  -        # br.set_debug_http(True)
  +        # br.set_debug(True)
   
  +        num_forms = len(br.get_current_page().find_all('form'))
  +        if not num_forms:
  +            raise plugin.PluginError('Unable to find any forms on {}'.format(url), log)
           try:
  -            for form in br.forms():
  -                loginform = form
  -
  +            for form_num in range(num_forms):
  +                br.select_form(nr=form_num)
                   try:
  -                    loginform[userfield] = username
  -                    loginform[passfield] = password
  +                    br[userfield] = username
  +                    br[passfield] = password
                       break
  -                except Exception:
  +                except mechanicalsoup.LinkNotFoundError:
                       pass
               else:
                   received = os.path.join(task.manager.config_base, 'received')
  @@ -89,20 +76,17 @@
                       os.mkdir(received)
                   filename = os.path.join(received, '%s.formlogin.html' % task.name)
                   with io.open(filename, 'wb') as f:
  -                    f.write(br.response().get_data())
  +                    f.write(response.content)
                   log.critical('I have saved the login page content to %s for you to view', filename)
                   raise plugin.PluginError('Unable to find login fields', log)
           except socket.timeout:
               raise plugin.PluginError('Timed out on url %s' % url)
   
  -        br.form = loginform
  -
  -        br.submit()
  -
  -        cookiejar = br._ua_handlers["_cookies"].cookiejar
  -
  -        # Add cookiejar to our requests session
  -        task.requests.add_cookiejar(cookiejar)
  +        try:
  +            br.submit_selected()
  +        except requests.RequestException:
  +            log.debug('Exception submitting login form.', exc_info=True)
  +            raise plugin.PluginError('Unable to post login form', log)
   
   
   @event('plugin.register')
  
verification_info: {"golden_diff": "diff --git a/flexget/plugins/operate/formlogin.py b/flexget/plugins/operate/formlogin.py\n--- a/flexget/plugins/operate/formlogin.py\n+++ b/flexget/plugins/operate/formlogin.py\n@@ -7,29 +7,17 @@\n import socket\n \n try:\n-    import mechanize\n+    import mechanicalsoup\n except ImportError:\n-    mechanize = None\n+    mechanicalsoup = None\n+import requests\n \n from flexget import plugin\n from flexget.event import event\n-from flexget.utils.soup import get_soup\n \n log = logging.getLogger('formlogin')\n \n \n-if mechanize:\n-    class SanitizeHandler(mechanize.BaseHandler):\n-        def http_response(self, request, response):\n-            if not hasattr(response, \"seek\"):\n-                response = mechanize.response_seek_wrapper(response)\n-            # Run HTML through BeautifulSoup for sanitizing\n-            if 'html' in response.info().get('content-type', ''):\n-                soup = get_soup(response.get_data())\n-                response.set_data(soup.prettify(encoding=soup.original_encoding))\n-            return response\n-\n-\n class FormLogin(object):\n     \"\"\"\n     Login on form\n@@ -49,8 +37,8 @@\n     }\n \n     def on_task_start(self, task, config):\n-        if not mechanize:\n-            raise plugin.PluginError('mechanize required (python module), please install it.', log)\n+        if not mechanicalsoup:\n+            raise plugin.PluginError('mechanicalsoup required (python module), please install it.', log)\n \n         userfield = config.get('userfield', 'username')\n         passfield = config.get('passfield', 'password')\n@@ -59,29 +47,28 @@\n         username = config['username']\n         password = config['password']\n \n-        br = mechanize.Browser()\n-        br.add_handler(SanitizeHandler())\n-        br.set_handle_robots(False)\n+        br = mechanicalsoup.StatefulBrowser(session=task.requests)\n+\n         try:\n-            br.open(url)\n-        except Exception:\n+            response = br.open(url)\n+        except requests.RequestException:\n             # TODO: improve error handling\n-            log.debug('Exception posting login form.', exc_info=True)\n-            raise plugin.PluginError('Unable to post login form', log)\n+            log.debug('Exception getting login page.', exc_info=True)\n+            raise plugin.PluginError('Unable to get login page', log)\n \n-        # br.set_debug_redirects(True)\n-        # br.set_debug_responses(True)\n-        # br.set_debug_http(True)\n+        # br.set_debug(True)\n \n+        num_forms = len(br.get_current_page().find_all('form'))\n+        if not num_forms:\n+            raise plugin.PluginError('Unable to find any forms on {}'.format(url), log)\n         try:\n-            for form in br.forms():\n-                loginform = form\n-\n+            for form_num in range(num_forms):\n+                br.select_form(nr=form_num)\n                 try:\n-                    loginform[userfield] = username\n-                    loginform[passfield] = password\n+                    br[userfield] = username\n+                    br[passfield] = password\n                     break\n-                except Exception:\n+                except mechanicalsoup.LinkNotFoundError:\n                     pass\n             else:\n                 received = os.path.join(task.manager.config_base, 'received')\n@@ -89,20 +76,17 @@\n                     os.mkdir(received)\n                 filename = os.path.join(received, '%s.formlogin.html' % task.name)\n                 with io.open(filename, 'wb') as f:\n-                    f.write(br.response().get_data())\n+                    f.write(response.content)\n                 log.critical('I have saved the login page content to %s for you to view', filename)\n                 raise plugin.PluginError('Unable to find login fields', log)\n         except socket.timeout:\n             raise plugin.PluginError('Timed out on url %s' % url)\n \n-        br.form = loginform\n-\n-        br.submit()\n-\n-        cookiejar = br._ua_handlers[\"_cookies\"].cookiejar\n-\n-        # Add cookiejar to our requests session\n-        task.requests.add_cookiejar(cookiejar)\n+        try:\n+            br.submit_selected()\n+        except requests.RequestException:\n+            log.debug('Exception submitting login form.', exc_info=True)\n+            raise plugin.PluginError('Unable to post login form', log)\n \n \n @event('plugin.register')\n", "issue": "Issue 2.7.2: Form plugin\n### Expected behaviour:\r\nNo error while using 2.5.2 version\r\n### Actual behaviour:\r\nGot an error while running task that using form plugin\r\n### Steps to reproduce:\r\nRunning task with form plugin\r\n\r\n#### Config:\r\n```yaml\r\n avistaz_subs:\r\n    form:\r\n      url: https://avistaz.to/auth/login\r\n      username: \"{{secrets.avistaz.usr}}\"\r\n      password: \"{{secrets.avistaz.pwd}}\"\r\n      userfield: email_username\r\n      passfield: password\r\n    html:\r\n      url: \"https://avistaz.to/subtitles?type=2&search=720p&language=0&subtitle=45&page={{i}}\"\r\n      title_from: url\r\n      links_re:\r\n        - '\\.(rar|r0+[01](/01)|zip|srt)'\r\n      increment:\r\n        from: 0\r\n        to: 1\r\n      #dump: result.html\r\n    regexp:\r\n      accept:\r\n        - someregex\r\n    #disable: builtins\r\n    download: yes\r\n    decompress: true\r\n    template: [notify_me]\r\n```\r\n#### Log:\r\nGenerated new crash log\r\n\r\n### Additional information:\r\n\r\n- Flexget Version: 2.7.2\r\n- Python Version: 2.7.9\r\n- Installation method: easy_install upgrade flexget\r\n- OS and version: osmc raspberry pi\r\n- Link to crash log: http://pastebin.com/XHL3dzQH\n", "before_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\nimport io\nimport os\nimport socket\n\ntry:\n    import mechanize\nexcept ImportError:\n    mechanize = None\n\nfrom flexget import plugin\nfrom flexget.event import event\nfrom flexget.utils.soup import get_soup\n\nlog = logging.getLogger('formlogin')\n\n\nif mechanize:\n    class SanitizeHandler(mechanize.BaseHandler):\n        def http_response(self, request, response):\n            if not hasattr(response, \"seek\"):\n                response = mechanize.response_seek_wrapper(response)\n            # Run HTML through BeautifulSoup for sanitizing\n            if 'html' in response.info().get('content-type', ''):\n                soup = get_soup(response.get_data())\n                response.set_data(soup.prettify(encoding=soup.original_encoding))\n            return response\n\n\nclass FormLogin(object):\n    \"\"\"\n    Login on form\n    \"\"\"\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'url': {'type': 'string', 'format': 'url'},\n            'username': {'type': 'string'},\n            'password': {'type': 'string'},\n            'userfield': {'type': 'string'},\n            'passfield': {'type': 'string'}\n        },\n        'required': ['url', 'username', 'password'],\n        'additionalProperties': False\n    }\n\n    def on_task_start(self, task, config):\n        if not mechanize:\n            raise plugin.PluginError('mechanize required (python module), please install it.', log)\n\n        userfield = config.get('userfield', 'username')\n        passfield = config.get('passfield', 'password')\n\n        url = config['url']\n        username = config['username']\n        password = config['password']\n\n        br = mechanize.Browser()\n        br.add_handler(SanitizeHandler())\n        br.set_handle_robots(False)\n        try:\n            br.open(url)\n        except Exception:\n            # TODO: improve error handling\n            log.debug('Exception posting login form.', exc_info=True)\n            raise plugin.PluginError('Unable to post login form', log)\n\n        # br.set_debug_redirects(True)\n        # br.set_debug_responses(True)\n        # br.set_debug_http(True)\n\n        try:\n            for form in br.forms():\n                loginform = form\n\n                try:\n                    loginform[userfield] = username\n                    loginform[passfield] = password\n                    break\n                except Exception:\n                    pass\n            else:\n                received = os.path.join(task.manager.config_base, 'received')\n                if not os.path.isdir(received):\n                    os.mkdir(received)\n                filename = os.path.join(received, '%s.formlogin.html' % task.name)\n                with io.open(filename, 'wb') as f:\n                    f.write(br.response().get_data())\n                log.critical('I have saved the login page content to %s for you to view', filename)\n                raise plugin.PluginError('Unable to find login fields', log)\n        except socket.timeout:\n            raise plugin.PluginError('Timed out on url %s' % url)\n\n        br.form = loginform\n\n        br.submit()\n\n        cookiejar = br._ua_handlers[\"_cookies\"].cookiejar\n\n        # Add cookiejar to our requests session\n        task.requests.add_cookiejar(cookiejar)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(FormLogin, 'form', api_ver=2)\n", "path": "flexget/plugins/operate/formlogin.py"}], "after_files": [{"content": "from __future__ import unicode_literals, division, absolute_import\nfrom builtins import *  # noqa pylint: disable=unused-import, redefined-builtin\n\nimport logging\nimport io\nimport os\nimport socket\n\ntry:\n    import mechanicalsoup\nexcept ImportError:\n    mechanicalsoup = None\nimport requests\n\nfrom flexget import plugin\nfrom flexget.event import event\n\nlog = logging.getLogger('formlogin')\n\n\nclass FormLogin(object):\n    \"\"\"\n    Login on form\n    \"\"\"\n\n    schema = {\n        'type': 'object',\n        'properties': {\n            'url': {'type': 'string', 'format': 'url'},\n            'username': {'type': 'string'},\n            'password': {'type': 'string'},\n            'userfield': {'type': 'string'},\n            'passfield': {'type': 'string'}\n        },\n        'required': ['url', 'username', 'password'],\n        'additionalProperties': False\n    }\n\n    def on_task_start(self, task, config):\n        if not mechanicalsoup:\n            raise plugin.PluginError('mechanicalsoup required (python module), please install it.', log)\n\n        userfield = config.get('userfield', 'username')\n        passfield = config.get('passfield', 'password')\n\n        url = config['url']\n        username = config['username']\n        password = config['password']\n\n        br = mechanicalsoup.StatefulBrowser(session=task.requests)\n\n        try:\n            response = br.open(url)\n        except requests.RequestException:\n            # TODO: improve error handling\n            log.debug('Exception getting login page.', exc_info=True)\n            raise plugin.PluginError('Unable to get login page', log)\n\n        # br.set_debug(True)\n\n        num_forms = len(br.get_current_page().find_all('form'))\n        if not num_forms:\n            raise plugin.PluginError('Unable to find any forms on {}'.format(url), log)\n        try:\n            for form_num in range(num_forms):\n                br.select_form(nr=form_num)\n                try:\n                    br[userfield] = username\n                    br[passfield] = password\n                    break\n                except mechanicalsoup.LinkNotFoundError:\n                    pass\n            else:\n                received = os.path.join(task.manager.config_base, 'received')\n                if not os.path.isdir(received):\n                    os.mkdir(received)\n                filename = os.path.join(received, '%s.formlogin.html' % task.name)\n                with io.open(filename, 'wb') as f:\n                    f.write(response.content)\n                log.critical('I have saved the login page content to %s for you to view', filename)\n                raise plugin.PluginError('Unable to find login fields', log)\n        except socket.timeout:\n            raise plugin.PluginError('Timed out on url %s' % url)\n\n        try:\n            br.submit_selected()\n        except requests.RequestException:\n            log.debug('Exception submitting login form.', exc_info=True)\n            raise plugin.PluginError('Unable to post login form', log)\n\n\n@event('plugin.register')\ndef register_plugin():\n    plugin.register(FormLogin, 'form', api_ver=2)\n", "path": "flexget/plugins/operate/formlogin.py"}]}