Skip to content

9. As importações

O erro encontrado na versão 1 do exercício prático leva-nos a aprofundar o papel da instrução [import].

Image

9.1. Scripts [import_01]

O script [imported] será importado por vários scripts (também denominados módulos):

Image


# módulo importado
# esta instrução será executada sempre que o módulo for importado
print("2")
# variável pertencente ao módulo importado
x=4

Um módulo é executado quando é importado. Assim, quando o módulo [imported] for importado:

  • a linha 3 será apresentada;
  • a variável x da linha 5 receberá o seu valor;

O script [main_01] é o seguinte:


# um módulo importado é executado
import imported
# utilização da variável x do módulo importado
print(imported.x)
  • linha 2: o módulo [imported] é importado. Isto provocará a sua execução:
    • o valor 2 será exibido;
    • a variável x é criada com o valor 4;
  • linha 4: utiliza-se a variável x do módulo importado;

No PyCharm, é sinalizado um erro:

No [1], o PyCharm indica que não reconhece o módulo [imported]. Em termos técnicos, isto significa que a pasta que contém o módulo [imported] não se encontra no Python Path do PyCharm. O Python Path é o conjunto de pastas nas quais os módulos importados são procurados. Para resolver este problema, basta indicar ao [Sources root] a pasta onde se encontra o módulo [imported], neste caso a pasta [import/01]:

Image

Image

Após esta operação, a pasta [import/01] é adicionada ao Python Path do Pycharm e o erro desaparece:

Image

  • em [1], a pasta [01] mudou de cor;
  • em [2-3], já não há erro;

Os resultados da execução são os seguintes:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/01/main_01.py
2
4

Process finished with exit code 0

Comentários

  • a linha 2 é o resultado da execução do módulo importado;
  • a linha 3 apresenta o valor da variável x do módulo importado;

Deste exemplo, fica a retê-se o conceito importante de que um módulo (ou um script) importado é executado.

O script [main_02] é o seguinte:


# importa-se a variável x do módulo importado
from imported import x
# é exibida
print(x)
  • Na linha 2, temos outra sintaxe de importação: [from module import objet1, objet2, …]. Aqui, importamos a variável [imported.x]. Com esta sintaxe, a variável x torna-se uma variável do script [main_02]. Já não é necessário prefixá-la com o seu módulo [imported];
  • linha 4: exibe-se a variável x de [main_02];

Os resultados da execução são os seguintes:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/01/main_02.py
2
4

Process finished with exit code 0

O script [main_03] é o seguinte:


# importa-se tudo o que está visível do módulo importado
from imported import *
# utiliza-se a variável x do módulo importado
print(x)

A notação [import *] na linha 2 significa que se importam todos os objetos visíveis do módulo importado (variáveis, funções).

Os resultados são os seguintes:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/01/main_03.py
2
4

Process finished with exit code 0

O script [main_04] é o seguinte:


# importa-se a variável x do módulo importado
# e renomeia-a para y
from imported import x as y
# exibe-se a variável y
print(y) 

A linha 3 mostra que é possível importar um objeto do módulo importado e atribuir-lhe um alias. Aqui, a variável [imported.x] passa a ser a variável [main_04.y]. Os resultados são os mesmos que anteriormente.

9.2. Script [import_02]

Image

O módulo importado [module1.py] é o seguinte:


# uma função
def f1():
    print("f1")

O módulo importado define uma função, o que é frequente.

O script [main_01] é o seguinte:


# import
import module1
# execução da função f1
module1.f1()
  • na linha 2, o módulo é importado. Vai ser executado. Aqui, não apresenta nada;
  • linha 4: a função [f1] do módulo importado é executada;

Os resultados da execução são os seguintes:

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/02/main_01.py
f1

Process finished with exit code 0

Nota: Para evitar que a função PyCharm sinalize um erro na importação da linha 2, é necessário colocar a pasta que contém a função [module1] dentro da pasta [Sources Root] da função PyCharm:

Image

No [1], o ficheiro [02] inserido no [Sources Root] ficou a azul. Note-se que o erro assinalado não impede, neste caso, a execução correta dos scripts. Com efeito, durante a execução do script [main_0x], a pasta do script é automaticamente adicionada ao Python Path. Assim, o [module1] é encontrado. A partir de agora, quando numa captura de ecrã uma pasta estiver a azul, significa que foi adicionada ao Python Path do [Sources Root] a partir do PyCharm.

