Ambientes Virtuais, PIP e Conda


Ambiente virtual

Um ambiente virtual é uma área isolada de seu computador onde pacotes específicos são instalados para o uso, sem o problema de conflitarem com outras versões instaladas. Com isso cada projeto pode ter suas próprias dependências, diferentes das possíveis dependências em outros projetos. Até mesmo versões diferentes do python podem ser usadas. Um projeto do Python pode usar diversos pacotes e módulos, sendo que alguns deles podem não estar na biblioteca padrão. Vários ambientes podem ser criados e gerenciados separadamente, sem limite na quantidade, pois são apenas diretórios contendo scripts. Esses ambientes podem ser criados usando as ferramentas no comando de linha venv, virtualenv ou pyenv. Nos concentraremos aqui na ferramenta venv.

Criando ambientes virtuais

Na construção de um aplicativo uma versão específica de uma biblioteca, ou até do próprio Python, pode ser necessária. Para isso a linguagem oferece a possibilidade de se criar ambientes virtuais: um ambiente independente armazenado em uma árvore de diretórios própria contendo a instalação do Python e pacotes em versão específica.

O módulo venv é usado para criar e gerenciar ambientes virtuais. Ele seleciona e organiza a versão do Python e dos módulos usados no projeto.

Para criar um ambiente virtual você deve decidir em que diretório ele deve ser abrigado. Depois execute o módulo venv como um script, no prompt de comando, informando o caminho do diretório. Uma boa prática é criar uma pasta oculta .venv na sua pasta raiz ou pasta de projetos para abrigar todos os seus ambientes virtuais. No exemplo criaremos a pasta ~/Projetos/.venv/aprendendo:

$ python3 -m venv ~/Projetos/.venv/aprendendo
Figura 1: estrutura de arquivos com venv.

Dentro da pasta aprendendo é criada uma estrutura de pastas contendo uma cópia do interpretador e alguns arquivos de configuração, mostrada na figura 1.

Essas pastas tem o conteúdo:

  • bin: arquivos que interagem com o ambiente virtual
  • include: cabeçalhos C que compilam os pacotes Python
  • lib: uma cópia da versão do Python junto com uma pasta site-packages onde cada dependência está instalada

Parte desses arquivos são links simbólicos (ou symlinks) que apontam para as corretas versões das ferramentas do python.

Na pasta bin ficam os scripts de ativação usados para definir o ambiente para uso. Depois de criado o ambiente pode ser ativado executando activate.

# No windows:
$ ~\Projetos\.venv\aprendendo\Scripts\activate.bat

# No Linux (bash shell)
$ source ~/Projetos/.venv/aprendendo/bin/activate

Ao ser carregado um novo ambiente o prompt de comando muda para indicar qual ambiente está em uso. Nesse prompt carregamos o Python (no meu caso 3.8.8 Anaconda), importamos a biblioteca sys e verificamos os caminhos em uso.

(aprendendo) $ python
Python 3.8.8 (default, Apr 13 2021, 19:58:26) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
   ['', '/home/usr/.anaconda3/lib/python38.zip', '/home/usr/.anaconda3/lib/python3.8', '/home/usr/.anaconda3/lib/python3.8/lib-dynload', '/home/usr/Projetos/.venv/aprendendo/lib/python3.8/site-packages']
>>> sys.prefix
   '/home/usr/Projetos/.venv/aprendendo'

Esse ambiente está isolado do meio externo. Por exemplo, no meu caso o pandas está instalado globalmente. No entanto ele não pode ser apontado por um código rodando em no ambiente (aprendendo).

>>> import pandas
    Traceback (most recent call last):
      File "", line 1, in 
    ModuleNotFoundError: No module named 'pandas'

Para sair do ambiente reservado usamos deactivate no terminal.

(aprendendo) (base) [guilherme@gui ~]$ deactivate
(base) [guilherme@gui ~]$ python
Python 3.8.8 (default, Apr 13 2021, 19:58:26)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas

Como o pandas está instalado globalmente, nenhuma mensagem de erro é gerada e o módulo fica disponível para uso.

A ativação de um ambiente significa a especificação do local onde estão os executáveis e bibliotecas importadas. Para reativar o ambiente nos “deslocamos” até a pasta onde ele está instalado e executamos activate.

