Introdução

A última grande atualização do Python - para a versão 3 - ocorreu em dezembro de 2008, há quase 12 anos. No entanto, há uma boa chance de que você ainda esteja trabalhando no produto Python 2 ou no código de teste. Nesse caso, você pode estar vendo a mensagem de depreciação abaixo como um lembrete para atualizar a versão do Python com a qual está trabalhando.

"DEPRECATION: O Python 2.7 chegará ao fim de sua vida útil em 1º de janeiro de 2020. Atualize seu Python, pois o Python 2.7 não será mantido após essa data. Uma versão futura do pip deixará de oferecer suporte ao Python 2.7."

Leve isso a sério e planeje adequadamente: As atualizações do Python para a versão 3.x não são compatíveis com versões anteriores. O que você escreve com as versões 2.x do Python pode não funcionar corretamente quando usar a 3.x.

Não deixe de ler também as letras miúdas. De acordo com o site da linguagem de programação, a data final de lançamento da atualização do Python ainda é uma incógnita: "Por ser a última da série 2.x, a versão 2.7 receberá suporte para correção de bugs até 2020. O suporte será oficialmente interrompido em 1º de janeiro de 2020, mas a versão final ocorrerá após essa data." [1]

Portanto, o Python 2 entrará no modo sem suporte até o final deste ano. Se você ainda não tiver feito isso, agora é um bom momento para migrar o código atual do Python 2 para a sintaxe do Python 3 e manter o Python 3 daqui para frente.

Por que as equipes simplesmente não iniciam essa migração do Python 2 para o 3? Um dos principais obstáculos é que a maioria dos códigos funcionais simplesmente quebra (leia mais em why-was-python-3-made-incompatible-with-python-2), seja por causa da sintaxe direta da linguagem ou por problemas com APIs de terceiros. Sejamos justos: poucos de nós se preocupariam com a migração se as novas atualizações do Python fossem compatíveis com as versões anteriores. Em vez disso, a versão 2 ficará sem suporte, forçando muitos - inclusive nós aqui no Couchbase - a priorizar a migração. Mesmo que a equipe ultrapasse o prazo de suporte para correção de bugs, não há problema (porque seu código ainda está funcionando). Como equipe, decidimos que é melhor migrar o mais próximo possível dessa data para que possamos estar na mesma página que outros membros da comunidade Python e aprender com eles.  

Este documento é uma coleção de dicas e truques que aprendemos durante a atualização para o Python 3, juntamente com problemas comuns que encontramos durante o processo de migração da infraestrutura de teste do Couchbase. Como você verá, atualizamos o Python manualmente pela linha de comando depois de iniciarmos um processo automatizado. Sua abordagem pode ser diferente. Independentemente disso, comece assim que puder. A atualização do python da versão 2 para a versão 3 é importante.

Couchbase é um banco de dados NoSQL de classe empresarial de código aberto, do MultiCloud ao Edge. A estrutura de teste funcional do Couchbase, TestRunner, foi desenvolvida em Python 2. O repositório git do TestRunner pode ser encontrado em https://github.com/couchbase/testrunner . Nosso objetivo agora é mudar completamente para o tempo de execução do Python 3 em vez de executar conjuntamente o Python 3 e o Python 2.

Como parte do processo de atualização do Python, identificamos as principais alterações necessárias para a portabilidade bem-sucedida para a versão 3. Alguns dos problemas sobre os quais você lerá foram identificados durante o processo de portabilidade. Nosso objetivo ao compartilhar nossos aprendizados é ajudá-lo em sua própria migração. Você pode escolher a versão mais recente do Python 3.x (depende da versão de pré-lançamento, estável e com correções de segurança em uma plataforma específica, 3.7 ou 3.6), à qual nos referimos como Python 3 em todo este blog. Veja mais detalhes sobre o lançamento em Download de versões do PythonDocumentação do Python 3.

Folha de dicas

 

Principais alterações: Python 2 vs. Python 3

