inspect.ispackage é uma função adicionada ao módulo inspect para verificar se um objeto de módulo representa um pacote Python. Embora pareça uma verificação simples, ela resolve um problema recorrente em ferramentas de introspecção, geradores de documentação, sistemas de plugins, analisadores de projetos e utilitários que percorrem módulos dinamicamente.
Neste guia, você vai entender o que caracteriza um pacote, como usar inspect.ispackage, como manter compatibilidade com versões anteriores, quais erros evitar e em quais cenários a função realmente melhora seu código.
O que é um pacote Python
Um pacote é um módulo capaz de conter outros módulos ou subpacotes. Tradicionalmente, ele é representado por um diretório com um arquivo __init__.py, embora pacotes de namespace também possam existir sem esse arquivo. Durante a importação, o Python registra metadados no objeto do módulo, como __spec__, __package__ e, em muitos casos, __path__.
Antes de inspect.ispackage, era comum verificar manualmente a presença de __path__. Essa técnica funciona em muitos casos, mas espalha detalhes de implementação pelo código e pode gerar decisões inconsistentes entre ferramentas.
Uso básico
import inspect
import pathlib
import json
print(inspect.ispackage(pathlib))
print(inspect.ispackage(json))
O resultado é verdadeiro quando o objeto representa um pacote e falso para módulos comuns, funções, classes e outros objetos. A função espera um objeto já importado. Ela não recebe diretamente uma string com o nome do pacote.
Importando antes de verificar
import importlib
import inspect
def verificar_nome(nome):
modulo = importlib.import_module(nome)
return inspect.ispackage(modulo)
print(verificar_nome("email"))
print(verificar_nome("math"))
Esse padrão é útil em ferramentas que recebem nomes configuráveis. Porém, importar código arbitrário pode executar efeitos colaterais definidos pelo pacote. Em sistemas de plugins, valide a origem, use ambientes controlados e não trate nomes fornecidos por usuários como automaticamente confiáveis.
Compatibilidade com versões anteriores
Bibliotecas que ainda suportam versões sem inspect.ispackage podem oferecer um fallback centralizado.
import inspect
def eh_pacote(objeto):
funcao = getattr(inspect, "ispackage", None)
if funcao is not None:
return funcao(objeto)
return inspect.ismodule(objeto) and hasattr(objeto, "__path__")
Esse fallback mantém a regra em um único lugar. Evite espalhar verificações de versão ou testes de atributos por todo o projeto.
Diferença entre módulo e pacote
Todo pacote importado é um módulo, mas nem todo módulo é um pacote. Portanto, inspect.ismodule(objeto) pode retornar verdadeiro para ambos. inspect.ispackage refina a classificação e responde se aquele módulo pode atuar como contêiner de submódulos.
import inspect
import math
import email
for objeto in (math, email):
print(
objeto.__name__,
inspect.ismodule(objeto),
inspect.ispackage(objeto),
)
Explorando submódulos com pkgutil
Uma aplicação comum é percorrer apenas objetos que realmente são pacotes.
import inspect
import pkgutil
import email
if inspect.ispackage(email):
for item in pkgutil.iter_modules(email.__path__):
print(item.name, item.ispkg)
pkgutil.iter_modules trabalha com os caminhos do pacote. A checagem explícita torna a intenção clara e evita tentar acessar __path__ em um módulo comum.
Sistema de plugins
Em um sistema de plugins, você pode aceitar um pacote raiz e procurar módulos internos que sigam uma convenção.
import importlib
import inspect
import pkgutil
def descobrir_plugins(nome_pacote):
raiz = importlib.import_module(nome_pacote)
if not inspect.ispackage(raiz):
raise TypeError(f"{nome_pacote} não é um pacote")
encontrados = []
for info in pkgutil.iter_modules(raiz.__path__, raiz.__name__ + "."):
if info.name.endswith("_plugin"):
encontrados.append(info.name)
return encontrados
Descobrir nomes não exige necessariamente importar todos os submódulos. Isso reduz efeitos colaterais e melhora o tempo de inicialização.
Geradores de documentação
Ferramentas de documentação precisam decidir se devem listar somente membros do módulo ou também percorrer filhos. inspect.ispackage fornece uma condição semântica clara. Ainda assim, não importe indiscriminadamente toda a árvore: alguns módulos são opcionais, dependem do sistema operacional ou executam inicialização cara.
Pacotes de namespace
Pacotes de namespace permitem distribuir partes do mesmo namespace em diferentes diretórios. Eles podem não possuir __init__.py, mas continuam sendo pacotes do ponto de vista do sistema de importação. Uma API oficial é preferível a depender de uma regra baseada exclusivamente na estrutura física do diretório.
Não confunda pacote instalado com pacote importado
inspect.ispackage classifica um objeto em memória. Ela não verifica se uma distribuição está instalada no ambiente, não consulta metadados do gerenciador de pacotes e não confirma a versão instalada. Para isso, use importlib.metadata.
from importlib.metadata import version, PackageNotFoundError
try:
print(version("requests"))
except PackageNotFoundError:
print("distribuição não instalada")
O nome da distribuição também pode ser diferente do nome importado. Essa distinção evita muitos erros em ferramentas de diagnóstico.
Não use para validar segurança
Ser um pacote não significa que o código seja seguro, confiável ou autorizado. A função apenas classifica o objeto. Se sua aplicação carrega extensões, aplique listas permitidas, assinaturas, isolamento de processo e permissões mínimas.
Tratamento de erros
import importlib
import inspect
def descrever(nome):
try:
objeto = importlib.import_module(nome)
except ModuleNotFoundError:
return {"nome": nome, "encontrado": False}
except Exception as erro:
return {"nome": nome, "encontrado": True, "erro": str(erro)}
return {
"nome": nome,
"encontrado": True,
"pacote": inspect.ispackage(objeto),
}
Não capture todos os erros e finja que o módulo não existe. Uma dependência ausente dentro do pacote, por exemplo, é diferente de o pacote raiz não ter sido encontrado.
Testes recomendados
Teste ao menos um módulo comum, um pacote tradicional e, quando seu projeto depender disso, um pacote de namespace. Teste também o fallback em uma função isolada. Evite alterar globalmente o módulo inspect durante testes concorrentes.
Desempenho
A classificação em si é barata. O custo relevante costuma estar na importação e na descoberta dos submódulos. Faça cache somente quando tiver evidência de necessidade e lembre que ambientes de desenvolvimento podem alterar módulos durante recargas.
Boas práticas
Centralize a compatibilidade, separe descoberta de importação, registre falhas com contexto e prefira nomes totalmente qualificados. Não dependa da ordem retornada pelo sistema de arquivos; ordene resultados quando a previsibilidade for importante.
Conteúdos relacionados
Veja também os conteúdos da Academify sobre módulos e pacotes, importlib, ambientes virtuais e publicação de pacotes. Consulte a documentação oficial de inspect e a referência do sistema de importação.
Conclusão
inspect.ispackage torna explícita uma classificação que antes dependia de verificações manuais. Ela é especialmente útil em introspecção, plugins, documentação e análise de módulos. Use-a sobre objetos importados, mantenha um fallback quando necessário e não confunda classificação estrutural com instalação, confiança ou segurança.







