<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>Hi Nyall,</div><div><br></div><div>thanks for your feedback.</div><div>You are right that some of my examples were not ideal to explain what I meant, so I try to explain it a bit better this time ;-)</div><div><br></div><div></div><div><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC2" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">Some of the following pyqgis-examples may be outdated <span class="gmail-pl-k">as</span> things can be done easier <span class="gmail-pl-k">in</span> qgis3 now but they should just be an example </td>
      </tr>
      <tr>
        </tr></tbody></table><span class="gmail-pl-k">for</span> some functions that were written by users to make life easier during the development of <span class="gmail-pl-c1">QGIS</span> plugins.<br></div><div><br></div><div><br></div><div>Example1: QgsVectorlayer:<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Mi., 20. Feb. 2019 um 10:29 Uhr schrieb Nyall Dawson <<a href="mailto:nyall.dawson@gmail.com">nyall.dawson@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
This is a single line via the existing API :<br>
<br>
    vl = QgsVectorLayer( '/home/me/my.shp' , 'my_layer' )<br>
<br>
I'm curious to hear how this could be improved?<br></blockquote><div><br></div><div>I wrote "<span class="gmail-im">load a vectorlayer</span>" but meant "create

<span class="gmail-im">a vectorlayer</span>"

<br></div><div><br></div><div>Something like:</div><div><br></div><div><a href="https://gist.github.com/rdbath/bbba7640cf98ab09dc9bb6018011f05e#file-pyqgis_common_functions_examples-py-L24">https://gist.github.com/rdbath/bbba7640cf98ab09dc9bb6018011f05e#file-pyqgis_common_functions_examples-py-L24</a><br></div><div><br></div><div><br></div><div>Example2: For loading layer I meant something like <br></div><div><br></div><div><a href="https://gist.github.com/rdbath/bbba7640cf98ab09dc9bb6018011f05e#file-pyqgis_common_functions_examples-py-L7">https://gist.github.com/rdbath/bbba7640cf98ab09dc9bb6018011f05e#file-pyqgis_common_functions_examples-py-L7</a>:</div><div><br></div><div><br></div><div>
<table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC7" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line gmail-highlighted"><span class="gmail-pl-k">def</span> <span class="gmail-pl-en">load_layer</span>(<span class="gmail-pl-smi">filename</span>, <span class="gmail-pl-smi">name</span> <span class="gmail-pl-k">=</span> <span class="gmail-pl-c1">None</span>):</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC8" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">    <span class="gmail-pl-s"><span class="gmail-pl-pds">'''</span></span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC9" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line"><span class="gmail-pl-s">    Tries to load a layer from the given file</span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC10" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line"><span class="gmail-pl-s">    :param filename: the path to the file to load.</span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC11" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line"><span class="gmail-pl-s">    :param name: the name to use for adding the layer to the current project.</span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC12" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line"><span class="gmail-pl-s">    If not passed or None, it will use the filename basename</span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC13" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line"><span class="gmail-pl-s">    <span class="gmail-pl-pds">'''</span></span></td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC14" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">    name <span class="gmail-pl-k">=</span> name <span class="gmail-pl-k">or</span> os.path.splitext(os.path.basename(filename))[<span class="gmail-pl-c1">0</span>]</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC15" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">    qgslayer <span class="gmail-pl-k">=</span> QgsVectorLayer(filename, name, <span class="gmail-pl-s"><span class="gmail-pl-pds">'</span>ogr<span class="gmail-pl-pds">'</span></span>)</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC16" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">    <span class="gmail-pl-k">if</span> <span class="gmail-pl-k">not</span> qgslayer.isValid():</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC17" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">        qgslayer <span class="gmail-pl-k">=</span> QgsRasterLayer(filename, name)</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC18" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">        <span class="gmail-pl-k">if</span> <span class="gmail-pl-k">not</span> qgslayer.isValid():</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC19" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">            <span class="gmail-pl-k">raise</span> <span class="gmail-pl-c1">RuntimeError</span>(<span class="gmail-pl-s"><span class="gmail-pl-pds">'</span>Could not load layer: <span class="gmail-pl-pds">'</span></span> <span class="gmail-pl-k">+</span> <span class="gmail-pl-v">unicode</span>(filename))</td>
      </tr>
      <tr>
        </tr></tbody></table><table class="gmail-highlight gmail-tab-size gmail-js-file-line-container"><tbody><tr><td id="gmail-file-pyqgis_common_functions_examples-py-LC20" class="gmail-blob-code gmail-blob-code-inner gmail-js-file-line">
