Pacote Python modelo

Introdução

O Python como as outras maiores linguagens também possui a forma de distribuição de seus programas (.egg), e além desta forma também pode ser distribuído pela rede através de repositórios Python Package Index (PyPI).

Os pacotes para distribuição existem em quase todas as linguagens conhecidas, C++ (.o,.so,.dll), Java (.jar), Delphi(.exe) e outras, com a finalidade de facilitar a distribuição dos aplicativos criados.

Escopo

Será apresentado como criar um pacote padrão, com estrutura e descrição do pacote.

Andamento

Primeiro o programa tem que existir.

Usaremos funções Void para representar o programa.

Programa mypackage-0.0.1:

  1. Criar estrutura do programa:
    $ mkdir -pv programa/mypackage/{foo,bar}
    mkdir: created directory ‘programa’
    mkdir: created directory ‘programa/mypackage’
    mkdir: created directory ‘programa/mypackage/foo’
    mkdir: created directory ‘programa/mypackage/bar’
    
    A estrutura fica assim:
    $ tree programa/
    programa/
    └── mypackage
        ├── bar
        └── foo
    
  2. Criandar o programa (Void) Vamos tabalhar dentro do diretório programa/.
    $ cd programa
    
    $ $ cat > mypackage/bar/barfunctions.py << eof
    > def bar1():
    >     pass
    > def bar2():
    >     pass
    > def bar3():
    >     pass
    > eof
    
    $ cat > mypackage/foo/foofunctions.py << eof
    def foo1():
        pass
    def foo2():
        pass
    def foo3():
        pass
    eof
    
    A estrutura atualizada:
    $ tree mypackage/
    mypackage/
    ├── bar
    │   └── barfunctions.py
    └── foo
        └── foofunctions.py
    
  3. setup.py

    Agora após o programa criado e testado, vem a parte interessante.

    Criar o arquivo programa/setup.py com o conteúdo abaixo:

    Este arquivo possui configuração para instalação automática do seu programa, que poderá ser utilizando o python, easy_install ou pip.

    Das linhas 5 a 11, são variáveis que coloquei para facilitar a edição deste arquivo, que é modelo para qualquer aplicativo Python.

    Para utiliza-lo em outro programa basta modificar NAME(5), DESCRIPTION(7), AUTHOR(8), AUTHOR_EMAIL(9), URL(10), e talvés estas LICENSE(11), install_requires(39), classifiers(44)

    A estutrutura atualizada fica assim:

    $ tree .
    .
    ├── mypackage
    │   ├── bar
    │   │   └── barfunctions.py
    │   └── foo
    │       └── foofunctions.py
    └── setup.py
    

  4. MANIFEST.in

    O arquivo programa/MANIFEST.in indica ao instalador, quais arquivos fazem parte do pacote, e o quê deverá ser usado durante a instalação.
    $ cat > MANIFEST.in << eof
    > graft src/
    > graft docs/
    > recursive-include mypackage *
    > include *.cfg *.in *.md *.rst *.txt
    > eof
    
    em recursive-include mypackage *, mypackage é o nome do seu programa, altere quando reutilizar este arquivo.

    A estutrutura atualizada fica assim:

    $ tree .
    .
    ├── MANIFEST.in
    ├── mypackage
    │   ├── bar
    │   │   └── barfunctions.py
    │   └── foo
    │       └── foofunctions.py
    └── setup.py
    
  5. __init__.py

    Este é o ultimo arquivo obrigatório.

    Necessário para funcionamento do pacote de distribuição, e está localizado dentro de cada subdiretório do programa.

    Ele indica onde encontrar os métodos do seu programa.

    Para encontrar os métodos, ou funções, vamos usar o comando grep. Quem estiver usando Window, faça manualmente.

    $ grep -r def
    mypackage/bar/barfunctions.py:def bar1():
    mypackage/bar/barfunctions.py:def bar2():
    mypackage/bar/barfunctions.py:def bar3():
    mypackage/foo/foofunctions.py:def foo1():
    mypackage/foo/foofunctions.py:def foo2():
    mypackage/foo/foofunctions.py:def foo3():
    

    Agora usando 'shell script', vamos formatar a exibição para a nossa necessidade.

    $ P=mypackage; grep -r def $P|sed "s|$P/|from $P.|; s|/|.|; s|.py:def| import|; s|(.*||"
    from mypackage.bar.barfunctions import bar1
    from mypackage.bar.barfunctions import bar2
    from mypackage.bar.barfunctions import bar3
    from mypackage.foo.foofunctions import foo1
    from mypackage.foo.foofunctions import foo2
    from mypackage.foo.foofunctions import foo3
    

    Em posse dos métodos, criamos os arquivos __init__.py

    $ cat > mypackage/bar/__init__.py << eof
    > from mypackage.bar.barfunctions import bar1
    > from mypackage.bar.barfunctions import bar2
    > from mypackage.bar.barfunctions import bar3
    > eof
    
    $ cat > mypackage/foo/__init__.py << eof
    > from mypackage.foo.foofunctions import foo1
    > from mypackage.foo.foofunctions import foo2
    > from mypackage.foo.foofunctions import foo3
    > eof
    
    $ cat > mypackage/__init__.py << eof
    > __version__ = '0.0.1'
    > eof
    

    A estutrutura atualizada fica assim:

    $ tree
    .
    ├── MANIFEST.in
    ├── mypackage
    │   ├── bar
    │   │   ├── barfunctions.py
    │   │   └── __init__.py
    │   ├── foo
    │   │   ├── foofunctions.py
    │   │   └── __init__.py
    │   └── __init__.py
    └── setup.py
    
  6. README.rst

    O arquivo programa/README.rst, deve conter informações sobre o seu programa.

    Neste modelo ele ficará em branco.

    $ > README.rst
    
  7. CONTRIBUTORS.rst

    O arquivo programa/CONTRIBUTORS.rst, a lista com os dados de contato de todos que contribuem para o desenvolvimento de seu programa.

    Neste modelo ele ficará em branco.

    $ > CONTRIBUTORS.rst
    
  8. CHANGES.rst

    O arquivo programa/CHANGES.rst, o registro de mudanças e atualizações ocorridas durante o desenvolvimento de seu programa.

    Neste modelo ele ficará em branco.

    $ > CHANGES.rst
    

    A estutrutura final do mypackage-0.0.1:

    
    $ tree
    .
    ├── CHANGES.rst
    ├── CONTRIBUTORS.rst
    ├── MANIFEST.in
    ├── mypackage
    │   ├── bar
    │   │   ├── barfunctions.py
    │   │   └── __init__.py
    │   ├── foo
    │   │   ├── foofunctions.py
    │   │   └── __init__.py
    │   └── __init__.py
    ├── README.rst
    └── setup.py
    