Para ter uma ideia das principais diferenças entre o Python 2 e o Python 3, aqui está a lista resumida das alterações de código necessárias.

Python 2 Python 3
Texto utf-8 : str
O texto é unicode : str
u"
Binário é o mesmo que Texto: bytes/str
Exemplo:
file.read(6) == 'GIF89a'
Os dados binários são representados como prefixo b: bytes
 b"
Use decode() para obter a string, encode() para obter bytes.Exemplos: 
file.read(6) == b'GIF89a'
b'hello'.decode() → 'hello'
'hello'.encode() → b'hello'
str(b'hello') → "b'hello'
Imprimir declaração
Exemplo: print ' '
Função de impressão
Exemplo: print(' ')
Divisão de números inteiros
Exemplo: 5/2=2
Divisão de andares. Use 2 barras
Exemplo: 5//2 = 2 e 5/2=2,5
Divisão de flutuação
Exemplo: 5/2,0 = 2,5 ou 5,0/2 = 2,5
Divisão de flutuação. Use uma barra simples
Exemplo: 5/2 = 2.5
O tipo long é diferente de int
longo 
Não existe um tipo long. Ele é igual a int
xrange() intervalo()
As funções de iteração tinham o prefixo iter. iterxxx()
Exemplo: iteritems()
O prefixo do iter foi removido. xxxx()
Exemplo: items()
As listas são carregadas diretamente (todos os elementos são carregados na memória quando a lista é usada)
Exemplo: for i in [] 
As listas são carregadas de forma preguiçosa (quando um elemento é acessado, ele só é carregado na memória)
Exemplo: for i in list([]) 
Os dicionários podem ser comparados por padrão ou com 2 dicionários.
Exemplo: sorted(dict) 
Os dicionários não podem ser comparados diretamente. sorted() deve ter uma chave.

Exemplo: sorted(expected_result,key=(lambda x: x[bucket.name]['name']))Para comparação geral de ditado/lista, você pode usar o seguinte: 
 from deepdiff import DeepDiff
 diffs = DeepDiff(resultado_real['resultados'], resultado_esperado['resultados'], ignore_order=Verdadeiro)se diffs:
   autônomo.assertTrue(Falso, diffs)

Bytes e cadeias de caracteres como valores:
diffs = DeepDiff(definir(actual_indexes), definir(indexes_names), ignore_order=Verdadeiro, ignore_string_type_changes=Verdadeiro)

string.replace(data[i],...) data[i].replace(..)
urllib.urlencode() Novos módulos

  • http.client
  • urllib.request, urllib.error, urllib.parse
  • sgmllib3k

Exemplos: 
urllib.parse.urlencode()

string.lowercase Atributos:
string.ascii_lowercase
string.ascii_uppercase

Veja o testrunner py3 commits  para mudanças

Configuração do Python 3

Para configurar o Python 3 do zero, execute os comandos abaixo em um novo host com as principais plataformas suportadas.
Posteriormente, durante o tempo de execução, use o comando python 3 ou python no ambiente virtual do python 3. Use pip3 ou pip3.x (pip3.6, por exemplo) para instalar pacotes com base na versão do Python 3 instalada.

Mac OS
(Exemplo: seu laptop)
Configuração direta (pip3 instalado automaticamente):(https://wsvincent.com/install-python3-mac/)

Configuração do ambiente virtual:

Instale as bibliotecas necessárias:

Por enquanto, a modificação abaixo é necessária para o cliente http comum do Python 3; caso contrário, você receberá um erro.

 
CentOS  
(Exemplo de nó: Jenkins Slave)
Configuração direta e ambiente virtual:

Instale as bibliotecas necessárias:

 

Realizar a instalação do Couchbase CSDK e do Python SDK no novo slave:

Por enquanto, a modificação abaixo é necessária para o cliente http comum do Python 3; caso contrário, você receberá um erro.

 

Ubuntu slave usando para verificação do tempo de execução do Python 3
Configuração direta:

 

Instale as bibliotecas necessárias:

Instalação do CSDK e do Python SDK: (Ref: https://docs.couchbase.com/c-sdk/2.10/start-using-sdk.html )

Por enquanto, a modificação abaixo é necessária para o cliente http comum do Python 3; caso contrário, você receberá um erro.

 

Windows
Faça o download e instale: https://www.python.org/ftp/python/3.7.4/python-3.7.4.exe

Instale as bibliotecas necessárias:

 

Processo de portabilidade

Em um nível elevado, a portabilidade é um processo de três etapas. 1) Conversão automática 2) Alterações manuais 3) Validação e correção em tempo de execução