<br></td>
      </tr>
      <tr>
        </tr></tbody></table>    <span class="gmail-pl-k">return</span> qgslayer

</div><div><br></div><div>-----</div><div><br></div><div>Example3: Iterate through layers:<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
# all layers<br>
layers = [l.layer() for l in QgsProject.instance().layerTreeRoot().findLayers()]<br></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
# visible layers<br>
visible_layers = [l.layer() for l in<br>
QgsProject.instance().layerTreeRoot().findLayers() if l.isVisible()]<br>
<br>
Ok, not super-obvious in this case, but still quite concise ;)<br></blockquote><div><br></div><div>For the example of 
visible_layers = [l.layer() for l in QgsProject.instance().layerTreeRoot().findLayers() if l.isVisible()]  :</div><div> I would probably have needed some minutes to search in one of my plugins if I have used such a code snippet before or google gis.stackexchange ;-)</div><div>Probably I also wouldn't have written such a fancy nice one-liner to get these layers.</div><div><br></div><div>So if there would be a pyqgis-commons library where I would know that I just have to call a function "get_visible_layers" instead of  using
[l.layer() for l in<br>
QgsProject.instance().layerTreeRoot().findLayers() if l.isVisible()] 

I probably could use this in my next plugin without having to search/google how to do this.</div><div><br></div><div><br></div><div></div><div>Example4: show messages / log messages: <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> - show a message with different levels (info, warning, critical)<br>
<br>
iface.messageBar().pushWarning('blah','some message')<br>
iface.messageBar().pushInfo('blah','some message')<br>
iface.messageBar().pushCritical('blah','some message')<br>
<br></blockquote><div>
> - log messages<br>
> QgsMessageLog.logMessage('my plugin','something', Qgis.Critical)  <br></div><div><br></div><div><br></div><div><br></div><div>I had something in mind like the MessageManager of 
<span class="gmail-pl-s">Germán Carrillo:</span>