O script [main_02] é o seguinte:


# importar
from module1 import f1
# execução de f1
f1()
  • a linha 2 importa a função [f1] do módulo [module1];
  • na linha 4, utiliza-se a função f1;

Os resultados são idênticos aos do script [main_01].

9.3. Scripts [import_03]

Image

Nota: O [03] encontra-se no [Sources Root] do projeto.

Os novos scripts irão importar o módulo [module2], que não se encontra na mesma pasta que eles.

O script [module2] é o seguinte:


# uma função
def f2():
    print("f2")

O script define, portanto, uma função [f2].

O script [main_01] é o seguinte:


# importação do módulo Class2
import dir1.module2
# execução f2
dir1.module2.f2()
  • linha 2: utiliza-se uma notação especial para indicar como localizar o módulo [module2]. O [dir1.module2] deve ser interpretado como o caminho [dir1/module2]: para encontrar o [module2], parte-se da pasta do script atual [main_01], depois passa-se para o [dir1] e aí encontra-se o [module2]. Não se deve esquecer que o ponto de partida do caminho é a pasta do script que está a ser importado;
  • linha 4: para executar a função [f2] a partir de [module2];

Os resultados são os seguintes:

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/03/main_01.py
f2

Process finished with exit code 0

Linha 2, o resultado da função [f2].

O script [main_02] é o seguinte:


# importação do módulo dir1.module2, que é renomeado
import dir1.module2 as module2
# execução de f2
module2.f2()

Na linha 2, renomeia-se o módulo [dir1.module] para simplificar a escrita da linha 4.

O script [main_03] é o seguinte:


# importação da função f2 do módulo dir1.module2
from dir1.module2 import f2
# execução da função f2
f2()

Desta vez, na linha 2, importamos apenas a função [f2], que passa a ser uma função do script [main_03] (linha 4).

Todos estes scripts funcionam tanto no contexto do PyCharm como no de uma consola Python. A razão é que, em ambos os casos, a pasta do script executado — neste caso, a pasta [03] — faz parte do Python Path. Assim, a pasta [dir1/module2] é encontrada.

9.4. Scripts [import_04]

Image

Aqui, as pastas [dir1] e [dir2] foram colocadas na pasta [Sources Root] do projeto PyCharm.

O primeiro módulo importado é o [module3]:


# uma função
def f3():
    print("f3")

O segundo módulo importado é o [module4]:


from module3 import f3

# uma função
def f4():
    f3()
    print("f4")
  • na linha 1, importa-se a função [f3] a partir de [module3]. Aqui, a função [module3] está visível porque a sua pasta [dir1] foi colocada dentro da pasta [Sources Root];
  • linhas 4-6: define-se uma função [f4] que chama a função [f3] da função [module3];

O script principal [main_01] é o seguinte:


# importação do módulo4
from module4 import f4
# execução f4
f4()
  • na linha 2, importa-se o módulo [module4]. Este está visível porque a sua pasta [dir2] foi colocada na pasta [Sources Root] de PyCharm;
  • linha 4: execução da função [f4] de [module4];

Os resultados da execução de [main_01] em PyCharm são os seguintes:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/04/main_01.py
f3
f4

Process finished with exit code 0

Agora, vamos executar a função [main_01] num terminal (consola) Python:

Image

Os resultados são os seguintes:

1
2
3
4
5
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\04>python main_01.py
Traceback (most recent call last):
  File "main_01.py", line 2, in <module>
    from module4 import f4
ModuleNotFoundError: No module named 'module4'

O que aconteceu? O terminal Python não tem conhecimento do Python Path nem dos ficheiros [Sources Root] e PyCharm. Tem o seu próprio Python Path. Neste, está sempre presente a pasta do script que está a ser executado, neste caso o script [main_01]. Por isso, conhece a pasta [import/04]. No script executado, encontra a linha:


from module4 import f4

O interpretador Python procura por [module4] nas pastas do seu Python Path. No entanto, o [module4] não se encontra no [import/04] — que, por sua vez, está sim no Python Path — mas sim no [import/04/dir2], que não se encontra nesse caminho. Daí o erro.

Temos, portanto, um problema já encontrado anteriormente: um script que se executa corretamente no PyCharm pode falhar no contexto de um terminal Python. Trata-se de um problema recorrente que teremos de resolver.

9.5. Scripts [import_05]

Image

Nota: as pastas [dir1] e [dir2] são adicionadas ao Python Path. É de salientar que existe aqui um conflito: os ficheiros [module3] e [module4] serão encontrados em dois locais do Python Path do PyCharm:

  • em [import/04/dir1] e [import/05/dir1] para [module3];
  • em [import/04/dir2] e [import/05/dir2] para [module4];

É então possível extrair [import/04/dir1] e [import/04/dir2] dos [Sources Root] do projeto PyCharm. Acontece que, neste caso, o [import/05/dir1] é uma cópia do [import/04/dir1] (o mesmo se aplica ao [dir2]) e, por isso, não há qualquer problema. No entanto, é importante referir que, no próprio ficheiro PyCharm, é necessário prestar atenção à lista de pastas do ficheiro [Sources Root], a fim de evitar conflitos.

O script [main_01] passa a ser o seguinte:


import sys
# altera-se o sys.path para incluir as pastas
# que contêm as classes a importar
sys.path.append(".")
sys.path.append("./dir1")
sys.path.append("./dir2")
# importar o módulo4
from module4 import f4
# execução f4
f4()

Estamos a tentar resolver o problema do Python Path. Queremos um que funcione tão bem no PyCharm como num terminal Python. Para isso, vamos resolver o problema nós próprios.

  • linhas 4-6: adicionamos as pastas [., ./dir1, ./dir2] ao Python Path. Para que isto funcione, é necessário que a pasta atual no momento da execução seja a pasta [import/05]. Isto será verdade no PyCharm, mas não necessariamente num terminal Python, como veremos;
  • linha 8: importa-se o [module4]. Tendo em conta o que acabámos de fazer, este deverá ser encontrado no [./dir2];

A execução em PyCharm dá os seguintes resultados:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/main_01.py
f3
f4

Process finished with exit code 0

Agora, num terminal Python:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\05>python main_01.py
f3
f4

Na linha 1, a pasta de execução é [import/05].

Agora, subamos um nível na árvore de diretórios de [import/05]:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\05>cd ..