Em um primeiro momento, clone o repositório original e faça as alterações básicas de conversão automática. Faça o check-in das alterações como um novo repositório até que a conversão completa seja concluída. Dessa forma, os ciclos de regressão atuais podem continuar sem interrupção.

1. Conversão automática

Há uma ferramenta automatizada chamada 2para3 ferramentafornecida pela equipe do Python 3, que ajuda a cuidar de alguns padrões comuns, como impressão, exceção, encapsulamento de lista, importações relativas etc.  

Você pode começar com um único diretório no espaço de trabalho clonado localmente para fazer uma verificação dupla. Posteriormente, a conversão pode ser feita inteiramente em todo o código para que a portabilidade básica seja resolvida.

Abaixo estão alguns exemplos de comandos de conversão de 2 para 3 no MacOS. No último comando, observe que todas as expressões idiomáticas foram aplicadas. Dessa forma, a primeira conversão pode cuidar das alterações de chave.

 

2. Alterações manuais

A conversão automática não faz a portabilidade completa. Os problemas comuns abaixo podem ocorrer durante o processo de portabilidade, além das alterações comuns de sintaxe feitas pela ferramenta de conversão automática 2to3. 

Execute a classe de teste e veja se há algum erro e corrija-o adequadamente, decidindo se deve mudar de bytes para str ou de str para bytes ou algum tipo de problema de comparação em que seja necessário corrigir o nome da chave na função de classificação. Esse é um processo iterativo até que todo o tempo de execução do código tenha sido validado.

Quando um padrão comum estiver claro, você poderá usar o grep e o sed para substituir em vários arquivos de classe. Se você não tiver certeza sobre outro código até o tempo de execução, adie até que a classe de teste seja executada. 

Pode haver problemas com bibliotecas/módulos de terceiros que podem ter sido alterados, que precisam ser pesquisados na Web e usados adequadamente.

Certifique-se de que todo o caminho do código seja coberto pela execução em todas as plataformas e parâmetros suportados.

3. Validação e correção em tempo de execução

Depois que a conversão for feita, execute muito tempo de execução do código, pois o Python é uma linguagem dinâmica. Caso contrário, as alterações podem quebrar as coisas se você fizer apenas inspeção/alterações visuais de código estático. Você pode começar com testes básicos de sanidade, testes de aceitação e, em seguida, selecionar testes completos de um único módulo de testes.

Quando estiver confortável, passe a usar todos os outros módulos, um a um. Continue verificando as alterações no novo repositório. Além disso, você precisa ter certeza de que não há regressões com as alterações portadas desse novo repositório, executando testes de sanidade nas compilações mais recentes. Além disso, a validação deve incluir todas as plataformas compatíveis com o Python 3.

 

Código portado e status do Python 3

Veja abaixo onde encontrar o novo repositório para o código portado do Python 3 até que ele seja mesclado ao repositório principal. O plano é fazer um ciclo de portabilidade ou, de forma intermediária, pegar as alterações do repositório principal e fazer uma mesclagem manual com esse repositório.

https://github.com/couchbaselabs/testrunner-py3/

(Branch: master)

