Do traceback ao commit: resolvendo quebras de dependências no Python 3.11 e ajustando autenticação no Git
Voltar para blog

Do traceback ao commit: resolvendo quebras de dependências no Python 3.11 e ajustando autenticação no Git

25/09/2026 · 4 min · Desenvolvimento

Quem roda ferramentas e scripts de automação no Linux sabe que atualizar uma versão do interpretador Python pode quebrar dependências antigas em cadeia.

Recentemente, precisei rodar utilitários de varredura e segurança em um servidor AlmaLinux atualizado com Python 3.11 (como collectivesqlscanner e holehe) e enfrentei uma sequência clássica de atritos: módulos ausentes, refatorações do pacote upstream lxml, falhas em checagens de versão e prompts interativos travando o Git no terminal.

Abaixo, compartilho o relato técnico e o passo a passo exato de como diagnostiquei e corrigi cada uma dessas falhas na prática.


1. O problema inicial: ModuleNotFoundError: No module named 'requests_html'#

Ao executar a ferramenta principal diretamente no terminal com Python 3.11:

python3.11 main.py -d "ver?id="

O script falhou logo na inicialização das bibliotecas internas:

Traceback (most recent call last):
  File "/scripts/sql/collectivesqlscanner/main.py", line 1, in <module>
    from lib.sql import SQL
  File "/scripts/sql/collectivesqlscanner/lib/sql.py", line 2, in <module>
    from .search import Search
  File "/scripts/sql/collectivesqlscanner/lib/search.py", line 5, in <module>
    from requests_html import HTMLSession
ModuleNotFoundError: No module named 'requests_html'

Causa e resolução#

O Python 3.11 não possuía a biblioteca requests-html instalada no diretório de pacotes daquela versão específica (site-packages).

A correção direta foi instalar o módulo apontando explicitamente para o gerenciador de pacotes do Python 3.11:

pip3.11 install requests_html

2. A quebra estrutural do lxml: o caso lxml.html.clean#

Assim que o requests_html foi instalado e o script executado novamente, surgiu uma quebra estrutural provocada por mudanças na biblioteca lxml:

Traceback (most recent call last):
  File "/scripts/sql/collectivesqlscanner/main.py", line 1, in <module>
    from lib.sql import SQL
  File "/scripts/sql/collectivesqlscanner/lib/sql.py", line 2, in <module>
    from .search import Search
  File "/scripts/sql/collectivesqlscanner/lib/search.py", line 5, in <module>
    from requests_html import HTMLSession
  File "/usr/local/lib/python3.11/site-packages/requests_html.py", line 14, in <module>
    from lxml.html.clean import Cleaner
  File "/usr/local/lib64/python3.11/site-packages/lxml/html/clean.py", line 18, in <module>
    raise ImportError(
ImportError: lxml.html.clean module is now a separate project lxml_html_clean.
Install lxml[html_clean] or lxml_html_clean directly.

A pegadinha do lxml[html_clean]#

Seguindo a primeira sugestão da mensagem de erro, tentei instalar a extensão via extra:

pip3.11 install --upgrade "lxml[html_clean]"

A saída retornou um aviso:

Requirement already satisfied: lxml[html_clean] in /usr/local/lib64/python3.11/site-packages (6.0.1)
WARNING: lxml 6.0.1 does not provide the extra 'html_clean'

Ao rodar o script novamente, o mesmo ImportError continuou acontecendo.

Entendendo a raiz do erro#

A partir de versões recentes do lxml (como a 6.0.1), os mantenedores desacoplaram completamente o módulo clean do core da biblioteca para reduzir o tamanho do pacote e isolar o código de sanitização HTML. O subpacote passou a existir como um projeto independente no PyPI: lxml_html_clean.

Como o requests_html ainda faz a chamada legada from lxml.html.clean import Cleaner, ele depende da existência desse pacote avulso para manter a compatibilidade.

A solução definitiva#

A instalação direta do pacote separado resolveu a árvore de dependências:

pip3.11 install lxml_html_clean

Com isso, o módulo Cleaner voltou a responder no namespace esperado pelo requests_html.


3. Falha na checagem de versão no holehe (AttributeError: 'Response' object has no attribute 'json')#

Em paralelo, ao rodar a ferramenta OSINT de e-mails holehe, o script quebrou durante o loop assíncrono do trio:

Traceback (most recent call last):
  File "/usr/local/bin/holehe", line 33, in <module>
    sys.exit(load_entry_point('holehe==1.61', 'console_scripts', 'holehe')())
  File "/usr/local/lib/python3.11/site-packages/holehe-1.61-py3.11.egg/holehe/core.py", line 233, in main
    trio.run(maincore)
  File "/usr/local/lib/python3.11/site-packages/trio-0.31.0-py3.11.egg/trio/_core/_run.py", line 2547, in run
    raise runner.main_task_outcome.error
  File "/usr/local/lib/python3.11/site-packages/holehe-1.61-py3.11.egg/holehe/core.py", line 197, in maincore
    check_update()
  File "/usr/local/lib/python3.11/site-packages/holehe-1.61-py3.11.egg/holehe/core.py", line 68, in check_update
    if check_version.json()["info"]["version"] != __version__:
       ^^^^^^^^^^^^^^^^^^
AttributeError: 'Response' object has no attribute 'json'

Análise técnica#

A função check_update() dispara uma requisição HTTP para a API do PyPI para verificar se existe uma versão mais recente do holehe.

Quando essa requisição sofre um bloqueio de firewall, erro transitório de rede ou redirecionamento inesperado que devolve um objeto incompatível com o método .json(), a execução é interrompida logo na inicialização.

Como contornar#

  1. Testar Conectividade: Verificar se o servidor consegue resolver DNS e acessar endpoints externos via curl -I https://pypi.org/pypi/holehe/json.
  2. Bypass da Checagem: Utilizar parâmetros da CLI que desativem a checagem automática de versão na inicialização (como --no-update ou flags similares do projeto).

4. Atualização de código e autenticação no Git#

Para manter essas ferramentas alinhadas com as correções mais recentes dos repositórios, os comandos padrão são:

git clone https://github.com/usuario-exemplo/projeto-exemplo.git
git pull

O desafio da autenticação interativa#

Ao rodar git pull dentro do diretório do projeto:

[root@server:/scripts/sql/collectivesqlscanner]# git pull
Username for 'https://github.com':

O Git bloqueou a execução pedindo credenciais interativas. Em rotinas automatizadas no servidor, depender de login interativo via HTTPS é inviável.

Soluções de autenticação para servidores#

Opção 1: Chaves SSH (Padrão Recomendado)#

Evita senhas e dispensa prompts interativos.

  1. Gerar o par de chaves no servidor:
ssh-keygen -t ed25519 -C "usuario@dominio.com.br"
  1. Inicializar o agente e adicionar a chave:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
  1. Exibir a chave pública para cadastro no GitHub (Settings > SSH and GPG keys):
cat ~/.ssh/id_ed25519.pub
  1. Mudar a URL remota do repositório de HTTPS para SSH:
git remote set-url origin git@github.com:usuario-exemplo/projeto-exemplo.git
Opção 2: Personal Access Token (PAT)#

Como o GitHub descontinuou o uso de senhas de conta via HTTPS, é necessário gerar um token em Developer settings > Personal access tokens. Ao ser solicitado pelo Username, informe seu usuário; no campo Password, cole o token.

Opção 3: Cache de Credenciais#

Para quem opta por manter o transporte HTTPS:

git config --global credential.helper store

(Atenção: essa opção salva as credenciais em texto simples no arquivo ~/.git-credentials).


Boas práticas: isolando o ambiente com venv#

Grande parte dos conflitos de dependências em distribuições Linux corporativas (AlmaLinux, Rocky Linux ou Debian) ocorre quando pacotes são instalados diretamente no Python global do sistema.

Para proteger os scripts contra quebras em cascata, a prática mais segura é isolar o ambiente de cada ferramenta:

# Entrar no diretório do script
cd /scripts/sql/collectivesqlscanner/

# Criar o ambiente virtual com Python 3.11
python3.11 -m venv venv

# Ativar o ambiente virtual
source venv/bin/activate

# Instalar os pacotes isoladamente
pip install requests_html lxml_html_clean

Assim, cada ferramenta mantém seu próprio conjunto de bibliotecas sem interferir nas outras aplicações do servidor nem sofrer com atualizações do sistema operacional.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários