Migração para Python 2.7

Nesta página, descrevemos as medidas necessárias para fazer upgrade do aplicativo Python para o ambiente de execução do Python 2.7. Seguindo essas instruções, o aplicativo aproveitará muitos dos recursos novos do ambiente de execução do Python 2.7, incluindo multissegmentação, mecanismo de modelos Jinja2 (ambos em inglês), acesso e upload de bytecode e diversas novas bibliotecas terceirizadas.

Pré-requisitos e considerações

Para usar o Python 2.7, um aplicativo precisa atender aos seguintes requisitos:

  • Para usar o Django, é preciso que a versão seja 1.2 ou posterior. Consulte a documentação do Django para detalhes de upgrade.
  • Para usar solicitações simultâneas, o aplicativo precisa usar gerenciadores de scripts de interface de gateway do servidor da Web (WSGI na sigla em inglês), conforme abordado em Como usar a WSGI.

Além de atender a esses pré-requisitos gerais, é preciso usar versões específicas de alguns recursos do App Engine e de bibliotecas de terceiros. Certifique-se de atualizar as versões incluídas e importadas no aplicativo e de testar o aplicativo extensivamente após o upgrade. A lista abaixo identifica os principais problemas de compatibilidade e aponta para outros recursos a fim de resolvê-los:

Solicitações simultâneas e WSGI

O recurso do Python 2.7 que mais afeta o design e o desempenho do aplicativo é a compatibilidade com aplicativos de multissegmentação que gerenciam solicitações simultâneas. A capacidade de gerenciar solicitações simultâneas resulta na melhoria da utilização e aprimoramento significativo do desempenho do aplicativo, especialmente para aplicativos que usam classes de instâncias mais elevadas que exploram diversos núcleos de CPU.

Para ativar a multissegmentação, os aplicativos precisam migrar da abordagem baseada na Common Gateway Interface (CGI) dos ambientes de execução anteriores no Python para uma abordagem baseada na interface de gateway do servidor da Web (WSGI). Isso ocorre porque os scripts CGI, projetados para gerenciar solicitações em série, dependem de variáveis de ambiente para acesso aos streams de entrada e saída.

Embora o modelo da WSGI para gerenciar solicitações dê aos aplicativos acesso mais direto aos streams de entrada e saída, permitindo solicitações simultâneas, gerenciar diversas solicitações em paralelo causa uma disputa quando a lógica de um gerenciador de solicitação depende de ou interage com dados maiores do que o escopo local, por exemplo, o estado do aplicativo. Por esse motivo, é importante codificar defensivamente para lidar com disputas e garantir que seu novo aplicativo WSGI seja thread-safe.

Para mais detalhes, veja Como tornar seu aplicativo thread-safe.

Como atualizar o app.yaml

O Python 2.7 requer um elemento especial de configuração runtime no cabeçalho de app.yaml. O elemento threadsafe: [ true | false ] é necessário para aplicativos Python 2.7. Se for true, o App Engine enviará solicitações simultaneamente. Se for false, o App Engine os enviará em série. O seguinte cabeçalho app.yaml permite solicitações simultâneas:

application: myapp
version: 1
runtime: python27
api_version: 1
threadsafe: true
...

Como usar a WSGI

O ambiente de execução do Python 2.7 permite executar diretamente um aplicativo da interface de gateway do servidor da Web (WSGI, na sigla em inglês), em vez de usar o adaptador run_wsgi_app para executar o programa como um script CGI. Para fazer isso, substitua o manipulador CGI (por exemplo, myapp.py) em app.yaml com um nome de aplicativo WSGI (por exemplo, myapp.app).

...
handlers:
- url: /.*
  script: myapp.app
...

É preciso também mover o objeto do aplicativo WSGI para o escopo global:

import webapp2

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/plain'
    self.response.out.write('Hello, WebApp World!')

app = webapp2.WSGIApplication([('/', MainPage)])

""" Old code:
def main():
  run_wsgi_app(app)

if __name__ == '__main__':
  main()
"""

Além disso, é possível especificar gerenciadores de scripts CGI no app.yaml. No entanto, as solicitações gerenciadas por scripts CGI são processadas em série, não simultaneamente. Além disso, não é possível ter um arquivo app.yaml que misture scripts CGI e aplicativos WSGI e não é possível definir threadsafe como true se você definir qualquer gerenciador CGI.

Algumas convenções de ambientes de execução anteriores do Python, como o uso de main() e a verificação de __name__ == 'main', foram suspensas. Essas medidas ajudavam os scripts CGI anteriores a permanecer em cache, mas agora que os aplicativos WSGI estão sendo executados diretamente, essas etapas não são mais necessárias.

