Crie um pacote Python puro#

Sobre esta lição

Esta lição usa o template copier de pacote Python do pyOpenSci para criar um pacote Python rapidamente. Seu pacote será instalável localmente e remotamente a partir de um site como GitHub (ou GitLab) em um ambiente Python.

Nesta lição, você aprenderá:

  • Como tornar seu código instalável em qualquer ambiente Python, localmente e a partir do GitHub

  • Como atualizar um arquivo pyproject.toml, que contém os metadata necessários para fazer build, instalar e publicar seu pacote.

  • Como declarar um backend de construção que será usado para fazer build e instalar seu pacote

  • Como instalar seu pacote em modo editável para desenvolvimento interativo

O que você precisa para concluir esta lição

Para concluir esta lição, você precisará de um ambiente Python local e de um shell no seu computador. Será necessário ter o Copier e o Hatch instalado para concluir a lição com sucesso.

Se você usa Windows ou não está familiarizado com Shell, pode querer conferir a lição de shell da Carpentries[1]. Usuários de Windows provavelmente precisarão configurar uma ferramenta como gitbash para qualquer etapa relacionada a Shell e git.

Este diagrama tem duas caixas menores com setas apontando para a direita em direção a um ambiente Python. As caixas pequenas mostram seu-pacote e pip install pacote. A caixa do ambiente à direita diz — seu ambiente Python. Em seguida, lista seu-pacote junto com alguns outros pacotes principais, como Matplotlib, NumPy, Pandas, Xarray e GeoPandas.

Em uma lição anterior, você aprendeu o que é um pacote Python. Criar um pacote Python permite instalar seu código em qualquer ambiente Python no seu computador. Em seguida, você pode importá-lo em workflows da mesma forma que importaria um pacote como Pandas ou GeoPandas. Se você enviar seu código para GitHub ou GitLab, também pode instalá-lo diretamente de lá. Role até o final da página para saber mais sobre os elementos básicos de um pacote Python..#

Crie seu pacote Python#

Abaixo, você criará um pacote Python puro usando o template copier dopyOpenSci. Nosso template usa Hatch como ferramenta de empacotamento padrão. No final desta lição, você aprenderá mais sobre o básico da estrutura de diretórios de um pacote Python e os arquivos principais associados (__init__.py e pyproject.toml).

Passo 1: Configure a estrutura de diretórios do pacote#

  • Abra seu shell ou terminal preferido.

  • Use o comando cd do shell para navegar até o local onde você quer que seu pacote fique. Nosso template criará a estrutura de diretórios do pacote para você

  • Escolha um nome para seu pacote. O nome deve:

    • Não ter espaços (Obrigatório)

    • Usar apenas letras minúsculas (Recomendado). Para este tutorial, usaremos pyospackage.

    • Use apenas letras e os caracteres _ ou - no nome. Isso significa que o nome pyos*package não é aceitável. Porém, os nomes pyos_package oupyos-package estão OK.

No seu terminal, execute o comando abaixo. Isso iniciará uma série de prompts que farão perguntas e ajudarão você a personalizar seu pacote Python.

copier copy gh:pyopensci/pyos-package-template .

Depois de executar o comando acima, o template guiará você por uma série de perguntas.

Observe que, quando chegar ao prompt «Do you want to answer one more question, and skip the rest, using the default values?», você pode escolher Yes, but with a minimal setup para criar a versão mais básica do seu pacote, contendo documentação, testes e um example module para você usar.

Após essa pergunta, o template pedirá seu nome de usuário do GitHub preferido e criará um pacote com testes básicos, documentação e configuração do GitHub para você.

➜ copier copy gh:pyopensci/pyos-package-template .
🎤 "Welcome to the pyOpenSci package template.
Please select the type of template that you want to create today."
 >> MINIMAL: I want a minimal setup (package, tests and docs; typing); linting not included).
    FULL DEFAULT: I want to use the default settings but I want it setup for me.
    FULL CUSTOM: I want it all but I want to fully customize all template elements.
