prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Encoding is always UTF-8 in POST data
  ## Long story short
  
  I'm doing a `POST` request via `client.post`:
  
  ```
  data = aiohttp.FormData({
              'FindText': name,
          }, charset='windows-1251')
  
  client.post(base_url, params={'RowFrom': offset}, data=data)
  ```
  
  where `name` contains some none-latin text (`'хан'`)
  
  ## Expected behaviour
  
  POST data should contain: `FindText=%D5%E0%ED`
  
  ## Actual behaviour
  
  `FindText=%D1%85%D0%B0%D0%BD'`
  
  ## Steps to reproduce
  
  Looking through the code of `formdata.py:99`
  
  ```
  urlencode(data, doseq=True).encode(charset),
  ```
  
  I noticed, that `data` is urlencoded in UTF-8 first and then encoded to `windows-1251` (and that has no effect on `%D1...`).
  
  For now, I just manually do in my code:
  
  ```
  data = urlencode({
              'FindText': name,
          }, encoding='windows-1251')
  ```
  
  And I get the string that I need.
  
  Is it a bug? Or am I doing it wrong?
  
  ## Your environment
  
  ```
  Python 3.6.0 (default, Jan 16 2017, 12:12:55) 
  [GCC 6.3.1 20170109] on linux
  ---
  aiohttp==2.0.3
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `aiohttp/formdata.py`
  Content:
  ```
  1 import io
  2 from urllib.parse import urlencode
  3 
  4 from multidict import MultiDict, MultiDictProxy
  5 
  6 from . import hdrs, multipart, payload
  7 from .helpers import guess_filename
  8 
  9 __all__ = ('FormData',)
  10 
  11 
  12 class FormData:
  13     """Helper class for multipart/form-data and
  14     application/x-www-form-urlencoded body generation."""
  15 
  16     def __init__(self, fields=(), quote_fields=True, charset=None):
  17         self._writer = multipart.MultipartWriter('form-data')
  18         self._fields = []
  19         self._is_multipart = False
  20         self._quote_fields = quote_fields
  21         self._charset = charset
  22 
  23         if isinstance(fields, dict):
  24             fields = list(fields.items())
  25         elif not isinstance(fields, (list, tuple)):
  26             fields = (fields,)
  27         self.add_fields(*fields)
  28 
  29     @property
  30     def is_multipart(self):
  31         return self._is_multipart
  32 
  33     def add_field(self, name, value, *, content_type=None, filename=None,
  34                   content_transfer_encoding=None):
  35 
  36         if isinstance(value, io.IOBase):
  37             self._is_multipart = True
  38         elif isinstance(value, (bytes, bytearray, memoryview)):
  39             if filename is None and content_transfer_encoding is None:
  40                 filename = name
  41 
  42         type_options = MultiDict({'name': name})
  43         if filename is not None and not isinstance(filename, str):
  44             raise TypeError('filename must be an instance of str. '
  45                             'Got: %s' % filename)
  46         if filename is None and isinstance(value, io.IOBase):
  47             filename = guess_filename(value, name)
  48         if filename is not None:
  49             type_options['filename'] = filename
  50             self._is_multipart = True
  51 
  52         headers = {}
  53         if content_type is not None:
  54             if not isinstance(content_type, str):
  55                 raise TypeError('content_type must be an instance of str. '
  56                                 'Got: %s' % content_type)
  57             headers[hdrs.CONTENT_TYPE] = content_type
  58             self._is_multipart = True
  59         if content_transfer_encoding is not None:
  60             if not isinstance(content_transfer_encoding, str):
  61                 raise TypeError('content_transfer_encoding must be an instance'
  62                                 ' of str. Got: %s' % content_transfer_encoding)
  63             headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding
  64             self._is_multipart = True
  65 
  66         self._fields.append((type_options, headers, value))
  67 
  68     def add_fields(self, *fields):
  69         to_add = list(fields)
  70 
  71         while to_add:
  72             rec = to_add.pop(0)
  73 
  74             if isinstance(rec, io.IOBase):
  75                 k = guess_filename(rec, 'unknown')
  76                 self.add_field(k, rec)
  77 
  78             elif isinstance(rec, (MultiDictProxy, MultiDict)):
  79                 to_add.extend(rec.items())
  80 
  81             elif isinstance(rec, (list, tuple)) and len(rec) == 2:
  82                 k, fp = rec
  83                 self.add_field(k, fp)
  84 
  85             else:
  86                 raise TypeError('Only io.IOBase, multidict and (name, file) '
  87                                 'pairs allowed, use .add_field() for passing '
  88                                 'more complex parameters, got {!r}'
  89                                 .format(rec))
  90 
  91     def _gen_form_urlencoded(self):
  92         # form data (x-www-form-urlencoded)
  93         data = []
  94         for type_options, _, value in self._fields:
  95             data.append((type_options['name'], value))
  96 
  97         charset = self._charset if self._charset is not None else 'utf-8'
  98         return payload.BytesPayload(
  99             urlencode(data, doseq=True).encode(charset),
  100             content_type='application/x-www-form-urlencoded')
  101 
  102     def _gen_form_data(self):
  103         """Encode a list of fields using the multipart/form-data MIME format"""
  104         for dispparams, headers, value in self._fields:
  105             try:
  106                 if hdrs.CONTENT_TYPE in headers:
  107                     part = payload.get_payload(
  108                         value, content_type=headers[hdrs.CONTENT_TYPE],
  109                         headers=headers, encoding=self._charset)
  110                 else:
  111                     part = payload.get_payload(
  112                         value, headers=headers, encoding=self._charset)
  113             except Exception as exc:
  114                 raise TypeError(
  115                     'Can not serialize value type: %r\n '
  116                     'headers: %r\n value: %r' % (
  117                         type(value), headers, value)) from exc
  118 
  119             if dispparams:
  120                 part.set_content_disposition(
  121                     'form-data', quote_fields=self._quote_fields, **dispparams
  122                 )
  123                 # FIXME cgi.FieldStorage doesn't likes body parts with
  124                 # Content-Length which were sent via chunked transfer encoding
  125                 part.headers.pop(hdrs.CONTENT_LENGTH, None)
  126 
  127             self._writer.append_payload(part)
  128 
  129         return self._writer
  130 
  131     def __call__(self):
  132         if self._is_multipart:
  133             return self._gen_form_data()
  134         else:
  135             return self._gen_form_urlencoded()
  136
  ```
  --- 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/aiohttp/formdata.py b/aiohttp/formdata.py
  --- a/aiohttp/formdata.py
  +++ b/aiohttp/formdata.py
  @@ -96,7 +96,7 @@
   
           charset = self._charset if self._charset is not None else 'utf-8'
           return payload.BytesPayload(
  -            urlencode(data, doseq=True).encode(charset),
  +            urlencode(data, doseq=True, encoding=charset).encode(),
               content_type='application/x-www-form-urlencoded')
   
       def _gen_form_data(self):
  
verification_info: {"golden_diff": "diff --git a/aiohttp/formdata.py b/aiohttp/formdata.py\n--- a/aiohttp/formdata.py\n+++ b/aiohttp/formdata.py\n@@ -96,7 +96,7 @@\n \n         charset = self._charset if self._charset is not None else 'utf-8'\n         return payload.BytesPayload(\n-            urlencode(data, doseq=True).encode(charset),\n+            urlencode(data, doseq=True, encoding=charset).encode(),\n             content_type='application/x-www-form-urlencoded')\n \n     def _gen_form_data(self):\n", "issue": "Encoding is always UTF-8 in POST data\n## Long story short\r\n\r\nI'm doing a `POST` request via `client.post`:\r\n\r\n```\r\ndata = aiohttp.FormData({\r\n            'FindText': name,\r\n        }, charset='windows-1251')\r\n\r\nclient.post(base_url, params={'RowFrom': offset}, data=data)\r\n```\r\n\r\nwhere `name` contains some none-latin text (`'\u0445\u0430\u043d'`)\r\n\r\n## Expected behaviour\r\n\r\nPOST data should contain: `FindText=%D5%E0%ED`\r\n\r\n## Actual behaviour\r\n\r\n`FindText=%D1%85%D0%B0%D0%BD'`\r\n\r\n## Steps to reproduce\r\n\r\nLooking through the code of `formdata.py:99`\r\n\r\n```\r\nurlencode(data, doseq=True).encode(charset),\r\n```\r\n\r\nI noticed, that `data` is urlencoded in UTF-8 first and then encoded to `windows-1251` (and that has no effect on `%D1...`).\r\n\r\nFor now, I just manually do in my code:\r\n\r\n```\r\ndata = urlencode({\r\n            'FindText': name,\r\n        }, encoding='windows-1251')\r\n```\r\n\r\nAnd I get the string that I need.\r\n\r\nIs it a bug? Or am I doing it wrong?\r\n\r\n## Your environment\r\n\r\n```\r\nPython 3.6.0 (default, Jan 16 2017, 12:12:55) \r\n[GCC 6.3.1 20170109] on linux\r\n---\r\naiohttp==2.0.3\r\n```\r\n\n", "before_files": [{"content": "import io\nfrom urllib.parse import urlencode\n\nfrom multidict import MultiDict, MultiDictProxy\n\nfrom . import hdrs, multipart, payload\nfrom .helpers import guess_filename\n\n__all__ = ('FormData',)\n\n\nclass FormData:\n    \"\"\"Helper class for multipart/form-data and\n    application/x-www-form-urlencoded body generation.\"\"\"\n\n    def __init__(self, fields=(), quote_fields=True, charset=None):\n        self._writer = multipart.MultipartWriter('form-data')\n        self._fields = []\n        self._is_multipart = False\n        self._quote_fields = quote_fields\n        self._charset = charset\n\n        if isinstance(fields, dict):\n            fields = list(fields.items())\n        elif not isinstance(fields, (list, tuple)):\n            fields = (fields,)\n        self.add_fields(*fields)\n\n    @property\n    def is_multipart(self):\n        return self._is_multipart\n\n    def add_field(self, name, value, *, content_type=None, filename=None,\n                  content_transfer_encoding=None):\n\n        if isinstance(value, io.IOBase):\n            self._is_multipart = True\n        elif isinstance(value, (bytes, bytearray, memoryview)):\n            if filename is None and content_transfer_encoding is None:\n                filename = name\n\n        type_options = MultiDict({'name': name})\n        if filename is not None and not isinstance(filename, str):\n            raise TypeError('filename must be an instance of str. '\n                            'Got: %s' % filename)\n        if filename is None and isinstance(value, io.IOBase):\n            filename = guess_filename(value, name)\n        if filename is not None:\n            type_options['filename'] = filename\n            self._is_multipart = True\n\n        headers = {}\n        if content_type is not None:\n            if not isinstance(content_type, str):\n                raise TypeError('content_type must be an instance of str. '\n                                'Got: %s' % content_type)\n            headers[hdrs.CONTENT_TYPE] = content_type\n            self._is_multipart = True\n        if content_transfer_encoding is not None:\n            if not isinstance(content_transfer_encoding, str):\n                raise TypeError('content_transfer_encoding must be an instance'\n                                ' of str. Got: %s' % content_transfer_encoding)\n            headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding\n            self._is_multipart = True\n\n        self._fields.append((type_options, headers, value))\n\n    def add_fields(self, *fields):\n        to_add = list(fields)\n\n        while to_add:\n            rec = to_add.pop(0)\n\n            if isinstance(rec, io.IOBase):\n                k = guess_filename(rec, 'unknown')\n                self.add_field(k, rec)\n\n            elif isinstance(rec, (MultiDictProxy, MultiDict)):\n                to_add.extend(rec.items())\n\n            elif isinstance(rec, (list, tuple)) and len(rec) == 2:\n                k, fp = rec\n                self.add_field(k, fp)\n\n            else:\n                raise TypeError('Only io.IOBase, multidict and (name, file) '\n                                'pairs allowed, use .add_field() for passing '\n                                'more complex parameters, got {!r}'\n                                .format(rec))\n\n    def _gen_form_urlencoded(self):\n        # form data (x-www-form-urlencoded)\n        data = []\n        for type_options, _, value in self._fields:\n            data.append((type_options['name'], value))\n\n        charset = self._charset if self._charset is not None else 'utf-8'\n        return payload.BytesPayload(\n            urlencode(data, doseq=True).encode(charset),\n            content_type='application/x-www-form-urlencoded')\n\n    def _gen_form_data(self):\n        \"\"\"Encode a list of fields using the multipart/form-data MIME format\"\"\"\n        for dispparams, headers, value in self._fields:\n            try:\n                if hdrs.CONTENT_TYPE in headers:\n                    part = payload.get_payload(\n                        value, content_type=headers[hdrs.CONTENT_TYPE],\n                        headers=headers, encoding=self._charset)\n                else:\n                    part = payload.get_payload(\n                        value, headers=headers, encoding=self._charset)\n            except Exception as exc:\n                raise TypeError(\n                    'Can not serialize value type: %r\\n '\n                    'headers: %r\\n value: %r' % (\n                        type(value), headers, value)) from exc\n\n            if dispparams:\n                part.set_content_disposition(\n                    'form-data', quote_fields=self._quote_fields, **dispparams\n                )\n                # FIXME cgi.FieldStorage doesn't likes body parts with\n                # Content-Length which were sent via chunked transfer encoding\n                part.headers.pop(hdrs.CONTENT_LENGTH, None)\n\n            self._writer.append_payload(part)\n\n        return self._writer\n\n    def __call__(self):\n        if self._is_multipart:\n            return self._gen_form_data()\n        else:\n            return self._gen_form_urlencoded()\n", "path": "aiohttp/formdata.py"}], "after_files": [{"content": "import io\nfrom urllib.parse import urlencode\n\nfrom multidict import MultiDict, MultiDictProxy\n\nfrom . import hdrs, multipart, payload\nfrom .helpers import guess_filename\n\n__all__ = ('FormData',)\n\n\nclass FormData:\n    \"\"\"Helper class for multipart/form-data and\n    application/x-www-form-urlencoded body generation.\"\"\"\n\n    def __init__(self, fields=(), quote_fields=True, charset=None):\n        self._writer = multipart.MultipartWriter('form-data')\n        self._fields = []\n        self._is_multipart = False\n        self._quote_fields = quote_fields\n        self._charset = charset\n\n        if isinstance(fields, dict):\n            fields = list(fields.items())\n        elif not isinstance(fields, (list, tuple)):\n            fields = (fields,)\n        self.add_fields(*fields)\n\n    @property\n    def is_multipart(self):\n        return self._is_multipart\n\n    def add_field(self, name, value, *, content_type=None, filename=None,\n                  content_transfer_encoding=None):\n\n        if isinstance(value, io.IOBase):\n            self._is_multipart = True\n        elif isinstance(value, (bytes, bytearray, memoryview)):\n            if filename is None and content_transfer_encoding is None:\n                filename = name\n\n        type_options = MultiDict({'name': name})\n        if filename is not None and not isinstance(filename, str):\n            raise TypeError('filename must be an instance of str. '\n                            'Got: %s' % filename)\n        if filename is None and isinstance(value, io.IOBase):\n            filename = guess_filename(value, name)\n        if filename is not None:\n            type_options['filename'] = filename\n            self._is_multipart = True\n\n        headers = {}\n        if content_type is not None:\n            if not isinstance(content_type, str):\n                raise TypeError('content_type must be an instance of str. '\n                                'Got: %s' % content_type)\n            headers[hdrs.CONTENT_TYPE] = content_type\n            self._is_multipart = True\n        if content_transfer_encoding is not None:\n            if not isinstance(content_transfer_encoding, str):\n                raise TypeError('content_transfer_encoding must be an instance'\n                                ' of str. Got: %s' % content_transfer_encoding)\n            headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding\n            self._is_multipart = True\n\n        self._fields.append((type_options, headers, value))\n\n    def add_fields(self, *fields):\n        to_add = list(fields)\n\n        while to_add:\n            rec = to_add.pop(0)\n\n            if isinstance(rec, io.IOBase):\n                k = guess_filename(rec, 'unknown')\n                self.add_field(k, rec)\n\n            elif isinstance(rec, (MultiDictProxy, MultiDict)):\n                to_add.extend(rec.items())\n\n            elif isinstance(rec, (list, tuple)) and len(rec) == 2:\n                k, fp = rec\n                self.add_field(k, fp)\n\n            else:\n                raise TypeError('Only io.IOBase, multidict and (name, file) '\n                                'pairs allowed, use .add_field() for passing '\n                                'more complex parameters, got {!r}'\n                                .format(rec))\n\n    def _gen_form_urlencoded(self):\n        # form data (x-www-form-urlencoded)\n        data = []\n        for type_options, _, value in self._fields:\n            data.append((type_options['name'], value))\n\n        charset = self._charset if self._charset is not None else 'utf-8'\n        return payload.BytesPayload(\n            urlencode(data, doseq=True, encoding=charset).encode(),\n            content_type='application/x-www-form-urlencoded')\n\n    def _gen_form_data(self):\n        \"\"\"Encode a list of fields using the multipart/form-data MIME format\"\"\"\n        for dispparams, headers, value in self._fields:\n            try:\n                if hdrs.CONTENT_TYPE in headers:\n                    part = payload.get_payload(\n                        value, content_type=headers[hdrs.CONTENT_TYPE],\n                        headers=headers, encoding=self._charset)\n                else:\n                    part = payload.get_payload(\n                        value, headers=headers, encoding=self._charset)\n            except Exception as exc:\n                raise TypeError(\n                    'Can not serialize value type: %r\\n '\n                    'headers: %r\\n value: %r' % (\n                        type(value), headers, value)) from exc\n\n            if dispparams:\n                part.set_content_disposition(\n                    'form-data', quote_fields=self._quote_fields, **dispparams\n                )\n                # FIXME cgi.FieldStorage doesn't likes body parts with\n                # Content-Length which were sent via chunked transfer encoding\n                part.headers.pop(hdrs.CONTENT_LENGTH, None)\n\n            self._writer.append_payload(part)\n\n        return self._writer\n\n    def __call__(self):\n        if self._is_multipart:\n            return self._gen_form_data()\n        else:\n            return self._gen_form_urlencoded()\n", "path": "aiohttp/formdata.py"}]}