general.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. """
  2. ***************************************************************************
  3. general.py
  4. ---------------------
  5. Date : April 2013
  6. Copyright : (C) 2013 by Victor Olaya
  7. Email : volayaf at gmail dot com
  8. ***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************
  16. """
  17. __author__ = 'Victor Olaya'
  18. __date__ = 'April 2013'
  19. __copyright__ = '(C) 2013, Victor Olaya'
  20. from qgis.core import (QgsApplication,
  21. QgsProcessingAlgorithm,
  22. QgsProcessingParameterDefinition,
  23. QgsProcessingParameterEnum,
  24. QgsProcessingParameterFeatureSink,
  25. QgsProcessingParameterVectorDestination,
  26. QgsProcessingParameterRasterDestination,
  27. QgsProcessingOutputLayerDefinition,
  28. QgsProject)
  29. from processing.core.Processing import Processing
  30. from processing.gui.Postprocessing import handleAlgorithmResults
  31. from processing.gui.AlgorithmDialog import AlgorithmDialog
  32. from qgis.utils import iface
  33. def algorithmHelp(id):
  34. """
  35. Prints algorithm parameters with their types. Also
  36. provides information about parameters and outputs,
  37. and their acceptable values.
  38. :param id: An algorithm's ID
  39. :type id: str
  40. """
  41. alg = QgsApplication.processingRegistry().algorithmById(id)
  42. if alg is not None:
  43. print(f'{alg.displayName()} ({alg.id()})\n')
  44. if alg.shortDescription():
  45. print(alg.shortDescription() + '\n')
  46. if alg.shortHelpString():
  47. print(alg.shortHelpString() + '\n')
  48. print('\n----------------')
  49. print('Input parameters')
  50. print('----------------')
  51. for p in alg.parameterDefinitions():
  52. if p.flags() & QgsProcessingParameterDefinition.FlagHidden:
  53. continue
  54. print(f'\n{p.name()}: {p.description()}')
  55. if p.help():
  56. print(f'\n\t{p.help()}')
  57. print(f'\n\tParameter type:\t{p.__class__.__name__}')
  58. if isinstance(p, QgsProcessingParameterEnum):
  59. opts = []
  60. for i, o in enumerate(p.options()):
  61. opts.append(f'\t\t- {i}: {o}')
  62. print('\n\tAvailable values:\n{}'.format('\n'.join(opts)))
  63. parameter_type = QgsApplication.processingRegistry().parameterType(p.type())
  64. accepted_types = parameter_type.acceptedPythonTypes() if parameter_type is not None else []
  65. if accepted_types:
  66. opts = []
  67. for t in accepted_types:
  68. opts.append(f'\t\t- {t}')
  69. print('\n\tAccepted data types:')
  70. print('\n'.join(opts))
  71. print('\n----------------')
  72. print('Outputs')
  73. print('----------------')
  74. for o in alg.outputDefinitions():
  75. print(f'\n{o.name()}: <{o.__class__.__name__}>')
  76. if o.description():
  77. print('\t' + o.description())
  78. else:
  79. print(f'Algorithm "{id}" not found.')
  80. def run(algOrName, parameters, onFinish=None, feedback=None, context=None, is_child_algorithm=False):
  81. """
  82. Executes given algorithm and returns its outputs as dictionary object.
  83. :param algOrName: Either an instance of an algorithm, or an algorithm's ID
  84. :param parameters: Algorithm parameters dictionary
  85. :param onFinish: optional function to run after the algorithm has completed
  86. :param feedback: Processing feedback object
  87. :param context: Processing context object
  88. :param is_child_algorithm: Set to True if this algorithm is being run as part of a larger algorithm,
  89. i.e. it is a sub-part of an algorithm which calls other Processing algorithms.
  90. :returns algorithm results as a dictionary, or None if execution failed
  91. :rtype: Union[dict, None]
  92. """
  93. if onFinish or not is_child_algorithm:
  94. return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
  95. else:
  96. # for child algorithms, we disable to default post-processing step where layer ownership
  97. # is transferred from the context to the caller. In this case, we NEED the ownership to remain
  98. # with the context, so that further steps in the algorithm have guaranteed access to the layer.
  99. def post_process(_alg, _context, _feedback):
  100. return
  101. return Processing.runAlgorithm(algOrName, parameters, onFinish=post_process, feedback=feedback, context=context)
  102. def runAndLoadResults(algOrName, parameters, feedback=None, context=None):
  103. """
  104. Executes given algorithm and load its results into the current QGIS project
  105. when possible.
  106. :param algOrName: Either an instance of an algorithm, or an algorithm's ID
  107. :param parameters: Algorithm parameters dictionary
  108. :param feedback: Processing feedback object
  109. :param context: Processing context object
  110. :returns algorithm results as a dictionary, or None if execution failed
  111. :rtype: Union[dict, None]
  112. """
  113. if isinstance(algOrName, QgsProcessingAlgorithm):
  114. alg = algOrName
  115. else:
  116. alg = QgsApplication.processingRegistry().createAlgorithmById(algOrName)
  117. # output destination parameters to point to current project
  118. for param in alg.parameterDefinitions():
  119. if not param.name() in parameters:
  120. continue
  121. if isinstance(param, (QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination,
  122. QgsProcessingParameterRasterDestination)):
  123. p = parameters[param.name()]
  124. if not isinstance(p, QgsProcessingOutputLayerDefinition):
  125. parameters[param.name()] = QgsProcessingOutputLayerDefinition(p, QgsProject.instance())
  126. else:
  127. p.destinationProject = QgsProject.instance()
  128. parameters[param.name()] = p
  129. return Processing.runAlgorithm(alg, parameters=parameters, onFinish=handleAlgorithmResults, feedback=feedback,
  130. context=context)
  131. def createAlgorithmDialog(algOrName, parameters={}):
  132. """
  133. Creates and returns an algorithm dialog for the specified algorithm, prepopulated
  134. with a given set of parameters. It is the caller's responsibility to execute
  135. and delete this dialog.
  136. :param algOrName: Either an instance of an algorithm, or an algorithm's ID
  137. :param parameters: Initial algorithm parameters dictionary
  138. :returns algorithm results as a dictionary, or None if execution failed
  139. :rtype: Union[dict, None]
  140. """
  141. if isinstance(algOrName, QgsProcessingAlgorithm):
  142. alg = algOrName.create()
  143. else:
  144. alg = QgsApplication.processingRegistry().createAlgorithmById(algOrName)
  145. if alg is None:
  146. return None
  147. dlg = alg.createCustomParametersWidget(iface.mainWindow())
  148. if not dlg:
  149. dlg = AlgorithmDialog(alg, parent=iface.mainWindow())
  150. dlg.setParameters(parameters)
  151. return dlg
  152. def execAlgorithmDialog(algOrName, parameters={}):
  153. """
  154. Executes an algorithm dialog for the specified algorithm, prepopulated
  155. with a given set of parameters.
  156. :param algOrName: Either an instance of an algorithm, or an algorithm's ID
  157. :param parameters: Initial algorithm parameters dictionary
  158. :returns algorithm results as a dictionary, or None if execution failed
  159. :rtype: Union[dict, None]
  160. """
  161. dlg = createAlgorithmDialog(algOrName, parameters)
  162. if dlg is None:
  163. return {}
  164. canvas = iface.mapCanvas()
  165. prevMapTool = canvas.mapTool()
  166. dlg.show()
  167. dlg.exec_()
  168. if canvas.mapTool() != prevMapTool:
  169. try:
  170. canvas.mapTool().reset()
  171. except:
  172. pass
  173. canvas.setMapTool(prevMapTool)
  174. results = dlg.results()
  175. # make sure the dialog is destroyed and not only hidden on pressing Esc
  176. dlg.close()
  177. return results