QGIS 2.16: processing.runalg falla cuando se ejecuta fuera de QGIS en una aplicación personalizada

8

Estoy desarrollando el paquete RQGIS. Para ejecutar QGIS desde R, llamo a QGIS a través de la línea de comando. Esto funcionó perfectamente con QGIS 2.14. Sin embargo, ejecutar el mismo código con QGIS 2.16 produce un error. Esto es lo que hago:

Primero, configuro todas las rutas necesarias en el símbolo del sistema:

@echo off
SET OSGEO4W_ROOT=D:\osgeo4w_qgis16
call "%OSGEO4W_ROOT%"\bin\o4w_env.bat
@echo off
path %PATH%;%OSGEO4W_ROOT%\apps\qgis\bin
set PYTHONPATH=%PYTHONPATH%;%OSGEO4W_ROOT%\apps\qgis\python;
set QGIS_PREFIX_PATH=%OSGEO4W_ROOT%\apps\qgis
rem open python     
python.exe

Posteriormente, ejecuto las siguientes líneas en Python:

import os
import sys
from qgis.core import *
import qgis.utils
from osgeo import ogr
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.gui import *
QgsApplication.setPrefixPath('D:\osgeo4w_qgis16\apps\qgis', True)
app = QgsApplication([], True)
QgsApplication.initQgis()
sys.path.append(r'D:\osgeo4w_qgis16\apps\qgis\python\plugins')
from processing.core.Processing import Processing
Processing.initialize()
import processing
processing.alglist()
processing.alghelp("grass7:v.voronoi")

Esto funciona. Sin embargo, llamando a processing.runalg ...

from processing.tests.TestData import points
result = processing.runalg('grass7:v.voronoi', points(), False, False, '270778.60198,270855.745301,4458921.97814,4458983.8488', -1, 0.0001, 0, None,)

... produce este mensaje de error:

Error in sys.excepthook:
Traceback (most recent call last):
  File "D:\osgeo4w_qgis16\apps\qgis\python\qgis\utils.py", line 196, in qgis_excepthook
    showException(type, value, tb, None, messagebar=True)
  File "D:\osgeo4w_qgis16\apps\qgis\python\qgis\utils.py", line 107, in showException
    open_stack_dialog(type, value, tb, msg)
  File "D:\osgeo4w_qgis16\apps\qgis\python\qgis\utils.py", line 142, in open_stack_dialog
    iface.messageBar().popWidget()
AttributeError: 'NoneType' object has no attribute 'messageBar'

Original exception was:
Traceback (most recent call last):
  File "<stdin>", line 10, in <module>
  File "D:\osgeo4w_qgis16\apps\qgis\python\plugins\processing\tools\general.py", line 75, in runalg
    alg = Processing.runAlgorithm(algOrName, None, *args, **kwargs)
  File "D:\osgeo4w_qgis16\apps\qgis\python\plugins\processing\core\Processing.py", line 304, in runAlgorithm
    ret = runalg(alg, progress)
  File "D:\osgeo4w_qgis16\apps\qgis\python\plugins\processing\gui\AlgorithmExecutor.py", line 52, in runalg
    progress.error(e.msg)
AttributeError: 'NoneType' object has no attribute 'error'
Jannes
fuente

Respuestas:

5

El error de procesamiento se corrigió recientemente, consulte https://github.com/qgis/QGIS/commit/df2ca2e60798315d816966f25aa024b93835f776

Victor Olaya
fuente
1
Víctor, aunque dijiste que el problema se solucionó, sigue vivo. Recientemente, QGIS 2.18 fue lanzado. Pero aún así hay que reemplazar manualmente alg.execute(progress)por alg.execute(progress or SilentProgress())en AlgorithmExecutor.py usar QGIS en una aplicación personalizada. El problema ha empeorado ya que ahora no hay ningún mensaje de error. En cambio, incluso hay mensajes de éxito (por ejemplo, cuando se ejecuta saga:catchmentarearecursive), solo las carpetas de salida especificadas permanecen vacías. Le agradecería mucho si pudiera solucionar ese problema. ¿O me estoy perdiendo algo?
Jannes
5

Barry, gracias por tu consejo. Aparentemente, el equipo central de QGIS cambió el código. En QGIS 2.14 runalgse definió de la siguiente manera:

def runalg(alg, progress=None):
  """Executes a given algorithm, showing its progress in the
  progress object passed along.

  Return true if everything went OK, false if the algorithm
  could not be completed.
  """

  if progress is None:
      progress = SilentProgress()
  try:
      alg.execute(progress)
      return True
  except GeoAlgorithmExecutionException as e:
      ProcessingLog.addToLog(sys.exc_info()[0], ProcessingLog.LOG_ERROR)
      progress.error(e.msg)
      return False

Entonces, si el progreso es igual a None(que es el caso en mi código de ejemplo), SilentProgresscuídalo. Por el contrario, en QGIS 2.16 se eliminó la instrucción if correspondiente (ver la respuesta de Barry más arriba), lo que conduce a la falla de runalg. Una solución sería editar manualmente el script AlgorithmExecutor.py agregando nuevamente las líneas faltantes. En este caso, uno tendría que agregar otra línea de importación al comienzo del script ( from processing.core.SilentProgress import SilentProgress).

También le preguntaré al equipo central de QGIS si hay una razón especial para la eliminación de estas líneas. Con un poco de suerte, los agregarán nuevamente ...

Jannes
fuente
¡agregar las 2 líneas anteriores y la declaración de importación al script AlgorithmExecutor.py funcionó para mí! Acabo de actualizarme a 2.16 la semana pasada y también me colgué. ¡Gracias!
rickD
Acabo de actualizar de 2.8.2 a 2.16.3 y encontré los mismos problemas con algunos scripts de Python externos que ejecuto. Hacer los cambios anteriores solucionó el problema para mí. Gracias Jannes y Spacedman.
BStone
4

Este último bit del error original:

  File "D:\osgeo4w_qgis16\apps\qgis\python\plugins\processing\gui\AlgorithmExecutor.py", line 52, in runalg
    progress.error(e.msg)
AttributeError: 'NoneType' object has no attribute 'error'

es decir que progresses None, por lo que la progress.errorfalla llamada. Esto activa la primera parte del error que se muestra porque el controlador de errores QGIS intenta escribir un mensaje en un objeto iface que tampoco existe.

El bit relevante del código de Python de Processing que genera el error original es:

def runalg(alg, progress=None):
    """Executes a given algorithm, showing its progress in the
    progress object passed along.

    Return true if everything went OK, false if the algorithm
    could not be completed.
    """
    try:
        alg.execute(progress)
        return True
    except GeoAlgorithmExecutionException as e:
        ProcessingLog.addToLog(sys.exc_info()[0], ProcessingLog.LOG_ERROR)
        progress.error(e.msg)  ## this line ##
        return False

Entonces, por alguna razón, el algoritmo ha generado una GeoAlgorithmExecutionException y progresses None. No sé de dónde progressdebe venir, quizás tu script de Python debería crear algo para pasarle. No sé si está generando el error GeoAlg tampoco, o cuál de los dos problemas es el que realmente necesita solucionar ...

Hombre espacial
fuente