Bug ou comportamento indesejado?

Postado por Osvaldo Santana

Estou trabalhando na construção do pacote do Python 2.4.2 para a plataforma Maemo e uma das nossas missões nesse projeto é fazer com que os pacotes com o Python ocupem pouco espaço em disco. Essa missão vem do fato que a plataforma Maemo é projetada para dispositivos móveis que não costumam ser construídos com discos muito grande.

Para reduzir essa ocupação de espaço resolvemos distribuir apenas os módulos otimizados (.pyo) da biblioteca Python porque esses arquivos são menores que os seus equivalentes em código fonte (.py) que serão distribuídos em um pacote separado específico para desenvolvedores. Outra mudança que fizemos foi distribuir esses pacotes dentro de um arquivo .zip.

No entanto, descobrimos posteriormente que o FS do N770 já é comprimido e colocar os módulos dentro desse .zip se tornou desnecessário. Enquanto eu ‘tirava’ os módulos de dentro do ZIP eu esbarrei numa inconsistência no comportamento do CPython que vou ilustrar na seção abaixo:

  1. Primeiramente eu crio dois módulos compilados. Um deles com otimização e o outro sem e adiciono os mesmos dentro de um ZIP:
    $ ls
    modulo_c.pyc  modulo_o.pyo
    $ zip modulos.zip modulo_o.pyo modulo_c.pyc
      adding: modulo_o.pyo (deflated 38%)
      adding: modulo_c.pyc (deflated 38%)
    $ ls
    modulo_c.pyc  modulo_o.pyo  modulos.zip
    
  2. Depois aciono o interpretador em modo normal (não-otimizado):
    $ python2.4
    >>> import modulo_c
    modulo_c
    >>> import modulo_o
    ImportError: No module named modulo_o

    Como puderam observar, o interpretador Python não procura arquivos com a extensão .pyo quando está em modo não-otimizado.

  3. Na seqüência eu aciono o interpretador em modo otimizado:
    $ python2.4 -O
    >>> import modulo_c
    ImportError: No module named modulo_c
    >>> import modulo_o
    modulo_o

    E o comportamento inverso pode ser observado. O interpretador também não procura módulos .pyc quando está em modo otimizado.

  4. Removo os módulos .pyc e .pyo para ficar com eles apenas dentro do Zip e repito os passos anteriores dizendo que o ‘modulos.zip’ agora faz parte do PYTHONPATH e deve servir de local para procura de módulos Python:
    $ rm *.pyc *.pyo
    $ ls
    modulos.zip
    $ PYTHONPATH=modulos.zip python2.4
    >>> import modulo_c
    modulo_c
    >>> import modulo_o
    modulo_o
    $ PYTHONPATH=modulos.zip python2.4 -O
    >>> import modulo_c
    modulo_c
    >>> import modulo_o
    modulo_o

Aqui está a inconsistência. Utilizando o hook zipimport do Python ele procura por módulos .pyc e .pyo no PYTHONPATH. A única distinção que ele faz entre os dois modos é a de que no modo normal o interpretador procura na ordem “py->pyc->pyo” e no modo otimizado ele procura na ordem “py->pyo->pyc”.

Acho que essa inconsistência tem que ser eliminada e, em minha humilde opinião o comportamento do hook zipimport é mais adequado do que o do primeiro porque poderemos encontrar casos onde bibliotecas bytecode sejam fornecidas como .pyo e .pyc misturados (ok, eu sei que só renomear o arquivo já que o bytecode é o mesmo, mas não acho essa solução muito ‘elegante’).

Estou preparando um patch para deixar o comportamento do hook de importação padrão do Python funcione de maneira equivalente ao hook zipimport e vou submetê-lo para o projeto. Mas como esse patch tem uma solução baseada na minha visão eu gostaria de saber antes a opinião dos leitores: Qual dos 2 comportamentos deve permanecer? E, isso deve ser mudado?