🎤 What is the name of the project? Used as the README.md title, in the
   pyospackage_juno
🎤 Please provide a short description for the package.
    (Finish with 'Alt+Enter' or 'Esc then Enter')
> A great package that adds and subtracts numbers.
🎤 Who is the author of the package? Used in the package description.
   juno dawg
🎤 Provide you or your organization's GitHub username. Used to generate
   pyopensci

O template então começará a copiar arquivos para o diretório usado acima. (. significa diretório de trabalho atual.)

...Copying from template version 0.6.4.1
    create  CODE_OF_CONDUCT.md
    ...The template will continue to copy files...

A estrutura final do pacote ficará assim:

└── .github/ # a hidden directory with templates for github and actions to run your tests
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── pyproject.toml
└── src/  # This is your package directory where your code lives
└── docs/ # this is where your documentation lives
└── tests/ # Your tests are here
Um pacote completo com testes, docs e infraestrutura do GitHub

Se você usar a opção padrão «bells and whistles» ao responder aos prompts do template, nosso template criará uma configuração completa do pacote com GitHub CI Actions, typing, testes, ambientes e mais usando o Hatch. Se você personalizar o pacote inteiro, poderá selecionar em qual plataforma deseja hospedá-lo (GitHub vs GitLab), caso queira typing, qual engine de documentação quer usar, e mais.

O diretório do pacote resultante fica assim:

├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs # This defaults to sphinx docs
│   ├── conf.py
│   └── index.md
├── pyproject.toml
├── src/   # This is your package directory where your code lives
│   └── pyospackage_pyopensci/
|       ├── __init__.py
|       └── example.py
└── tests/   # This is where your tests live, you don't need subdirectories, but they are nice to have
    ├── integration/
    ├── system/
    └── unit/
        └── test_example.py

As ferramentas padrão que seu pacote usa são:

  • Sphinx com o PyData Sphinx Theme para documentação

  • pytest para testes

  • Hatch para configuração de ambiente

Personalização completa Se você quiser personalizar qualquer elemento da configuração do seu pacote, escolha No, I want to fully customize the template.. Isso permitirá que você selecione:

  • Sphinx vs MkDocs vs sem documentação

  • GitHub vs GitLab

  • versionamento VCS

  • e mais

Passo 2: Explore o módulo existente no seu pacote#

Um módulo refere-se a um arquivo .py contendo o código que você quer que seu pacote acesse e execute. No subdiretório pyospackage, você tem um module example.py que pode usar para testar seu pacote rapidamente.

Observe que o código no module example.py tem algumas características:

  1. Ele tem uma numpy-style docstring

  2. Ele usa typing

  3. At the top of the module, there is a docstring explaining what the module does.

Python suporta diferentes formatos de docstring. Os formatos mais populares para documentar objetos Python são NumPy Style Docstring[2], Google Style Docstring[3] e Epytext Style Docstrings[4].

A pyOpenSci recomenda usar a convenção NumPy Docstring.

Saiba mais sobre docstrings aqui para uma visão geral de ambos os tópicos.

def add_num(a: int, b: int) -> int:
    """
    Add two numbers.

    Parameters
    ----------
    a : int
        The first number to be added.
    b : int
        The second number to be added.

    Returns
    -------
    int
        The sum of the two input numbers (a + b).

    Examples
    --------
    >>> add_num(3, 5)
    8
    >>> add_num(-2, 7)
    5
    """
    return a + b

Módulos Python e o arquivo __init__.py

A palavra módulo refere-se a um arquivo .py contendo código Python.

O __init__.py permite que o Python reconheça que um diretório contém pelo menos um módulo que pode ser importado e usado no seu código. Um pacote pode ter vários módulos[5].

Passo 3: Opcional – Adicione código ao seu módulo#