$ cd /home/usuario/Projetos/.venv/aprendendo
$ source bin/activate
# o prompt é alterado
(aprendendo) $ python
>>> import sys
>>> sys.prefix
    '/home/guilherme/Projetos/.venv/aprendendo'
Observação Importante: Para instalar env com versão específica do Python

Pode ocorrer que existam mais de uma versão do Python instalada em seu computador. Para criar um ambiente com outra versão devevemos executar o script do venv na versão que desejamos para o ambiente virtual. Por exemplo, para um ambiente com python 3.11 (supondo que ele esteja instalado nesse computador) devemos executar:

$ python3.11 -m venv ~/Projetos/.venv/VsCode
$ source ~/Projetos/.venv/VsCode/bin/activate
$ python
>>> Python 3.11.0a7 (main, Apr  7 2022, 00:00:00) [GCC 11.2.1 20220127 (Red Hat 11.2.1-9)] on linux
>>> Type "help", "copyright", "credits" or "license" for more information.

Nesse caso criamos um ambiente virtual no diretório ~/Projetos/.venv/VsCode.

Gerenciando ambientes virtuais com pip

Uma vez dentro do novo ambiente você pode instalar pacotes usando pip que, por default, encontra e instala pacotes do Python Package Index. PIP é um gerenciador padrão de pacotes (ou bibliotecas) do Python, que acessa um reservatório de pacotes publicados no Python Package Index, ou PyPI. Em versões mais recentes ele vem instalado por default. Um pacote é um conjunto de arquivos que executam um ou várias funções. Eles podem ser importados em um aplicativo para extender a funcionalidade do Python padrão. PIP funciona por meio de comandos de linha, digitados no prompt do sistema operacional.

A sintaxe de venv é a seguinte: [parâmetros opcionais] | indice um ou outro. Apenas ENV_DIR é obrigatório e posicional.

venv [-h] [–system-site-packages] [–symlinks | –copies] [–clear] [–upgrade]
[–without-pip] [–prompt PROMPT] [–upgrade-deps] ENV_DIR [ENV_DIR …]
Cria o ambiente virtual em um ou mais diretórios especificados.
ENV_DIR Diretório onde criar o ambiente virtual,
-h, –help exibe (o presente) texto de ajuda,
–system-site-packages Dá acesso ao ambiente virtual para a pasta site-packages do sistema.
–symlinks Tenta usar symlinks no lugar de cópias, quando os symlinks não são default na plataforma.
–copies Tenta usar cópias no lugar de symlinks, mesmo que symlinks sejam o default na plataforma.
–clear Apaga o conteúdo do diretório de ambiente, se existe, antes da criação do ambiente.
–upgrade Atualiza o diretório de ambiente, caso o python do ambiente tenha sido atualizado.
–without-pip Interrompe a instalação ou atualização via pip nesse ambiente. (Por default o pip é acionado).
–prompt PROMPT Estabelece um prefixo alternativa para o prompt desse ambiente.
–upgrade-deps Atualiza as dependências do pip setuptools para o última versão disponível em PyPI.

Depois que o ambiente é criado você deve ativá-lo com o script source pasta/do/ambiente/bin/activate.

Instalação de PIP

Você pode verificar a presença do pip (ou conferir a versão) com pip --version, no prompt de comando.

$ pip --version
  pip 22.0.3 from /home/usuario/Projetos/.venv/aprendendo/lib/python3.8/site-packages/pip (python 3.8)    

O output do comando mostra a versão do pip e do python sendo usados no ambiente virtual instalado na pasta /home/usuario/Projetos/.venv/aprendendo.

Alternativamente, é possivel encontrar onde está instalado o pip:

# no Windows    
C:\> where pip3  
# no Linux
$ which pip
~/.anaconda3/bin/pip
$ which pip3
~/.anaconda3/bin/pip3

Caso o pip não esteja instalado, isso pode ser feito de duas formas: ensurepip e get-pip.py.