Como usar o diretório raiz do aplicativo

No Python 2.5, os scripts CGI eram executados com o diretório de trabalho atual configurado como o diretório que continha o script. Isso foi alterado no Python 2.7. Com a WSGI, o diretório de trabalho atual no início do tempo de vida do gerenciador da solicitação é o diretório raiz do aplicativo.

Revise seu código de aplicativo e verifique se todos os gerenciadores estão escritos para esperar que o diretório de trabalho atual seja a raiz do aplicativo.

Como configurar bibliotecas

O ambiente de execução do Python 2.7 inclui alguns módulos de terceiros. Alguns estão disponíveis por padrão. Outros estão disponíveis apenas quando configurados. Especifique qual versão você quer usar.

libraries:
- name: PIL
  version: "1.1.7"
- name: webob
  version: "1.1.1"

Especifique que o aplicativo use a versão mais recente do módulo. Isso é útil para desenvolver um aplicativo que ainda não tem usuários, Não é preciso rastrear novas versões. Caso o aplicativo esteja sendo usado ativamente, cuidado. Talvez você se surpreenda ao constatar que seu aplicativo começou a usar uma nova versão de biblioteca não compatível com versões anteriores. Para usar a versão mais recente:

libraries:
- name: PIL
  version: latest

Para uma lista de bibliotecas suportadas, veja Bibliotecas de terceiros.

Como tornar seu aplicativo thread-safe

O gerenciamento de solicitações simultâneas é simples quando cada gerenciador interage apenas com variáveis dentro do respectivo escopo. No entanto, ele se torna complicado quando um gerenciador modifica recursos enquanto outro faz a leitura deles. Ao garantir o comportamento esperado do seu aplicativo, mesmo que diversas solicitações estejam manipulando os mesmos dados e interferindo umas nas outras - você torna seu aplicativo "thread-safe".

A regra principal ao projetar um aplicativo para se tornar thread-safe é limitar o uso de recursos compartilhados, como informações de estado ou variáveis globais, com a maior frequência possível. Entretanto, geralmente não é possível descartar completamente este uso, e é aí que entram mecanismos de sincronização, como objetos de bloqueio.

No Python 2.7, você tem acesso à biblioteca de threads do Python. Isso permite declarar um bloqueio em um bloco de lógica, fazendo com que o código seja executado em série em vez de simultaneamente. Pense no seguinte código:

class Configuration(ndb.Model):
  some_config_data = ndb.StringProperty()
  _config_cache = None
  _config_lock = threading.Lock()
  @classmethod
  def get_config(cls):
    with cls._config_lock:
      if not cls._config_cache:
        cls._config_cache = cls.get_by_id('config')
    return cls._config_cache

Esse código mostra a criação de um cache de algumas variáveis de configuração globais em uma variável chamada _config_cache. Aqui, o uso de um objeto de bloqueio chamado _config_lock garante que a verificação de um _config_cache preexistente se comporte de maneira confiável. Caso contrário, essa variável poderá perder tempo fazendo várias viagens ao Datastore para definir a mesma variável várias vezes com os mesmos dados, porque todas as solicitações concorrentes descobriram que _config_cache estava vazio.

Pense bem ao utilizar bloqueios. Um bloqueio trava todos os outros threads que executam esse método. Isso se torna um gargalo no desempenho.

Como atualizar seu aplicativo para webapp2

Observação: se você não estiver usando webapp como gerenciador de solicitações, ignore esta seção.

O framework da Web incluído no ambiente de execução do Python 2.7 foi atualizado de webapp para webapp2. Dentre outras coisas, o webapp2 promove a melhoria do roteamento de URIs e gerenciamento de exceções, um objeto de resposta completo e um mecanismo de despacho mais flexível.

O uso de modelos webapp foi suspenso. Substitua-os por Jinja2 (em inglês), Djangoou por um sistema de modelos de sua escolha, desde que ele esteja programado em Python puro.

No App Engine, webapp2 tem o alias webapp, e webapp2 é compatível com versões anteriores. No entanto, após o upgrade, ainda será preciso testar completamente seu aplicativo e se familiarizar com a nova sintaxe e os recursos (em inglês) do webapp2, em vez de continuar a depender da compatibilidade com versões anteriores.

E seu upgrade está completo!

Após fazer o upload do aplicativo, é preciso testá-lo extensivamente para garantir a compatibilidade com versões anteriores. Se você tiver problemas, confira os fóruns.