Se quiser, adicione uma segunda função ao módulo example.py. Pode ser uma função simples. Por exemplo, escreva uma segunda função que multiplique números.

Passo 4: Confira o metadata no seu arquivo pyproject.toml#

Um arquivo pyproject.toml armazena metadata que fornece instruções a várias ferramentas que interagem com ele, incluindo Hatch, que fará o build do seu pacote. Você também pode especificar metadata para o seu pacote.

Você aprenderá mais sobre o formato pyproject.toml na próxima lição, quando adicionar metadata/informações adicionais a este arquivo.

O metadata no seu pyproject.toml gerado já está configurado para você com as informações que você forneceu ao copiar o template acima.

Visão geral breve do arquivo TOML

O formato TOML consiste em tabelas e variáveis. Tabelas são seções de informação indicadas por colchetes:

[this-is-a-table].

Tabelas podem conter variáveis definidas por um nome de variável e um sinal de =. Por exemplo, uma tabela build-system geralmente contém duas (2) variáveis:

  1. requires = , que informa a uma ferramenta de build quais ferramentas ela precisa instalar antes de fazer o build do seu pacote. Neste caso, hatchling.

  2. build-backend = , que é usado para definir o nome específico do build-backend (neste exemplo estamos usando hatchling.build).

# An example of the build-system table which contains two variables - requires and build-backend
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

TOML organiza estruturas de dados, definindo relacionamentos dentro de um arquivo de configuração.

Saiba mais sobre o formato pyproject.toml aqui.

  • Abra o arquivo pyproject.toml que o Hatch criou no seu editor de texto favorito. Ele deve parecer algo como o exemplo abaixo.

  • Verifique se a versão do pacote, o nome do pacote e o nome do autor estão corretos. O e-mail é opcional.

[project]
name = "pyospackage"
version = "0.1.0"
description = "A small template package that does cool things."
authors = [
    { name = "pyOpenSci", email = "pyopensci@pyopensci.org" },
]
license = "MIT"
readme = {"file" = "README.md", "content-type" = "text/markdown"}
# Please consult https://pypi.org/classifiers/ for a full list.
classifiers = [
    "Development Status :: 2 - Pre-Alpha",
    "Intended Audience :: Science/Research",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3 :: Only",
]
# TODO: add keywords
keywords = []
# TODO: add dependencies
dependencies = []

[project.urls]
Homepage = "https://github.com/pyopensci/pyospackage"
"Source Code" = "https://github.com/pyopensci/pyospackage"
"Bug Tracker" = "https://github.com/pyopensci/pyospackage/issues"
Documentation = "https://pyospackage.readthedocs.io"
Download = "https://pypi.org/project/pyospackage/#files"

[project.optional-dependencies]
dev = [
    "hatch",
    "pre-commit",
]

Na parte inferior do arquivo pyproject.toml gerado pelo template, você verá uma seção que define ambientes Hatch. Abordaremos ambientes Hatch em uma lição posterior.

O mínimo necessário em um arquivo pyproject.toml

As informações essenciais que você precisa em um arquivo pyproject.toml para publicar no PyPI são o nome do pacote e a versão. Porém, sugerimos que você preencha seu metadata logo no início no arquivo pyproject.toml.

Depois que você tiver o metadata do projeto no arquivo pyproject.toml, raramente precisará atualizá-lo.

Passo 5: Instale seu pacote localmente#

Neste ponto, você deve ter:

  1. Uma estrutura de diretório de projeto com um arquivo pyproject.toml na raiz

  2. Um diretório de pacote contendo um arquivo __init__.py vazio e

  3. Pelo menos um Python module (por exemplo, example.py)

Agora você está pronto para instalar (e fazer o build) do seu pacote Python!

Embora você possa fazer isso usando Hatch, usaremos pip nesta lição, para que você veja como instalar sua ferramenta no ambiente de sua preferência.