Muitas alterações comuns já foram feitas, mas não foram concluídas, pois pode haver outros problemas de tempo de execução. As correções em comum também podem ser revertidas para as correções anteriores devido a suposições sobre conversões de tipo de valor de entrada. Ainda há mais alguns códigos portados a serem validados com o Python 3 e o esforço ainda está em andamento.

Agora, vou lhe mostrar os problemas comuns que ocorreu durante a validação do tempo de execução. Você pode usar isso como referência quando tiver um problema para ver se está tendo um problema semelhante. Você pode aplicar a mesma solução e ver se ela funciona para você. E se você tiver algum novas ideias, você pode colocá-las nos comentários.

Problemas comuns de tempo de execução

 

1. Problema(s):

  • Você pode receber alguns dos TypeErrors abaixo durante o tempo de execução, como str em vez de bytes e bytes em vez de str
  • Error#1. TypeError: não é possível concatenar str com bytes
  • Error#2. TypeError: deve ser str, não bytes
  • Error#3. TypeError: é necessário um objeto do tipo bytes, não 'str'
  • Error#4. TypeError: Não é possível misturar argumentos str e não str

Solução(ões):

Veja os tipos das variáveis na declaração e use xxx.encode() para obter os bytes ou xxx.decode() para obter a string ou use o prefixo b ou use str(). Às vezes, a entrada pode não ser desconhecida e, nesse caso, use try x.encode() except AttributeError: pass


2. Problema(s):

TypeError: root - ERRO - --->instalação falhou: é necessário um objeto do tipo bytes, não 'str'

Solução(ões): 

Nesse caso, adicione b como prefixo à string em comparação ou altere o tipo de byte para o tipo de string. Exemplo: lib/remote/remote_util.py

Envolva o try-except para verificar a linha exata que está causando o erro (digamos, acima do TypeError). 

Exemplo de saída após traceback.print_exec() para ver o rastreamento completo da pilha de forma semelhante ao java.

Corrigir com alterações no lib/remote/remote_util.py conforme abaixo.

3. Problema(s):

 

Solução(ões):

 

4. Problema(s):

AttributeError suite_setUp() ou suite_tearDown() estão faltando em alguns conjuntos de teste.

Solução(ões):

Adicione os métodos dummy suite_setUp() e suite_tearDown(). 

 

5. Problema(s):

 

Solução(ões):

 

6. Problema(s):

AttributeError: o objeto 'Transport' não tem o atributo '_Thread__stop'

Solução(ões):

Não há parada direta de um thread não-demônico. Mas, em termos de sintaxe, use t._stop(). A recomendação é usar o desligamento gracioso usando um sinalizador global e verificar na execução() do thread para interromper.