9 Responses to “Bug ou comportamento indesejado?”

  1. Sidnei da Silva Says:

    Realmente esse comportamento nao eh consistente.

    Eu concordo que o comportamento do zipimport eh o mais adequado.

    Eu ja tropecei no mesmo problema mas nao tinha notado que o zipimport se comportava de forma diferente. Seria otimo se isso fosse consertado.

  2. Roger Says:

    Trackback to Internet Tablet Users blog: http://www.internettablettalk.com/blog/?p=130

  3. Osvaldo Santana Neto Says:

    Sidnei,

    Eu criei um patch de sugestão em
    http://pymaemo.sourceforge.net/cgi-bin/moin.cgi/OsvaldoSantanaNeto

    Roger,

    Thanks for the quote in your blog. I’ll try to publish my posts in english in near future to make reader’s life easier :)

  4. Gustavo Sverzut Barbieri Says:

    Eu também acho o comportamento incoerente.

    Sobre o Patch, legal, mas alguns comentários que podem te ajudar a tê-lo aceito:


    - if (strcmp(filetab->suffix, “.pyc”) == 0)
    + if (strcmp(filetab->suffix, “.pyc”) == 0) {
    filetab->suffix = “.pyo”;
    + continue;
    + }
    + if (strcmp(filetab->suffix, “.pyo”) == 0) {
    + filetab->suffix = “.pyc”;
    + continue;
    + }

    pode ser substituído por:


    + else if (strcmp(filetab->suffix, “.pyo”) == 0)
    + filetab->suffix = “.pyc”;

    eliminando os “continue“.

    Depois, tem algo não relevante, em “/* Try .py */” juntamente com a linha em branco acima. Idem para “/* Try pyo/pyc */” e as mudanças em whitespace no bloco todo! Aliás, a repetição deste bloco deveria ser feita dentro do primeiro, para os valores diferentes “(!Py_OptimizeFlag)“, você está conferindo a mesma coisa duas vezes! :-).

    Tirar o “/* XXX INDT */” ajuda :-)

    strcpy() is harmful! Troque por:


    strncpy(module_filename, filename, MAXPATHLEN);
    module_filename[ MAXPATHLEN ] = ”; /* vide man strncpy por que */

    com isso a comparação “strlen(module_filename) ” torna-se sempre verdadeira (no seu código atual se ela for falsa –> SEGFAULT!)

    Então você deve trocar a comparação por MAXPATHLEN-1, para caber o “c” ou “o” da extensão.

    Uma pequena optimização nesta última parte é fazer:


    size_t l = strlen( module_filename );

    if ( l

    eliminando, assim, cópia desnecessária das strings e ainda chamadas de função.

    Valeu!

  5. Osvaldo Santana Neto Says:

    Aqui não é um local muito agradável para discutir patches mas vamos lá :)
    Já mudei o patch para usar ‘else if’ e tirei os continues. Pra você ver como fazer um patch ‘nas coxas’ só aumenta o trabalho :)
    Não entendi o que você quis dizer no parágrafo que fala sobre espaços em branco e sobre os testes duplicados (criei uma thread lá na lista, vamos mudar a discussão pra lá?)

    strcpy(): Eu sei que é harmful, mas mantive a mesma construção do original. Sim, o import.c original usa strcpy() e a verificação de “strlen()

  6. Osvaldo Santana Neto Says:

    Ah! e eu comentei no meu e-mail que iria retirar as referências à INDT do patch :P :)

  7. Gustavo Sverzut Barbieri Says:

    Qual lista você mandou o email? Na python brasil ainda não chegou nada.

    Bom, manda o patch renovado para lá que eu vejo o que ficou “faltando” :-)

  8. Osvaldo Santana Neto Says:

    Ok, vou mandar pra lá, mas já chegou na lista sim:

    http://thread.gmane.org/gmane.comp.python.brasil/12593

  9. Roger Says:

    Is the work you are doing going to apply to the S60 smartphones too? From the announcements yesterday, it seems that Nokia is settling on python as its language of choice.

    Alas for me. I am one of those who found python hazy and ruby clear, so I turned down the ruby path and know nothing of python.

    Roger

Deixe um comentário