(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 05/main_01.py
Traceback (most recent call last):
  File "05/main_01.py", line 8, in <module>
    from module4 import f4
ModuleNotFoundError: No module named 'module4'
  • linha 2: quando o [main_01] é executado, já não estamos na pasta [import/05], mas sim na [import]. No entanto, escrevemos:

sys.path.append(".")
sys.path.append("./dir1")
sys.path.append("./dir2")

Isto adiciona ao Python Path as pastas [import, import/dir1, import/dir2], o que não é de todo o que pretendemos. Note-se que adicionar ao Python Path pastas que não existem (import/dir1, import/dir2) não provoca erros.

Fizemos progressos, mas ainda não é suficiente. É necessário adicionar ao Python Path, não caminhos relativos, mas sim caminhos absolutos.

O script [main_02] é uma variante do [main_01] que utiliza um ficheiro de configuração [config.json]:


{
  "dependencies": [
    "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/dir1",
    "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/dir2"
  ]
}

O valor da chave [dependencies] é a lista de pastas a adicionar ao Python Path. Note-se que, neste caso, foram utilizados nomes absolutos e não nomes relativos.

O script [main_02] utiliza o ficheiro [config.json] da seguinte forma:


import codecs
import json
import sys

# ficheiro de configuração
config_filename="C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/05/config.json"
# leitura do ficheiro de configuração JSON
with codecs.open(config_filename, "r", "utf-8") as file:
    config = json.load(file)

# alteração do sys.path
for directory in config['dependencies']:
    sys.path.append(directory)

# importação do módulo4
from module4 import f4
# execução de f4
f4()

  • linha 6: repare que foi utilizado o nome absoluto do ficheiro de configuração;
  • linhas 8-9: o ficheiro de configuração é lido. É criado um dicionário [config] (linha 9) com o seu conteúdo;
  • linhas 11-13: adicionam-se os elementos da tabela [config['dependencies']] ao Python Path. Note-se que, uma vez que foram inseridos nomes absolutos de pastas no [config.json], são adicionados nomes absolutos ao Python Path;
  • linha 16: o [module4] é importado. Deverá ser encontrado, uma vez que agora o [dir2] se encontra no Python Path;

A execução produz os mesmos resultados que para [main_02], exceto que o script continua a funcionar quando a pasta de execução já não é [import/05]:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 05/main_02.py
f3
f4

Na linha 1, a pasta de execução é [import].

Fizemos progressos. Vimos que:

  • que precisávamos de construir o Python Path nós próprios;
  • que era necessário incluir nele os nomes absolutos de todas as pastas que contêm os módulos importados pela aplicação;

No entanto, colocar nomes absolutos nos scripts não é uma solução. Assim que o projeto for transferido para outro local, deixa de funcionar. Temos de encontrar outra solução.

9.6. Scripts [import_06]

Image

Nota: as pastas [06, dir1, dir2] foram colocadas nas pastas [Sources Root] do projeto PyCharm. As pastas [dir1, dir2] são idênticas às dos exemplos anteriores.

O ficheiro [config.json] é o seguinte:


{
  "rootDir": "C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06",
  "relativeDependencies": [
    "dir1",
    "dir2"
  ],
  "absoluteDependencies": [
   ]
}

Introduzimos dois tipos de caminhos:

  • caminhos absolutos, linhas 7-8;
  • caminhos relativos, linhas 3-6. Estes são relativos à raiz da linha 2. Assim, quando o projeto for movido para outro local, apenas esta linha terá de ser alterada;

O script [utils.py] utiliza o ficheiro [config.json] e define o Python Path:


# importações
import codecs
import json
import os
import sys

# configuração da aplicação
def config_app(config_filename: str) -> dict:
    # config_filename: nome do ficheiro de configuração
    # permitir que as exceções sejam reportadas

    # processamento do ficheiro de configuração
    with codecs.open(config_filename, "r""utf-8"as file:
        config = json.load(file)
    # adição de dependências ao sys.path
    rootDir = config['rootDir']
    # adicionam-se as dependências relativas do projeto ao syspath
    for directory in config['relativeDependencies']:
        # adiciona-se a dependência no início do syspath
        sys.path.insert(0f"{rootDir}/{directory}")
    # adicionam-se as dependências absolutas do projeto ao syspath
    for directory in config['absoluteDependencies']:
        # adiciona-se a dependência ao início do syspath
        sys.path.insert(0, directory)
    # cria-se o dicionário de configuração
    return config

# pasta do script executado
def get_scriptdir():
    return os.path.dirname(os.path.abspath(__file__))
  • linha 8: a função [config_app] recebe como parâmetro o nome do ficheiro de configuração;
  • linhas 12-14: o ficheiro de configuração é utilizado para criar o dicionário [config];
  • linha 20: [sys.path] é a lista de pastas do Python Path;
  • linhas 17-20: as dependências relativas do ficheiro de configuração são adicionadas ao Python Path. São adicionadas no início da tabela [sys.path], linha 20. Com efeito, quando o Python procura um módulo, explora as pastas do [sys.path] por ordem. No entanto, neste documento, módulos com os mesmos nomes vão encontrar-se em pastas diferentes do [sys.path]. Ao colocar as dependências da aplicação no início da tabela [sys.path], garantimos que estas serão exploradas antes de outras pastas do [sys.path] que possam conter módulos com os mesmos nomes;
  • linhas 21-24: as dependências absolutas do ficheiro de configuração são adicionadas ao Python Path;
  • linha 26: devolve-se a configuração da aplicação;
  • linhas 29-30: a função [get_scriptdir] devolve o nome absoluto da pasta do script em execução (aquela onde se encontra a chamada à função);

O script principal [main] é o seguinte:


# importações
import sys

from utils import config_app


def affiche_path(msg: str):
    # mensagem
    print(f"{msg}------------------------------")
    # sys.path
    for path in sys.path:
        print(path)


# main -------------
try:
    # o sys.path está configurado
    affiche_path("avant....")
    config = config_app(f"{get_scriptdir()}/config.json")
    affiche_path("après....")
    # importamos o módulo4
    from module4 import f4
    # execução f4
    f4()
except BaseException as erreur:
    print(f"L'erreur suivante s'est produite : {erreur}")
finally:
    print("done")
  • linha 4: a função [config_app] é importada. Note-se que, uma vez que [utils] e [main] se encontram na mesma pasta, esta função [import] funciona sempre. Com efeito, a pasta do script principal é automaticamente adicionada ao Python Path;
  • linhas 7-12: a função [affiche_path] apresenta a lista de pastas do Python Path;
  • linha 19: configura-se a aplicação. Note-se que se passa à função [config_app] o nome absoluto do ficheiro de configuração. Após esta instrução, o Python Path foi reconstruído;
  • linha 22: importa-se o módulo [module4]. Graças à reconstrução do Python Path, este módulo será encontrado;
  • linha 24: executa-se a função [f4];

No contexto PyCharm, os resultados da execução são os seguintes:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/06/main.py
avant....------------------------------
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions\shared
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01\shared

C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
après....------------------------------
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir2
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir1
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions\shared
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01\shared
….
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
f3
f4
done

Process finished with exit code 0

Comentários

  • linhas 2-13: o Python Path de PyCharm. Aqui encontram-se todas as pastas incluídas no [Sources Root] do projeto;
  • linhas 14-29: o Python Path construído pela função [config_app]. Nas linhas 15-16, encontram-se as duas dependências que adicionámos;
  • linhas 22-27: as pastas do sistema do interpretador Python que executou o script;
  • linhas 28-29: a execução decorre normalmente;

Agora, vamos situar-nos no contexto que, até agora, provocava um erro de execução:

  • abrimos um terminal Python;
  • vamos para uma pasta diferente daquela que contém o script executado;

(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 06/main.py
avant....------------------------------
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
après....------------------------------
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir2
C:/Data/st-2020/dev/python/cours-2020/v-02/imports/06/dir1
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import\06
C:\Program Files\Python38\python38.zip
C:\Program Files\Python38\DLLs
C:\Program Files\Python38\lib
C:\Program Files\Python38
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\lib\site-packages
f3
f4
done

Desta vez está tudo bem (linhas 20-21). Note-se que o [sys.path] não contém as mesmas pastas que quando a execução ocorre no PyCharm.

9.7. Scripts [import_07]

Melhoramos a solução anterior de duas formas:

  • substituímos o ficheiro de configuração [config.json] por um script [config.py]. Com efeito, o ficheiro jSON apresenta um problema importante: não pode ser comentado. O dicionário [config.json] pode ser substituído por um dicionário Python, que tem a vantagem de poder ser comentado;
  • utilizamos um módulo visível para todos os projetos Python da máquina;

9.7.1. Instalação de um módulo com âmbito de máquina

Image

Acima, criamos uma pasta [packages/myutils] no projeto PyCharm (os nomes não importam).

O script [myutils.py] é o seguinte:


# importações
import sys
import os


def set_syspath(absolute_dependencies: list):
    # absolute_dependencies: uma lista de nomes absolutos de pastas

    # adicionam-se ao syspath as dependências absolutas do projeto
    for directory in absolute_dependencies:
        # verifica-se se a pasta existe
        existe = os.path.exists(directory) and os.path.isdir(directory)
        if not existe:
            # lança-se uma exceção
            raise BaseException(f"[set_syspath] le dossier du Python Path [{directory}] n'existe pas")
        else:
            # adiciona-se a pasta ao início do syspath
            sys.path.insert(0, directory)
  • linhas 6-18: a função [set_syspath] cria um Python Path com a lista de pastas que lhe é passada como parâmetro;
  • linhas 12-15: verifica-se se a pasta a incluir no Python Path existe;

O script [__init.py__] (com dois traços antes e depois do nome. Este nome é obrigatório) é o seguinte:


from .myutils import set_syspath

Importa-se a função [set_syspath] do script [myutils]. A notação [.myutils] designa o caminho [./myutils], ou seja, o script [myutils] encontra-se na mesma pasta que o [__init.py]. Poderíamos ter utilizado a notação [myutils]. No entanto, vamos criar um módulo [myutils] com âmbito de máquina. Assim, a notação [from myutils import set_syspath] tornar-se-ia ambígua. Trata-se de importar o script [myutils] da pasta atual ou o script [myutils] com âmbito de máquina? A notação [.myutils] elimina essa ambiguidade.

O script [setup.py] (também neste caso o nome é imposto) é o seguinte:


from setuptools import setup

setup(name='myutils',
      version='0.1',
      description='Utilitaire fixant le Python Path',
      url='#',
      author='st',
      author_email='st@gmail.com',
      license='MIT',
      packages=['myutils'],
      zip_safe=False)

Neste script, descreve-se o módulo que se vai criar. Aqui, vamos criá-lo localmente. Mas o mesmo processo é utilizado para criar um módulo distribuído oficialmente (ver |pypi|). Os pontos importantes são os seguintes:

  • linha 3: o nome do módulo criado;
  • linha 4: a versão do módulo;
  • linha 5: a sua descrição;
  • linhas 7-8: o autor do módulo;

Para instalar este módulo com um âmbito de máquina, procedemos da seguinte forma:

Image

Em seguida, no terminal Python, introduz-se o seguinte comando: [pip install .]:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\packages>pip install .
Processing c:\data\st-2020\dev\python\cours-2020\python3-flask-2020\packages
Using legacy setup.py install for myutils, since package 'wheel' is not installed.
Installing collected packages: myutils
  Attempting uninstall: myutils
    Found existing installation: myutils 0.1
    Uninstalling myutils-0.1:
      Successfully uninstalled myutils-0.1
    Running setup.py install for myutils ... done
Successfully installed myutils-0.1

A partir de agora, qualquer script da máquina pode importar o módulo [myutils] sem que este esteja nos códigos do projeto.

9.7.2. O script [config.py]

Image

O script [config.py] assegura a configuração da aplicação:


def configure():
    import os

    # nome absoluto da pasta do script de configuração
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # caminhos absolutos das pastas a incluir no syspath
    absolute_dependencies = [
        # pastas locais
        f"{script_dir}/dir1",
        f"{script_dir}/dir2",
    ]
    # atualização do syspath
    from myutils import set_syspath
    set_syspath(absolute_dependencies)

    # retornamos a configuração
    return {}
  • linha 1: a função [configure] assegura a configuração da aplicação;
  • linhas 7-10: o dicionário que anteriormente se encontrava em [config.json];
  • linhas 9-10: como estamos num script, podemos obter diretamente os nomes absolutos das pastas [dir1, dir2];
  • linhas 12-14: utilizamos a função [set_syspath] do módulo [myutils] que acabámos de criar para definir o Python Path da configuração;
  • linha 20: devolvemos o dicionário da configuração da aplicação. Aqui, está vazio;

9.7.3. O script [main.py]

O script principal [main] é o seguinte:


# configuramos a aplicação
import config

config = config.configure()

# o syspath está configurado — já é possível efetuar as importações
from module4 import f4

# main -------------
try:
    f4()
except BaseException as erreur:
    print(f"L'erreur suivante s'est produite : {erreur}")
finally:
    print("done")
  • linhas 2-4: configuramos a aplicação utilizando o módulo [config.py]. Este está acessível porque se encontra na mesma pasta que o script principal. Ora, a pasta do script principal faz sempre parte do Python Path;
  • quando se chega à linha 6, o Python Path já foi construído, incluindo a pasta do módulo [module4]. Assim, é possível importar este módulo na linha 7;
  • linhas 10-15: basta agora executar a função [f4];

Os resultados da execução em PyCharm são os seguintes:

1
2
3
4
5
6
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/import/07/main.py
f3
f4
done

Process finished with exit code 0

Num terminal Python e fora da pasta do script principal, os resultados são os seguintes:

1
2
3
4
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\import>python 07/main.py
f3
f4
done

A partir de agora, procederemos sempre da mesma forma para configurar uma aplicação:

  • existência de um script [config.py] na pasta do script principal. Este script contém uma função [configure] que tem dois objetivos:
    • construir o Python Path para a aplicação. Para tal, o [config.py] declara todas as pastas que contêm os módulos utilizados pela aplicação e constrói o Python Path com os seus nomes absolutos;
    • construir o dicionário [config] da configuração da aplicação;

Aplicamos este esquema à segunda versão do exercício prático. Recordemos, de facto, que a versão 1 funcionava no ambiente PyCharm, mas não num terminal Python. O problema prendia-se com o Python Path.