Primeiro, abra seu shell preferido (usuários do Windows podem usar algo como GitBash) e use cd para ir ao diretório do projeto, se ainda não estiver lá.

  • Ative o ambiente Python que deseja usar.

  • Execute python -m pip install -e .

# Activate your environment using conda or venv
# Below we use conda but you can do the same thing with venv!
> conda activate pyosdev
(pyosdev)
> conda info
    active environment : pyosdev
    active env location : /Users/your-path/mambaforge/envs/pyosdev
# Cd into your project directory
> cd pyospackage
# Install your package
> python -m pip install -e .

Obtaining file:///Users/leahawasser/Documents/GitHub/pyos/pyosPackage
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done

# Check to see if the package is installed
> conda list
# use pip list instead of conda list here if you are working in an venv environment rather than a conda envt

O que python -m pip install -e . faz?

python -m pip install -e . instala seu pacote no ambiente Python ativo atual em modo editável (-e). Instalar seu pacote em modo editável permite que você trabalhe no seu código e teste as atualizações de forma interativa na sua interface Python favorita. Uma ressalva importante do modo editável é que, sempre que atualizar seu código, você precisa reiniciar o Python.

Se quiser instalar o pacote normalmente (não em modo editável), você pode usar:

  • python -m pip install .

Usando python -m ao chamar pip

Acima, você usapython -m para chamar a versão do pip instalada no seu ambiente ativo atual. python -m é importante para garantir que você está chamando a versão do pip instalada no seu ambiente atual.

IMPORTANTE: pip também pode ser usado para instalar pacotes do PyPI. Porém, neste caso, você está dizendo ao pip para instalar seu pacote apartir de uma pasta local usando o .. Você também poderia especificar um caminho para o diretório do projeto no seu computador em vez do ., que informa ao pip para usar o diretório de trabalho atual.

Procure pyospackage no seu ambiente#

Depois de instalar seu pacote, você pode visualizá-lo no seu ambiente atual. Se estiver usando venv ou conda, pip list retornará uma lista de pacotes no ambiente ativo atual.

Observe que, como pyospackage está instalado em modo editável (-e), o pip mostrará o caminho do diretório para o código do seu projeto

$ pip list

➜ pip list
Package                       Version        Editable project location
----------------------------- -------------- --------------------------------------------------------------
...
arrow                         1.2.3
...
...
mamba                         1.1.0
markdown-it-py                2.2.0
MarkupSafe                    2.1.2
matplotlib                    3.7.1
msgpack                       1.0.5
mypy                          1.4.1
nox                           2021.10.1
numpy                         1.24.2
packaging                     23.0
pandas                        1.5.3
pyosPackage                   0.1            /Users/yourusername/path/here/pyosPackage
...
...
...

Passo 6: Teste seu novo pacote#

Depois de instalar seu pacote, digite «python» no prompt de comando no terminal escolhido para iniciar uma sessão Python no seu ambiente Python ativo.

Agora você pode importar seu pacote e acessar a função add_numbers.

➜ python
Python 3.11.4 | packaged by conda-forge
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyospackage.example import add_numbers
>>> add_numbers(1, 2)
3

Instalando pacotes do GitHub

Se quiser compartilhar seu código sem publicar no PyPI, você sempre pode instalar pacotes diretamente do GitHub usando a sintaxe:

python -m pip install git+https://github.com/user/repo.git@branch_or_tag

Para tornar seu pacote instalável pelo GitHub, você pode:

  1. Criar um novo repositório do GitHub

  2. Fazer push do conteúdo do diretório do projeto que você criou acima para o GitHub

  3. Por fim, instale o pacote do GitHub usando o comando acima. Ao usar o comando acima, não se esqueça de substituir user, repo e branch_or_tag pelos seus valores específicos.

Por exemplo, abaixo você instala o pyospackage da branch main do repositório da pyOpenSci.

python -m pip install git+https://github.com/user/repo.git@branch_or_tag

Parabéns! Você criou seu primeiro pacote Python#

Agora você criou um pacote Python que pode instalar em qualquer ambiente Python.

Nas próximas lições, você irá:

Sobre a estrutura de diretório de um pacote Python#

Para tornar seu código Python instalável, você precisa criar uma estrutura de diretório específica com os seguintes elementos:

  • Um arquivo pyproject.toml.

  • Uma estrutura de diretório específica.

  • Algum código.

  • Um arquivo __init__.py no diretório do seu código.

A estrutura de diretório que você criará nesta lição ficará assim:

pyospackage/  # Your project directory
 └─ pyproject.toml
 └─ src/  # The source (src) directory ensures your tests always run on the installed version of your code
    └── pyospackage/  # Package directory where code lives
        ├── __init__.py
        ├── add_numbers.py
        └── # Add any other .py modules that you want here
Diagrama mostrando os passos básicos para criar um pacote instalável. Há 4 caixas com setas apontando para a direita. As caixas dizem: seu código, criar estrutura do pacote, adicionar metadata ao pyproject.toml e pip install pacote.

Depois que você tiver os itens básicos de um pacote Python (código, metadata e uma estrutura de arquivos), você pode pip install seu pacote em qualquer Python environment no seu computador.#

Sobre a estrutura básica de diretório do pacote#

Observe algumas coisas sobre o layout acima:

  1. O código do seu pacote fica dentro de um diretório src/packagename. Sugerimos que você use o diretório src (abreviação de source code) porque garante que você está executando testes na versão instalada do seu código.

  2. Dentro do diretório src, você tem um diretório de pacote chamado pyospackage. Use o nome do seu pacote para esse diretório. Este será o nome para importar seu pacote no código Python depois de instalado.

  3. No diretório do seu pacote, você tem um arquivo __init__.py e todos os seus Python modules. Você aprenderá mais sobre o arquivo __init__.py abaixo.

  4. O arquivo pyproject.toml fica no diretório raiz do seu pacote.

  5. O nome do diretório raiz do pacote é pyospackage, que é o nome do pacote. Isso não é obrigatório, mas você verá com frequência que o repositório do GitHub / GitLab e o nome do diretório raiz são os mesmos que o nome do pacote.

O que é um arquivo __init__.py?#

O arquivo __init__.py informa ao Python que um diretório deve ser tratado como um pacote Python. Assim, um diretório com um arquivo __init__.py pode ser importado diretamente no Python. O arquivo __init__.py não precisa conter nenhum código para o Python reconhecê-lo; ele pode estar vazio.

Por exemplo, seguindo o exemplo de estrutura de arquivos acima, que tem um arquivo __init__.py dentro dele, você pode executar:

import pyospackage

O que é um arquivo pyproject.toml?#

O arquivo pyproject.toml é:

  • Onde você define o metadata do seu projeto (incluindo nome, autores, license, etc.)

  • Onde você define dependências (os pacotes dos quais ele depende)

  • Usado para especificar e configurar qual build backend você quer usar para fazer o build do seu pacote.

Depois que os arquivos __init__.py e pyproject.toml forem adicionados, seu pacote pode ser construído e distribuído como um pacote Python instalável usando ferramentas como pip. Observe que o arquivo pyproject.toml precisa ter alguns itens básicos definidos para o pacote ser instalável, incluindo:

  • O build-backend que você quer usar,

  • O name e a version do projeto.

Por que o arquivo pyproject.toml é importante

O arquivo pyproject.toml substitui parte da funcionalidade dos arquivos setup.py e setup.cfg. Se você tentar pip install um pacote sem pyproject.toml, receberá o seguinte erro:

GitHub/pyospackage/testme
➜ python -m pip install .
ERROR: Directory '.' is not installable.
Neither 'setup.py' nor 'pyproject.toml' found.

Se o seu projeto já tiver um arquivo setup.py, o Hatch pode ser usado para criar automaticamente um pyproject.toml.

Notas de rodapé#