(https://stackoverflow.com/questions/27102881/python-threading-self-stop-event-object-is-not-callable)

7. Problema(s):

O teste expirytests.ExpiryTests.test_expired_keys não foi encontrado: o módulo 'string' não tem o atributo 'translate'

Solução(ões):

Reescreva com métodos estáticos str. Não existe uma maneira antiga de obter todos os caracteres, portanto, usamos o código anterior e o conjunto total.

vi lib/membase/api/tap.py 

 

8. Problema(s):

TabError: uso inconsistente de tabulações e espaços na indentação

 

Solução(ões):

Procure caracteres de tabulação e substitua por caracteres de espaço. 

Para o problema acima, remova os caracteres de tabulação.

 

9. Problema(s):

Solução(ões):

Problema de sensibilidade a maiúsculas e minúsculas. Corrigido com a alteração da chave x_couchbase_meta para X_Couchbase_Meta

 

10. Problema(s):

  • Error#1. TypeError: '<' não é suportado entre instâncias de 'dict' e 'dict'
  • Erro#2. TypeError: 'cmp' é um argumento de palavra-chave inválido para esta função

Solução(ões):

   

11. Problema(s):

Solução(ões):

 

12. Problema(s):

Solução(ões):

 

13. Problema(s):

Solução(ões):

Aqui, ele deve retornar int, pois o python 3 não compara automaticamente como no python 2.

 

14. Problema(s):

Solução(ões):

 

15. Problema(s):

Solução(ões):

Converteu a chave em string para que ch seja string em vez de int com chave binária. Veja o arquivo.

 

16. Problema(s):

TypeError: o objeto 'FileNotFoundError' não é subescriturável

Solução(ões):

Alterado no Python 3, pois FileNotFoundError não é subescriturável e, em vez disso, use o atributo errno, e.errno

 

17. Problema(s):

Solução(ões):

A comparação de dicionário/lista aninhada não estava funcionando porque a função de classificação anterior para classificar completamente agora não está disponível. Use o módulo deepdiff e a classe DeepDiff para fazer a comparação

 

18. Problema(s):

AttributeError: o módulo 'string' não tem o atributo 'replace'

Solução(ões):

Use a variável direct str para substituir como mostrado abaixo para corrigir o problema.

 

19. Problema(s):

Solução(ões):

Use a função str ou int adequadamente.

 

20. Problema(s):

NameError: o nome 'cmp' não está definido

Solução(ões):

Use o módulo deepdiff e a classe DeepDiff para fazer a comparação de objetos.

 

21. Problema(s):

Solução(ões):

Converta str em int como abaixo para o problema de erro de tipo acima.

—-

Por enquanto, isso é tudo na lista de problemas a serem observados quando você atualizar o Python versão 2 para o Python versão 3. Publicaremos mais aprendizados em futuras postagens no blog. Enquanto isso, boa sorte na migração!

 

Leituras adicionais

As referências a seguir nos ajudaram. Você também pode ler mais nos links de referência abaixo para obter mais detalhes e melhorar a portabilidade do seu código para o Python 3.

  1. https://www.python.org/dev/peps/pep-0373/
  2. https://wiki.python.org/moin/Python2orPython3
  3. https://www.toptal.com/python/python-3-is-it-worth-the-switch
  4. https://weknowinc.com/blog/running-multiple-python-versions-mac-osx
  5. https://docs.python.org/3/howto/pyporting.html
  6. https://wsvincent.com/install-python3-mac/
  7. http://python3porting.com/pdfs/SupportingPython3-screen-1.0-latest.pdf
  8. https://riptutorial.com/Download/python-language.pdf
  9. https://docs.couchbase.com/python-sdk/2.5/start-using-sdk.html
  10. https://docs.couchbase.com/c-sdk/2.10/start-using-sdk.html
  11. https://pypi.org/project/deepdiff/
  12. https://buildmedia.readthedocs.org/media/pdf/portingguide/latest/portingguide.pdf
  13. http://ptgmedia.pearsoncmg.com/imprint_downloads/informit/promotions/python/python2python3.pdf

Espero que você tenha se divertido com a leitura!

Isenção de responsabilidade: Por favor, veja isso como uma referência rápida para a atualização do Python 3, em vez de um guia completo para resolver problemas de portabilidade. Nossa intenção aqui é ajudá-lo em algum nível e dar um empurrãozinho no processo de portabilidade. Sinta-se à vontade para compartilhar se tiver aprendido algo novo que possa nos ajudar. Seu feedback positivo é muito bem-vindo!

 

Agradecemos a Raju Suravarjjala e Keshav Murthy por suas principais contribuições e feedback.

 

Autor

Postado por Jagadesh Munta, engenheiro de software principal, Couchbase

Jagadesh Munta é engenheiro de software principal da Couchbase Inc., EUA. EUA. Antes disso, ele foi veterano na Sun Microsystems e na Oracle por 19 anos. Jagadesh é mestre em engenharia de software pela San Jose State University, EUA, e bacharel em tecnologia. Ciência e Engenharia da Computação na JNTU, Índia. Ele é autor do "Software Quality and Java Automation Engineer Survival Guide" para ajudar desenvolvedores de software e engenheiros de automação de qualidade.

Deixar uma resposta