No prompt do terminal de seu sistema (que representaremos por $, comentários por #) digite:

$ python -m ensurepip
# ou 
$ python -m ensurepip --upgrade

A chave -m garante que pip seja executado como um módulo. Na segunda forma se garante que apenas versões mais novas que atual (se presente) seja instalada. Nenhuma ação será executa se já existe a instalação, ou se está em sua versão mais atual, no segundo caso. pip será instalado globalmente ou no ambiente virtual, se esse estiver ativo.

Outra alternativa é baixar o script get-pip.py e executá-lo com a primeiro linha no código. A segunda linha é uma forma de atualizá-lo.

# instalar pip
$ python get-pip.py
# fazer atualização de pip
$ python -m pip install --upgrade pip

Instalando módulos com o PIP

O uso geral de pip é o seguinte:

# no linux/Mac    
$ python -m pip <argumentos>
# ou
$ pip <argumentos>
# no windows    
$ py -m pip <argumentos>

Para instalar um módulo com o PIP executamos pip com o argumento install e o nome do módulo. Vários módulos podem ser instalados com uma única linha.

$ python -m pip install 
# ou    
$ pip install 
# por exemplo, para instalar o Flask
$ pip install Flask
# vários módulos
$ python -m pip install   ... 

Para controlar qual é a versão a ser instalado usamos:

python -m pip install Modulo             # instalar a última versão
python -m pip install Modulo ==1.0.4     # instalar versão especificada
python -m pip install 'Modulo >=1.0.4'   # especificar a versão mínima

É possível passar para pip uma lista de requisitos para a exata reprodução de um ambiente.

# para gerar o arquivo relativa a um ambiente:
$ python -m pip freeze > requirements.txt
# para reproduzir a instalação:
$ python -m pip install -r requirements.txt    

O arquivo requirements.txt contém uma lista dos argumentos do pip install. Essa lista pode ser gerada com freeze.

pip pode ser usado para instalar pacotes de outros repositórios. Por exemplo, se você deseja instalar o pacote rptree disponível em TestPyPI package index, ou no GitHub.

# no TestPyPI    
python -m pip install -i https://test.pypi.org/simple/ rptree
# no GitHub
python -m pip install git+https://github.com/realpython/rptree

Observação: pode ocorrer que em seu computador o python 3 esteja instalado com o nome python3.

<h2=”idm”>Listando e desinstalando módulos

Módulos instalados podem ser vistos com o argumento list. A lista obtida reflete a instalação do Flask e suas dependências. Uma lista com pacotes desatualizados é obtida com a chave list –outdated.

$ python -m pip list
  Package      Version
  ------------ -------
  click        8.0.3
  Flask        2.0.2
  itsdangerous 2.0.1
  Jinja2       3.0.3
  MarkupSafe   2.0.1
  pip          22.0.3
  setuptools   49.2.1
  Werkzeug     2.0.2    

# listar apenas pacotes desatualizados
$ python -m pip list --outdated
  Package    Version Latest Type
  ---------- ------- ------ -----
  setuptools 49.2.1  60.8.1 wheel

Pode ocorrer que você deseje usar outro pacote e queira remover o antigo de seu computador. A desinstalação é feita com uninstall. pip desinstala pacotes com versões desatualizadas antes de fazer uma atualização para versão mais nova.

Um cuidado deve ser tomado: Quando um pacote é instalado é possível que ele possua dependências que são instaladas juntas com ele. Se você tem muitos pacotes instalados é possível que mais de um use a mesma dependência. Por isso é importante verificar se ele é dependência de outro ou se possui dependências. Para isso usamos python -m pip show <modulo>.

$ python -m pip show Flask
Name: Flask
Version: 2.0.2
Summary: A simple framework for building complex web applications.
Home-page: https://palletsprojects.com/p/flask
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
License: BSD-3-Clause
Location: /home/guilherme/.anaconda3/lib/python3.8/site-packages
Requires: itsdangerous, Jinja2, click, Werkzeug
Required-by: 

Vemos no output que Flask possui as dependências (Requires: )itsdangerous, Jinja2, click e Werkzeug. Por outro lado ele não é exigido por nenhum outro modulo (Required-by:) portanto pode ser seguramente desinstalado. Para isso usamos uninstall.

$ python -m pip uninstall Flask

O mesmo procedimento deve ser usado com as dependências, caso você queira apagá-las.

Busca por pacotes

pip pode fazer buscas por um pacote com o comando:

python -m pip search "query"

A pesquisa retorna uma lista de pacotes com uma breve descrição de cada um.
Importante: pip search deixou de funcionar em dezembro de 2020. Um substituto para esse comando é poetry (que deve ser instalado em seu sistema). Por exemplo, uma busca por pacotes com “pandas” no nome: (o output está truncado).

$ poetry search "pandas"
  pandas (1.4.0)
     Powerful data structures for data analysis, time series, and statistics
  pandas3 (0.0.1)
     Boto3 extension to help facilitate data science workflows with S3 and Pandas
  pandas-alchemy (0.0.2)
     SQL based, pandas compatible DataFrame & Series


Poetry é similar ao npm do JavaScript, gerenciando pacotes e auxiliando na criação de distribuições de aplicativos e bibliotecas, além da inserção no PyPI. Outro pacote é o Pipenv que gerencia pacotes e controla ambientes virtuais. Real Python: Pipenv Guide.

Estrutura de um projeto Python

O Python é bastante flexível na questão de estrutura de pastas para um projeto. No entanto algumas sugestões foram dadas para um desenho ótimo para um projeto. Aqui eu sigo as sugestões de Lucas Tonin.
Vamos denominar nosso projeto de meu_projeto. Se estamos usando, como é recomendado, um ambiente virtual podemos criá-lo com python3 -m venv ~/Projetos/.venv/meu_projeto, que já estabelece uma estrutura mínima de pastas. Vamos por hora ignorar as pastas relativas ao ambiente virtual.

Para definir uma terminologia chamamos de projeto python tudo aquilo que estará no diretório base, que em nosso caso é ~/Projetos/.venv/meu_projeto. Todos os arquivos relacionados ao desenvolvimento, teste e arquivos auxiliares ficam nesse diretório. Chamamos de pacote (package) ao conteúdo de um subdiretório dentro do projeto com o mesmo nome. O pacote contém o código-fonte do aplicativo. Ele isola o código fonte de todos os outros arquivos. Depois de pronto a instalaçao do projeto inclui apenas os arquivos contidos nesse diretório, ignorando código fonte e testes.

Arquivo __init__.py: O pacote deve necessariamente conter pelo menos um arquivo como o nome __init__.py. A presença desse informa ao python que esse diretório é um pacote. __init__.py é executado automaticamente quando esse pacote é carregado e deve conter as inicializações para o aplicativo. Duas coisas importantes podem ser aí incluídas: (a) uma variável ROOT_DIR com o caminho absoluto do atual pacote, onde estiver no momento; (b) as configurações de logger, quando existir.

from os.path import dirname, abspath
ROOT_DIR = dirname(abspath(__file__))
# inicialização de logs

Um arquivo de documentação, README.md: geralmente esses arquivos são escritos em MARKDOWN. Ele deve conter uma descrição de seu projeto para outros usuários de seu código, ou para você mesmo no caso de retomar após um tempo esse trabalho, além de instruções de instalações. Um exmplo simples:

# Meu Projeto
Um aplicativo simples para a importação de arquivos *csv* e exportação para banco de dados SQL.
## Instalação
Para instalar execute `pip install /caminho/meu_projeto`

Usando setup.py: o arquivo setup.py contém informações sobre configurações do pacate a ser instalado. No mínimo ele deve conter:

import setuptools
setuptools.setup(name='meu_projeto', packages=['meu_projeto'])

que informa o nome do projeto e do pacote. O parâmetro packages informa ao pip que apenas esse diretório será instalado.

Para projetos maiores e mais complexos, que envolvem muitas dependências, é útil acrescentar um arquivo requirements.txt Este arquivo lista os pacotes necessários para o projeto, que não fazem parte da biblioteca padrão. Com ele o pip pode baixar e instalar automaticamente todas as dependências, se não o encontrar já instalado. Por exemplo, se o projeto depende do numpy (um pacote para computação científica) a arquivo deverá conter pelo menos a linha

numpy==1.18.2

O arquivo setup.py deve ser modificado para que essa informação seja usada.

# setp.py
import setuptools
with open('requirements.txt', 'r') as f:
    install_requires = f.read().splitlines()

setuptools.setup(name='meu_projeto',
                 packages=['meu_projeto'],
                 install_requires=install_requires)


Um arquivo LICENCE, que descreve a licença sob a qual você está distribuindo seu projeto, pode ficar no diretório base, onde pode ser facilmente encontrado. Finalmente, uma pasta separa para os testes usados para testar a correção do código.

O projeto fica portanto com a seguinte estrutura mostrada na figura.

Usando Jupyter Notebook em ambiente virtual

Anaconda é uma plataforma de distribuição de Python e R muito usada para a ciência de dados e aprendizado de máquina. Ele simplifica a instalação de pacotes como pandas, NumPy, SciPy, e pode ser usada com diversas outras linguagens. Conda é o gerenciador padrão de pacotes do Anaconda, multiplataforma e agnóstico à linguagem e que pode ser usado para instalar pacote de terceiros. O Anaconda Navigator, instalado junto com o Anaconda, é uma interface gráfica que permite o gerenciamento de pacotes coda, com busca, instalação, atualização e desinstalação, execução dos aplicativos incluidos na Anaconda Cloud ou outro repositório Anaconda local. Todo esse sitema está disponível para Windows, macOS e Linux.

O Anaconda Cloud é um serviço de nuvem que abriga pacotes, notebooks e ambientes Python para variadas situações e casos, incluindo pacotes conda e PyPI públicos e privados. Ele permite o uploud de pacotes de usuário e notebooks, sem a necessidade de um login ou conta na nuvem.

Jupyter Notebook é uma ambiente interativo de interface do usuário da Web onde se pode rodar código nas linguagens instaladas, criar documentos de notebook contendo texto (em Markdown), imagens e vídeos. Esses documentos podem ser partilhados e publicados na nuvem, onde podem ser alterados e executados por outros usuários.

O Jupyter Notebook faz um gerenciamento de ambiente próprio. Mas tambem podemos criar um ambiente virtual específico para ele. Isso é bastante útil pois esse ambiente é usualmente dedicado à computação científica e aplicações com grandes volumes de dados, exigindo bibliotecas específicas. Para isso criamos um ambiente virtual, que chamaremos de jupyter. Depois ativamos o ambiente e instalamos o Jupyter Notebook dentro desse ambiente.

# criamos o ambiente virtual    
$ python3 -m venv ~/Projetos/.venv/jupyter_venv
# ativamos esse ambiente
$ cd /home/usuario/Projetos/.venv/jupyter_venv
$ source bin/activate 
# instala o Jupyter Notebook no ambiente
(jupyter) $ ipython kernel install --user --name=jupyter_venv

Para usar o ambiente virtual abra o jupyter e selecione o kernel no menu kernel | change kernel. A opção para o ambiente jupyter_venv deve estar disponível, como mostra a figura, como uma das opções de kernel a usar.

Para desinstalar o ambiente fazemos:

$ jupyter-kernelspec uninstall jupyter_venv

Gerenciador conda


Para quem está trabalhando com a distribuição Python Anaconda (site) é mais interessante usar o gerenciador conda, que além de gerenciar pacotes e suas dependências controle também ambioentes virtuais. Ele pode ser usado com Python, R, Ruby, Lua, Scala, Java, JavaScript, C/ C++, FORTRAN e outras.

Com o conda você pode pesquisar por pacotes, instalar os pacotes desejados ou construir um pacote do usuário com build (conda-build deve ser instalado).

A versão de conda pode ser verificada, e atualizada se necessário. Essa atualização pode incluir atualização de outros pacotes e remoção de pacotes não usados.

# verificar versão    
$ conda --version
  conda 4.10.3
# informações mais detalhadas podem ser obtidas
$ conda info
    active environment : base
    active env location : /home/guilherme/.anaconda3
# -----(outpup truncado)-----

# atualizar versão
$ conda update conda
# se existir versão mais recente
  Proceed ([y]/n)? y

A pesquisa e instalação de pacotes é feita com search e install. A construção (build) de pacotes é feitas com build.

# pesquisar   
$ conda search scipy
# instalação
$ conda install scipy
# o novo pacote deve estar na lista
$ conda list

# construir um pacote
$ conda build meu_projeto

Versões podem ser especificadas, inclusive com o uso de operadores lógicos.

conda install numpy=1.11                  #(instala versão especificada)
conda install numpy==1.11                 #(idem)
conda install "numpy>1.11"                #(versão superior a 1.11)
conda install "numpy=1.11.1|1.11.3"       #(versão 1.11.1 ou 1.11.3)
conda install "numpy>=1.8,<2"          #(versão maior ou igual a 1.8 mas inferior a 2)

A barra | é o operador OR: “pacote=1.1|1.3” significa 1.1 ou 1.3.
A vírgula , é o operador AND: “pacote=1.1,1.3” significa ambos 1.1 e 1.3.
O igual = é o operador fuzzy: “pacote=1.11” pode ser “1.11”, “1.11.1”, , “1.11.8”, etc.
O duplo igual == é o operador exato: “pacote==1.11” pode ser “1.11”, “1.11.0”, , “1.11.0.0”, etc.

Gerenciamento de ambientes com conda

Um novo ambiente, que chamaremos de cientifico pode ser criado, e simultanemanete instalado nele o pacote pandas. Caso um versão do Python diferente da versão default do Anaconda instalado usamos a declaração conda create --name nome_ambiente python=n, onde n é a versão desejada.

# criar um ambiente com um pacote
$ conda create --name cientifico pandas
  Proceed ([y]/n)? y
  
# ativar o ambiente
$ conda activate cientifico

# para verificar a versão do python em uso
$ python --version
  Python 3.8.8

# para criar ambiente coom outra versão do python
conda create --name cientifico python=3.9

Uma lista de todos os ambientes disponíveis pode ser vista com info --envs. As pastas listadas dependem do local onde os ambientes foram criados.

$ conda info --envs
  conda environments:
      base           /home/username/Anaconda3
      cientifico   * /home/username/Anaconda3/envs/cientifico

O ambiente ativo aparece com um asterisco *.

Um canal conda é um local na rede onde pacotes estão armazenados. Por default Conda busca em uma lista de canais e baixa arquivos de Repo Anaconda, onde alguns pacotes podem ser prorietários. Outros repositórios podem ser apontados com o conda, por exemplo o Conda Forge, uma organização parte do GitHub que contém um grande número de pacotes gratuitos. O parâmetro --override-channels é usado para que os canais default (gravados em .condarc) sejam ignorados.

# para apontar para o conda-forge
$ conda install scipy --channel conda-forge

# múltilpos repositórios podem ser apontados
$ conda install scipy --channel conda-forge --channel bioconda
# argumentos que aparecem na frente são pesquisados primeiro

# para pesquisar em repositório local, ignorando os defaults
$ conda search scipy --channel file:/caminho/local-channel --override-channels

Para instalar um pacote presente no conda-forge também é possível fazer:

$ conda config --add channels conda-forge
$ conda config --set channel_priority strict
$ conda install "nome-do-pacote"

Muito mais é possível com o Conda: consulte as instruções em Conda Docs.

Argumentos positionais
comando descrição
clean Remove pacotes e caches não utilizados.
compare Compara pacotes entre ambientes conda.
config Modifica os valores de configuração em .condarc. (feito após a configuração do comando git).
Grava arquivo .condarc do usuário
create Cria um ambiente conda a partir de uma lista de pacotes especificados.
help Exibe uma lista de comandos conda disponíveis e suas ajudas.
info Exibe informações sobre a instalação atual do conda.
init Inicializa o conda para interação do shell. [Experimental]
install Instala uma lista de pacotes em um ambiente conda especificado.
list Lista pacotes vinculados em um ambiente conda.
package Utilitário de pacote conda de baixo nível. (EXPERIMENTAL)
remove Remove uma lista de pacotes de um ambiente conda especificado.
uninst Alias para remove.
run Execute executável em um ambiente conda. [Experimental]
search Pesquisa pacotes e exibe informações associadas.
update Atualiza pacotes conda para a versão compatível mais recente.
upgrade Alias para update.
Argumentos opcionais
comando descrição
-h, –help Mostra ajuda,
-V, –version Mostra versão.

Bibliografia

Deixe um comentário

O seu endereço de e-mail não será publicado.