</div><div><br><a href="https://github.com/gacarrillor/AutoFields/blob/master/MessageManager.py">https://github.com/gacarrillor/AutoFields/blob/master/MessageManager.py</a> <br></div><div><br></div><div>I like the MessageManager because I can easily switch between the message-modes 
<span class="gmail-pl-c">'production' or 'debug.</span></div><div><span class="gmail-pl-c"><br></span></div><div><span class="gmail-pl-c">One other example would be the function 
<span class="gmail-pl-en">"display_warning_message_bar" </span>from the inasafe-utilities where I can show a short message and also provide a button to show more details about a warning:<br></span></div><div><span class="gmail-pl-c"><a href="https://github.com/inasafe/inasafe/blob/bd00bfeac510722b427544b186bfa10861749e51/safe/utilities/qgis_utilities.py#L132">https://github.com/inasafe/inasafe/blob/bd00bfeac510722b427544b186bfa10861749e51/safe/utilities/qgis_utilities.py#L132</a><br></span></div><div><span class="gmail-pl-c"><br></span></div><div><span class="gmail-pl-c"><br></span></div><div><span class="gmail-pl-c"><br></span></div><div> Example5: Settings:</div><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
> - reading setting, writing settings<br>
<br>
The QgsSettings class should make this straightforward<br></blockquote><div><br></div><div>Here I hat something in mind like the qgis-settingsmanager of opengis ( <a href="https://github.com/opengisch/qgissettingmanager">https://github.com/opengisch/qgissettingmanager</a> ).<br></div><div>I know it is not only a collection of python-/pyqt-functions but a 
<span class="gmail-text-gray-dark gmail-mr-2">whole python module</span>

but I still it is an example of how functionalities are provided to make the development of plugins easier.</div><div></div><div><br></div><div></div><div><br></div><div>So it is always about providing some helper functions that I could also write by myself but which will save time during development and can help me to do the things in a consistent way in all of my plugins.</div><div></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
I'm not saying we can't improve the PyQGIS experience, but I don't<br>
personally see these as good candidates.<br>
<br>
I think we have a LOT of work to do with things like:<br>
- throwing proper exceptions instead of crashing/returning "None"<br>
values/returning "invalid" objects (e.g. QgsGeometry.fromWkt should<br>
ideally raise an exception for invalid wkt instead of returning a null<br>
geometry)<br>
- providing Python-esque things like __repr__ methods, __len__, []<br>
operators (which behave in a python style, e.g. with -1 returning the<br>
last item), iterators, etc<br>
- providing more "context managers" (e.g. with .... : #something )<br></blockquote><div><br></div><div>I don't have such a deep insight in the QGIS-codebase but I guess this would probably have to be done in the C++-part of QGIS, wouldn't it?<br></div><div><br></div><div><br></div><div> (Definitely don't take this as a "don't proceed"... there is a VERY<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
STRONG need to improve the PyQGIS API/Documentation/examples, and this<br>
would be very valuable work!)<br>
<br></blockquote><div><br></div><div>I agree. Even if the PyQGIS-Documentation is now much better than in the past for me often some short examples like the ones from 
Thomas Gratier are really helpful to know how to proceed:<br></div><div><a href="https://webgeodatavore.github.io/pyqgis-samples/">https://webgeodatavore.github.io/pyqgis-samples/</a>  </div><div><br></div><div>So I see three ideas here:<br><br></div><div>- provide a collection of common PyQGIS-functions</div><div>- provide nice PyQGIS-examples</div><div>- 
improve the PyQGIS experience in generall (your examples like
throwing proper exception)

</div><div> </div><div><br></div><div>regards,</div><div>Thomas <br></div><div><br></div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Nyall<br>
<br>
><br>
><br>
><br>
> Wouldn't it be possible to provide such a collection not only from privat persons/projects but from the QGIS-project itself so users could add common functions?<br>
> I think the chances would be higher that such a "official" collection would be used in the long run and constantly extended.<br>
><br>
> Apart from the fact that developers could save time while writing their plugins this could perhaps also help to improve the overall quality of the qgis-plugins as there would probably be several persons who could/would countercheck these common functions to make sure they are well written.<br>
><br>
> regards,<br>
> Thomas<br>
><br>
> PS: I asked something similar also on gis.stackexchange recently:<br>
><br>
> <a href="https://gis.stackexchange.com/questions/311755/looking-for-common-pyqgis-functions-for-qgis-3" rel="noreferrer" target="_blank">https://gis.stackexchange.com/questions/311755/looking-for-common-pyqgis-functions-for-qgis-3</a><br>
><br>
><br>
><br>
><br>
> _______________________________________________<br>
> QGIS-Developer mailing list<br>
> <a href="mailto:QGIS-Developer@lists.osgeo.org" target="_blank">QGIS-Developer@lists.osgeo.org</a><br>
> List info: <a href="https://lists.osgeo.org/mailman/listinfo/qgis-developer" rel="noreferrer" target="_blank">https://lists.osgeo.org/mailman/listinfo/qgis-developer</a><br>
> Unsubscribe: <a href="https://lists.osgeo.org/mailman/listinfo/qgis-developer" rel="noreferrer" target="_blank">https://lists.osgeo.org/mailman/listinfo/qgis-developer</a><br>
</blockquote></div></div></div></div></div></div></div></div></div></div>