Requests: UnicodeEncodeError: o codec 'latin-1' não pode codificar caracteres

Criado em 20 dez. 2013  ·  7Comentários  ·  Fonte: psf/requests

Requests é a versão mais recente.
Quando tento postar os dados que contêm caracteres chineses, essa exceção é lançada.

Traceback (most recent call last):
  File "X/threading.py", line 639, in _bootstrap_inner
  File "X/threading.py", line 596, in run
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\salesforce\api.py", line 546, in execute_anonymous
    headers=headers)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\api.py", line 88, in post
    return request('post', url, data=data, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\sessions.py", line 338, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\sessions.py", line 441, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\adapters.py", line 292, in send
    timeout=timeout
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\packages\urllib3\connectionpool.py", line 428, in urlopen
    body=body, headers=headers)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\packages\urllib3\connectionpool.py", line 280, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "X/http/client.py", line 1049, in request
  File "X/http/client.py", line 1086, in _send_request
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 1632-1633: ordinal not in range(256)

Comentários muito úteis

Portanto, ST 3, mas não a revisão mais recente. Ok, isso nos dá algo. Especificamente, Sublime Text 3 usa Python 3.3, não Python 2.7 (que Sublime Text 2 usa). Isso significa que todas as strings padrão no Sublime Apex são strings Unicode.

Se você abrir o arquivo Python 3.3 http.client , verá que a função _send_request() tem a seguinte aparência:

# Honor explicitly requested Host: and Accept-Encoding: headers.
header_names = dict.fromkeys([k.lower() for k in headers])
skips = {}
if 'host' in header_names:
    skips['skip_host'] = 1
if 'accept-encoding' in header_names:
    skips['skip_accept_encoding'] = 1

self.putrequest(method, url, **skips)

if body is not None and ('content-length' not in header_names):
    self._set_content_length(body)
for hdr, value in headers.items():
    self.putheader(hdr, value)
if isinstance(body, str):
    # RFC 2616 Section 3.7.1 says that text default has a
    # default charset of iso-8859-1.
    body = body.encode('iso-8859-1')
self.endheaders(body)

Agora, ISO-8859-1 é um apelido para Latin-1, que é o codec com o qual estamos tendo problemas. O problema que temos é que o Sublime Apex está fornecendo um corpo de string unicode para Requests, que o httplib precisa codificar em bytes. Tomando como padrão o RFC 2616, conclui que você deseja o Latin-1, que não inclui nenhum caractere chinês. Claramente, a codificação falha e você obtém a exceção em questão.

Considerando que o Sublime Apex afirma nos cabeçalhos que envia estar enviando dados codificados em UTF-8 (o que atualmente é uma mentira), o Sublime Apex deseja codificar os dados como UTF-8 antes de enviá-los. Isso significa que qualquer linha de envio de dados (neste caso, a linha 545 de salesforce/api.py ) deve ser lida assim:

response = requests.post(self.apex_url, soap_body.encode('utf-8'), verify=False, headers=headers)

Para o bem de qualquer pessoa que queira confirmar meu diagnóstico, aqui está um pequeno exemplo de código que confirma o problema:

a = "\u13E0\u19E0\u1320"
a.encode('latin1')  # Throws UnicodeEncodeError, proves that this can't be expressed in ISO-8859-1.
a.encode('utf-8')  # Totally fine.
r = requests.post('http://httpbin.org/post', data=a)  # Using unicode string, throws UnicodeEncodeError blaming Latin1.
r = requests.post('http://httpbin.org/post', data=a.encode('utf-8'))  # Works fine.

Obrigado por nos informar, mas este não é um bug de solicitações. =)

Todos 7 comentários

Arquivo "X / http / client.py"

Você escreveu X porque esse é um caminho para um arquivo local? Em caso afirmativo, sua estrutura de diretório pode estar confundindo urllib3. Se não, você provavelmente deve levantar isso em bugs.python.org, pois isso não é algo que eu acho que as solicitações devam ser tratadas. Parece que está subindo de httplib (ou http no Python 3, que suponho que você esteja usando).

@ sigmavirus24 ,

Eu usei solicitações no plugin sublime, se o soap_body na instrução abaixo não contiver nenhum caractere chinês, não haverá exceção.

response = requests.post(self.apex_url, soap_body, verify=False, headers=headers)

Em primeiro lugar, a menos que você esteja usando uma versão diferente do Sublime Apex daquela em seu repositório público, Requests _não_ é a versão mais recente, é a versão 1.2.3. Você pode me dizer qual versão do Sublime Text você está usando?

É um texto sublime 3056

Portanto, ST 3, mas não a revisão mais recente. Ok, isso nos dá algo. Especificamente, Sublime Text 3 usa Python 3.3, não Python 2.7 (que Sublime Text 2 usa). Isso significa que todas as strings padrão no Sublime Apex são strings Unicode.

Se você abrir o arquivo Python 3.3 http.client , verá que a função _send_request() tem a seguinte aparência:

# Honor explicitly requested Host: and Accept-Encoding: headers.
header_names = dict.fromkeys([k.lower() for k in headers])
skips = {}
if 'host' in header_names:
    skips['skip_host'] = 1
if 'accept-encoding' in header_names:
    skips['skip_accept_encoding'] = 1

self.putrequest(method, url, **skips)

if body is not None and ('content-length' not in header_names):
    self._set_content_length(body)
for hdr, value in headers.items():
    self.putheader(hdr, value)
if isinstance(body, str):
    # RFC 2616 Section 3.7.1 says that text default has a
    # default charset of iso-8859-1.
    body = body.encode('iso-8859-1')
self.endheaders(body)

Agora, ISO-8859-1 é um apelido para Latin-1, que é o codec com o qual estamos tendo problemas. O problema que temos é que o Sublime Apex está fornecendo um corpo de string unicode para Requests, que o httplib precisa codificar em bytes. Tomando como padrão o RFC 2616, conclui que você deseja o Latin-1, que não inclui nenhum caractere chinês. Claramente, a codificação falha e você obtém a exceção em questão.

Considerando que o Sublime Apex afirma nos cabeçalhos que envia estar enviando dados codificados em UTF-8 (o que atualmente é uma mentira), o Sublime Apex deseja codificar os dados como UTF-8 antes de enviá-los. Isso significa que qualquer linha de envio de dados (neste caso, a linha 545 de salesforce/api.py ) deve ser lida assim:

response = requests.post(self.apex_url, soap_body.encode('utf-8'), verify=False, headers=headers)

Para o bem de qualquer pessoa que queira confirmar meu diagnóstico, aqui está um pequeno exemplo de código que confirma o problema:

a = "\u13E0\u19E0\u1320"
a.encode('latin1')  # Throws UnicodeEncodeError, proves that this can't be expressed in ISO-8859-1.
a.encode('utf-8')  # Totally fine.
r = requests.post('http://httpbin.org/post', data=a)  # Using unicode string, throws UnicodeEncodeError blaming Latin1.
r = requests.post('http://httpbin.org/post', data=a.encode('utf-8'))  # Works fine.

Obrigado por nos informar, mas este não é um bug de solicitações. =)

Obrigado.

r = requests.post (' http://httpbin.org/post ', data = a.encode ('utf-8'))
muito útil,
obrigada!

Esta página foi útil?
0 / 5 - 0 avaliações