Esta foi a estrutura básica. Agora vamos dar uma incrementada.

Programa mypackage-0.1.0:

A partir do mypackage-0.0.1, vamos fazer algumas modificações.

  1. mypackage/__init__.py
    $ cat > mypackage/__init__.py << eof
    import os
    > __version__ = open(os.path.join("mypackage","version.txt")).read().strip()
    > eof
    

    Isto fará que o '__version__' receba o seu valor do arquivo 'mypackage/version.txt'

  2. mypackage/version.txt

    Este arquivo não exite na versão 0.0.1. Vamos cria-lo com o comando abaixo:

    cat > mypackage/version.txt << eof
    > 0.1.0
    > eof
    

    Agora para saber a versão basta acessar o 'mypackage/version.txt', como todo os programas que acessamos os fontes.

    E para reutilizar estes códigos, lembrem-se de alterar o arquivo '__init__.py' como o nome do pacote.

    A estutrutura final do mypackage-0.1.0:

    $ tree
    .
    ├── CHANGES.rst
    ├── CONTRIBUTORS.rst
    ├── MANIFEST.in
    ├── mypackage
    │   ├── bar
    │   │   ├── barfunctions.py
    │   │   └── __init__.py
    │   ├── foo
    │   │   ├── foofunctions.py
    │   │   └── __init__.py
    │   ├── __init__.py
    │   └── version.txt
    ├── README.rst
    └── setup.py
    

Programa mypackage-1.0.0:

A partir do mypackage-0.1.0, vamos fazer Novas modificaçôes. E diminuir a quantidade de arquivos para alterar durante a criação de um novo pacote.

O arquivo 'mypackage/__init__.py', possui o conteúdo abaixo:

$ cat mypackage/__init__.py

import os
__version__ = open(os.path.join("mypackage","version.txt")).read().strip()

Altere para:

$ cat mypackage/__init__.py

import os
__version__ = open(os.path.join(os.path.dirname(__file__), *rnames)).read()

Com esta alteração, o arquivo '__init__.py', não precisará ser modificado para cada empacotamento.

Arquivos para estudo

  • 0.0.1 zip:
    wget https://gitlab.com/development-incolume/programa/repository/archive.zip?ref=0.0.1 -O mypackage-0.0.1.zip
  • 0.0.1 tgz:
    wget https://gitlab.com/development-incolume/programa/repository/archive.tar.gz?ref=0.0.1 -O mypackage-0.0.1.tar.gz
  • 0.0.1 git:
    git clone --depth 1 -b 0.0.1 https://gitlab.com/development-incolume/programa.git

  • 0.1.0 zip:
    wget https://gitlab.com/development-incolume/programa/repository/archive.zip?ref=0.1.0 -O mypackage-0.1.0.zip
  • 0.1.0 tgz:
    wget https://gitlab.com/development-incolume/programa/repository/archive.tar.gz?ref=0.1.0 -O mypackage-0.1.0.tar.gz
  • 0.1.0 git:
    git clone --depth 1 -b 0.1.0 https://gitlab.com/development-incolume/programa.git
  • 1.0.0 zip:
    wget https://gitlab.com/development-incolume/programa/repository/archive.zip?ref=1.0.0 -O mypackage-1.0.0.zip
  • 1.0.0 tgz:
    wget https://gitlab.com/development-incolume/programa/repository/archive.tar.gz?ref=1.0.0 -O mypackage-1.0.0.tar.gz
  • 1.0.0 git:
    git clone --depth 1 -b 1.0.0 https://gitlab.com/development-incolume/programa.git

Referências

Comentários