OR-Tools (backend opcional)¶
O logis roda somente com PyQGIS + a biblioteca padrão do Python. O Google OR-Tools é um backend opcional de otimização: quando está presente, os algoritmos de roteirização por nós (TSP e CVRP) podem delegar a solução a ele; quando não está — ou está quebrado —, o plugin usa as heurísticas em Python puro, que são o padrão obrigatório. Nada no logis deixa de funcionar por causa do OR-Tools.
Onde o OR-Tools entra no logis¶
O OR-Tools entra apenas na roteirização por nós — TSP e CVRP — e somente
quando o parâmetro BACKEND resolve para "ortools". Todo o resto do plugin é
Python puro, sem exceção.
| Família de algoritmos | Usa OR-Tools? | Backend |
|---|---|---|
TSP (logis:vrp_tsp) — euclidiano e em rede |
Sim, via BACKEND |
auto / python / ortools |
CVRP (logis:vrp_cvrp) — euclidiano e em rede |
Sim, via BACKEND |
auto / python / ortools |
| Arc Routing (CPP, RPP, CARP) | Não | Python puro sempre |
| Localização de instalações (p-mediana, MCLP, LSCP) | Não | Python puro sempre |
| Indicadores (urbanos, regionais, resíduos) | Não | Python puro sempre |
Política de falha — três modos e uma saída imediata¶
O plugin trata três situações em que o OR-Tools não pode ser usado, mais um atalho para quem não quer correr risco nenhum:
| Modo | O que acontece | Comportamento do plugin |
|---|---|---|
| Ausente — pacote não instalado | import ortools levanta ImportError |
pick_backend() devolve "python" e registra aviso no Log de Mensagens (aba logis). A roteirização sai pela heurística Python pura. |
Quebrado / erro de import — pacote instalado mas não importável (típico de Linux com versão de numpy ou protobuf incompatível) |
import ortools levanta ImportError ou outra exceção |
Mesmo comportamento: fallback automático para "python" com aviso. |
Abort nativo — o import derruba o processo do QGIS (fecha sem exceção, sem log) |
O selo ortools_guard.json fica congelado em stage = "importing" |
Na sessão seguinte, guard_state() lê blocked → pick_backend() devolve "python" sem sequer tentar o import. O status aparece em vermelho no diálogo Dependências; o rearme é pelo botão Reativar OR-Tools no mesmo diálogo. |
Saída imediata — "Python puro": em qualquer das três situações — ou mesmo
com o OR-Tools perfeitamente funcional —, escolher BACKEND = 1 — Python puro
(heurística) no parâmetro do algoritmo (ou no combo Backend de otimização do
painel) impede qualquer import do OR-Tools. É o modo seguro quando o
carregamento da biblioteca derruba o QGIS: o cálculo sai inteiramente pela
heurística nativa, sem tocar no OR-Tools.
A execução é em segundo plano — e a interface não congela mais. O painel
logis — Roteirização despacha TSP e CVRP ao gerenciador de tarefas do QGIS:
o cálculo corre numa thread de trabalho, com barra de progresso e botão
Cancelar (ver Guia de Roteirização §8).
Isso muda o diagnóstico de um sintoma que antes se creditava ao OR-Tools: a
janela travada durante os segundos da busca era da arquitetura do painel, que
rodava o algoritmo dentro do laço da interface, e não do OR-Tools. Com a
execução em segundo plano, o congelamento deixou de existir nos dois backends —
inclusive com o limite de tempo de 10 segundos do GUIDED_LOCAL_SEARCH. O que
continua sendo do OR-Tools é o abort nativo da tabela acima (o processo
fecha, sem exceção e sem log) e o atraso descrito no guia para o cancelamento
durante uma busca sem soluções novas.
O comando de instalação é uma regra, não um comando fixo¶
O comando não pode ser copiado de um tutorial e colado em qualquer máquina: ele é montado a partir do ambiente Python do QGIS onde vai rodar. A regra é:
- instalar
ortools; - acrescentar
nome==versão_instaladapara cada um denumpy,pandasetyping_extensionsque já esteja presente no ambiente (módulo ausente fica de fora do comando, deixando o resolvedor do pip escolher); - passar
--only-binary=:all:, para nunca tentar compilar o pacote.
Fixar nome==versão_instalada garante que o pip não substitua nem altere as versões
dos pacotes que o QGIS já carrega no seu sys.path — o requisito já está satisfeito e o
pip não toca no pacote instalado.
Num ambiente em que numpy 2.1.3, pandas 2.2.3 e typing_extensions 4.12.2 estejam
presentes, a regra produz:
python3 -m pip install --user --only-binary=:all: \
ortools numpy==2.1.3 pandas==2.2.3 typing_extensions==4.12.2
Em outra máquina, com outras versões — ou sem o pandas, por exemplo —, o comando
correto é outro. É por isso que o plugin monta o comando na hora
(core.ortools_installer.build_command(), e command_text() para a linha pronta para
cópia) em vez de guardar uma linha literal.
Por que a trava antiga quebra em Python 3.13¶
A forma antiga do comando fixava faixas em vez de versões instaladas:
# NÃO use — quebra em Python 3.13
pip install ortools "pandas<3" "numpy<2" "typing_extensions==4.10.0"
Ela funcionou no QGIS 3.34 (Python 3.10/3.11), mas falha no QGIS 4.2+ e no Flatpak, que usam Python 3.13, por dois motivos que se somam:
- não existe wheel de
numpy 1.xparacp313— a travanumpy<2não tem candidato binário nesse interpretador; e ortools>=9.15exigenumpy>=2.0.2— ou seja, a trava contradiz diretamente o pacote que se está instalando, e o pip termina emResolutionImpossible.
A regra nome==versão_instalada não tem esse problema: ela acompanha o ambiente em vez
de impor uma faixa histórica.
Debian/Ubuntu — --break-system-packages¶
Quando o Python usado é o do sistema em distros com PEP 668
(Debian, Ubuntu), o pip recusa a instalação com externally-managed-environment. Nesse
caso, acrescente --break-system-packages ao comando:
python3 -m pip install --user --only-binary=:all: --break-system-packages \
ortools numpy==2.1.3 ...
Quem roda o pip é você, então esse ajuste é seu: se a saída trouxer
externally-managed-environment, repita o comando com a opção acrescentada.
Windows e macOS — use o Python do QGIS¶
O que importa é qual interpretador recebe o pacote: precisa ser o mesmo que o QGIS
usa, senão o import ortools dentro do QGIS continuará falhando.
No Windows há uma armadilha a mais, e ela já derrubou o comando antigo. Dentro do QGIS,
sys.executable não aponta para um Python: aponta para o qgis-bin.exe, porque o
QGIS embarca o interpretador no próprio executável. Um comando montado com esse valor
sai assim —
REM NÃO funciona — qgis-bin.exe não é um interpretador
"C:\Program Files\QGIS 3.34\bin\qgis-bin.exe" -m pip install ortools ...
— e não instala nada: o binário do QGIS não entende -m pip. Por isso o plugin resolve
o python.exe do QGIS (core.ortools_installer.python_executable()), que em geral fica
em …\apps\Python3xx\python.exe, e escreve esse caminho no comando que exibe:
"C:\Program Files\QGIS 3.34\apps\Python312\python.exe" -m pip install --user ^
--only-binary=:all: --disable-pip-version-check ortools numpy==2.1.3 ...
Com o caminho completo na linha, o comando funciona tanto no OSGeo4W Shell (instalado
junto com o QGIS) quanto no Prompt de Comando comum — não é mais preciso que o console
já aponte para o Python certo. O que continua não servindo é trocar esse caminho pelo
python do PATH do Windows: é outro interpretador, e o QGIS não enxerga o que for
instalado nele.
No macOS vale a mesma ideia, sem a armadilha: o comando aponta para o Python embarcado
na instalação do QGIS (/Applications/QGIS.app/Contents/MacOS/bin/python3).
O interpretador que o plugin resolveu aparece na linha de Ambiente detectado do diálogo Dependências — é ali que se confere, antes de instalar, se o pacote vai para o Python certo.
O diálogo “Dependências” do plugin¶
Em vez de montar o comando na mão, use Complementos → logis → Dependências…, que abre o logis — Gerenciador de Dependências.
O botão “Instalar OR-Tools agora”¶
O caminho curto é o botão Instalar OR-Tools agora, que aparece enquanto o OR-Tools não
estiver disponível (se não houver pip no ambiente, ele fica desabilitado e sobra o
comando manual). Ao clicar:
- o diálogo pede confirmação, avisando que o pip vai baixar algumas dezenas de MB e que a janela do QGIS pode ficar sem resposta durante o processo;
- a instalação roda no Python do próprio QGIS — o mesmo interpretador que depois vai importar a biblioteca —, aplicando a mesma regra de comando descrita acima;
- enquanto roda, o cursor vira relógio e a janela pode ficar sem resposta por alguns instantes: é esperado, não é travamento;
- o log do pip aparece na tela, na caixa escura abaixo do botão. É ali que se lê o
motivo de uma falha — sem rede, sem permissão, sem wheel para este Python, conflito de
numpy. Em ambientes PEP 668 (Debian/Ubuntu), a flag--break-system-packagesjá entra sozinha, decidida pela detecção de ambiente.
No fim há três desfechos, e o diálogo diz qual foi:
- instalado e já disponível — o
import ortoolspassa a funcionar na hora, sem reiniciar nada; - instalado, mas é preciso reiniciar o QGIS — o pip terminou bem e o interpretador ainda não enxerga a biblioteca; reinicie e ela entra;
- a instalação falhou — o log fica visível, o comando manual continua ali para copiar e rodar no terminal, e o plugin segue funcionando com as heurísticas em Python puro.
A linha de “Ambiente detectado”¶
Logo acima do botão, uma linha resume o que o plugin viu na máquina: sistema
operacional, versão do Python, caminho do interpretador que vai receber o
pacote, se o pip está disponível, se o ambiente é gerenciado externamente
(PEP 668) e se o QGIS roda em Flatpak ou Snap.
Ela existe para responder, antes de qualquer tentativa, as perguntas que explicam quase
toda falha de instalação: é mesmo o Python do QGIS?, há pip aqui?, vai precisar de
--break-system-packages?, estou dentro de um sandbox?. É também a linha a colar num
relato de problema.
O comando manual continua disponível¶
Para quem prefere o terminal — ou quando o botão falha —, o mesmo bloco ainda:
- mostra o status — Instalado (Disponível) ou Não instalado (Heurística pura ativada);
- monta e exibe o comando aplicando a regra acima com as versões detectadas na hora, já apontando para o interpretador do QGIS;
- copia essa linha para a área de transferência no botão Copiar Comando;
- lista os passos seguintes: abrir o terminal (ou o OSGeo4W Shell, no Windows), colar e executar o comando, e reiniciar o QGIS para que a biblioteca seja carregada.
O que o plugin não faz é executar processo externo: nenhum arquivo sob logis/ chama
subprocess, para não acionar o achado B603 do scanner do plugins.qgis.org. A
instalação pelo botão acontece dentro do processo do QGIS, chamando a API do pip
(core.ortools_installer.install_ortools(), com o ponto de entrada do pip resolvido em
try/except e fallback para o comando manual se ele não estiver acessível) — é por isso
que o log do pip sai na janela do diálogo, e não num terminal. Quando a instalação é feita
à mão, os erros do pip aparecem no seu terminal. Em qualquer um desses casos o plugin
segue funcionando com a heurística em Python puro.
O mesmo diálogo mostra o estado do GisBR (fonte de dados viários).
Fallback automático para as heurísticas em Python puro¶
A detecção é sempre lazy e protegida: o import ortools só acontece na hora do uso e
qualquer exceção é capturada (core.optim_backend.has_ortools()). A escolha do backend
passa por core.optim_backend.pick_backend():
- pedir
backend="ortools"com a biblioteca disponível → resolve para"ortools"; - pedir
backend="ortools"sem a biblioteca (ausente, quebrada, ou instalada em outro interpretador) → cai automaticamente para"python"e registra um aviso no painel de Log de Mensagens do QGIS, abalogis; backend="python"(o padrão) → usa a heurística direto.
Ou seja: o resultado sai de qualquer jeito. Com o OR-Tools ele tende a ser melhor e mais rápido; sem ele, sai pela heurística clássica (Vizinho Mais Próximo + 2-opt/Or-opt no TSP, Clarke-Wright + 2-opt/Or-opt no CVRP) — soluções boas, não necessariamente ótimas.
A trava automática: quando o OR-Tools é desativado sozinho¶
O fallback da seção anterior cobre o OR-Tools ausente ou quebrado — casos em que o
import levanta exceção e o plugin a captura. Há um caso que nenhum try/except pega: o
import de uma biblioteca compilada pode derrubar o processo inteiro do QGIS, que
fecha sem mensagem de erro e sem log. Para não repetir o tombo a cada execução, o plugin
guarda um selo em ortools_guard.json, no cache (QStandardPaths.CacheLocation →
.../logis/):
- antes de importar o OR-Tools, grava o selo com
stage = "importing"; - voltando do import, regrava com
stage = "ok".
Se o QGIS morre no meio do import, o selo fica congelado em "importing". Na sessão
seguinte core.optim_backend.guard_state() lê esse selo como blocked, e a partir
daí pick_backend() devolve "python" sem sequer tentar o import, registrando no Log de
Mensagens do QGIS (aba logis) a linha "OR-Tools foi desativado porque o QGIS fechou
durante a última tentativa de carregá-lo."
O que significa ver o OR-Tools desativado¶
No diálogo Dependências o status aparece em vermelho como Bloqueado (o QGIS fechou durante o carregamento do OR-Tools; o plugin está usando a heurística Python), e o painel de roteirização abre cada execução com um aviso em amarelo dizendo o mesmo.
Isso não quer dizer que a instalação falhou nem que o pacote sumiu: ele pode estar
perfeitamente instalado. Quer dizer que a última tentativa de carregá-lo coincidiu com o
fechamento do QGIS, e que o plugin optou por não arriscar de novo. Enquanto a trava
estiver ativa, todos os algoritmos continuam disponíveis pelas heurísticas em Python puro
— o que muda é só a qualidade possível da solução, nunca a existência dela. O passo a
passo de confirmação (última linha do diagnostico.log e o teste de import de uma linha
no Console Python) está no
Guia de Roteirização.
Onde fica o botão “Reativar OR-Tools”¶
Em Complementos → logis → Dependências…, na mesma linha do status do OR-Tools, logo à direita dele. O botão só fica habilitado quando a trava está ativa; no estado normal ele aparece esmaecido, porque não há nada para rearmar.
Clicar nele apaga o selo (core.optim_backend.reset_ortools_guard()) e atualiza o
status na hora. A partir daí a próxima roteirização volta a tentar o OR-Tools
normalmente — e, se o QGIS fechar outra vez durante o import, a trava se arma de novo
sozinha. É o botão a usar depois de reinstalar, atualizar ou remover o pacote, ou quando
se quer conferir se o problema já passou.
Ambientes onde a instalação pode simplesmente não dar¶
Em instalações isoladas — QGIS Flatpak ou Snap com Python 3.13 — pode não existir
pacote binário do OR-Tools para o interpretador do QGIS, e --only-binary=:all: impede a
compilação local. O pip termina em No matching distribution found.
Isso vale para os dois caminhos: o botão do diálogo também falha ali, pelo mesmo motivo de sempre — não há wheel para o Python do QGIS —, e o log na tela mostra exatamente essa mensagem. Nada precisa ser feito: todos os algoritmos continuam disponíveis com as heurísticas em Python puro.