{"id":1776,"date":"2015-08-12T15:58:17","date_gmt":"2015-08-12T13:58:17","guid":{"rendered":"https:\/\/www.opengis.ch\/?p=1776"},"modified":"2020-04-29T16:05:41","modified_gmt":"2020-04-29T14:05:41","slug":"with-edit-layer","status":"publish","type":"post","link":"https:\/\/www.opengis.ch\/it\/2015\/08\/12\/with-edit-layer\/","title":{"rendered":"Syntactic sugar for PyQGIS"},"content":{"rendered":"<p>If you are a python coder you probably already know the <span class=\"lang:python decode:true  crayon-inline \">with<\/span>-statement.<br \/>\nIf yes, you can directly jump to the <a href=\"#with-edit\">with edit<\/a>-section.<br \/>\nIf not, here&#8217;s a short summing up.<br \/>\nIf you want to edit a file you can do:<\/p>\n<pre class=\"lang:python decode:true\">f = open('file', 'w')\ndo_some_changes_to(f)\nf.write()<\/pre>\n<p>This is a bad idea. The file is not closed and <a href=\"https:\/\/stackoverflow.com\/questions\/11095474\/why-do-i-have-to-use-close-to-close-a-file\">you should always do that<\/a>. We can easily add that, right?<\/p>\n<pre class=\"lang:python decode:true \">f = open('file', 'w')\ndo_some_changes_to(f)\nf.write()\nf.close()<\/pre>\n<p>Now what happens if <span class=\"lang:python decode:true  crayon-inline\">do_some_changes_to(f)<\/span> causes an exception? <span class=\"lang:python decode:true  crayon-inline\">f.close()<\/span> is never called.<br \/>\nYou may remember something called <span class=\"lang:python decode:true  crayon-inline\">finally<\/span>. That can be appended to a <span class=\"lang:python decode:true  crayon-inline \">try<\/span>-block and will be executed in the end no-matter-what.<\/p>\n<pre class=\"lang:python decode:true \">try:\n    f = open('file', 'w')\n    do_some_changes_to(f)\n    f.write()\nfinally:\n    f.close()<\/pre>\n<p>That&#8217;s a lot of code for something that was originally very slick. That&#8217;s where the <span class=\"lang:python decode:true  crayon-inline \">with<\/span>-statement comes into play:<\/p>\n<pre class=\"lang:python decode:true\">with open('file', 'w') as f:\n    do_some_changes_to(f)\n    f.write()<\/pre>\n<p>It does the very same thing. Plus it is easier to read and faster to write than the whole <span class=\"lang:python decode:true  crayon-inline \">try<\/span>&#8211;<span class=\"lang:python decode:true  crayon-inline \">finally<\/span>-block.<br \/>\nNow QGIS has the same for editing layers since today (read: shipped with version 2.12).<\/p>\n<h2>with edit(layer)<a name=\"with-edit\"><\/a><\/h2>\n<p>Instead of writing<\/p>\n<pre class=\"lang:python decode:true\">try:\n    layer.startEditing()\n    layer.updateFeature(f)\n    layer.commitChanges()\nexcept SomeError:\n    layer.rollBack()<\/pre>\n<p>You can do:<\/p>\n<pre class=\"lang:python decode:true\">with edit(layer):\n    layer.addFeature(...)\n    layer.updateFeatures(...)<\/pre>\n<p>If all goes well, the changes will be saved persistently to the datasource without any call to <span class=\"lang:python decode:true  crayon-inline\">commitChanges()<\/span>\u00a0.<br \/>\nIf any exception occurs, the changes will be rolled back. So like for the <span class=\"lang:python decode:true  crayon-inline \">with<\/span>\u00a0-statement for files: it is easier to read, easier to write and it is comparable to a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Database_transaction\">database transaction<\/a>: Commit everything in the end or nothing at all if an error happens.\u00a0How cool is that!<br \/>\nPlus you will get a python exception if something went wrong in committing (normally you will have to check the return value of <span class=\"lang:python decode:true  crayon-inline\">layer.commitChanges()<\/span>\u00a0)and who does that anyway?<\/p>\n<pre class=\"lang:python decode:true\">try:\n    with edit(layer):\n        layer.addFeature(...)\n        layer.updateFeatures(...)\nexcept QgsEditException as err:\n    print repr(err)<\/pre>\n<p>If you are writing your own .py files you will have to<\/p>\n<pre class=\"lang:python decode:true\">from qgis.core import edit, QgsEditException<\/pre>\n<p>And a final note since I am already on the topic of modifying data in persistent backends:<br \/>\n<strong>Avoid using the dataProvider() methods!<\/strong><a name=\"avoid-using-dataprovider-methods\"><\/a><\/p>\n<pre class=\"lang:python decode:true\">layer.dataProvider().addFeatures()\nlayer.dataProvider().deleteFeatures()\nlayer.dataProvider().changeAttributeValues()\nlayer.dataProvider().changeGeometryValues()<\/pre>\n<ul>\n<li>You cannot undo them easily<\/li>\n<li>They generate one request per call what\u00a0may reduce performance<\/li>\n<li>They do not emit internal signals for map redraws and other refreshes of the user interface<\/li>\n<li>They do not take uncommitted changes into account so the python changes will get overwritten by the user when he commits the layer changes<\/li>\n<\/ul>\n<p>There is a theoretical advantage of slightly more control over how the communication with the backend happens (e.g. how many features are sent per request). But this is hardly ever required in real life unless you are working with really, really, really huge datasets.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PyQGIS now supports a nice new addition for handling edit sessions in layers. This way, changes get committed automatically at the end of a successful (python) edit session.<\/p>\n<pre>\nwith edit(layer):\n    do your changes here()\n<\/pre>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_themeisle_gutenberg_block_has_review":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[12,14,15],"tags":[125],"class_list":["post-1776","post","type-post","status-publish","format-standard","hentry","category-programming","category-python","category-qgis","tag-qgis-org"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":3314,"url":"https:\/\/www.opengis.ch\/fr\/2017\/10\/03\/cours-pyqgis-13-11-14-11-2017-a-neuchatel\/","url_meta":{"origin":1776,"position":0},"title":"Cours PyQGIS 13.11.\/14.11.2017 \u00e0 Neuch\u00e2tel","author":"Matthias Kuhn","date":"3 Ottobre 2017","format":false,"excerpt":"Le cours est complet. Le cours est destin\u00e9 aux utilisateurs avanc\u00e9s de QGIS qui souhaitent accro\u00eetre leurs possibilit\u00e9s gr\u00e2ce \u00e0 l\u2019utilisation de python dans QGIS. Lors de cette formation, nous aborderons diff\u00e9rentes possibilit\u00e9s d\u2019interaction avec l\u2019API QGIS ainsi que la cr\u00e9ation d\u2019interfaces graphiques simples avec PyQt. Les th\u00e8mes suivants seront\u2026","rel":"","context":"In &quot;QGIS&quot;","block_context":{"text":"QGIS","link":"https:\/\/www.opengis.ch\/fr\/category\/gis-fr\/qgis-fr\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1577,"url":"https:\/\/www.opengis.ch\/it\/2015\/04\/29\/performance-for-mass-updating-features-on-layers\/","url_meta":{"origin":1776,"position":1},"title":"Performance for mass updating features","author":"Matthias Kuhn","date":"29 Aprile 2015","format":false,"excerpt":"This post discusses how to improve the performance of pyqgis code which updates a lot of features by a factor of more than 10.","rel":"","context":"In &quot;Python&quot;","block_context":{"text":"Python","link":"https:\/\/www.opengis.ch\/it\/category\/programming\/python\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":11877,"url":"https:\/\/www.opengis.ch\/de\/2020\/11\/02\/pyqgis-kurs-am-27-11-4-12-2020-in-bern\/","url_meta":{"origin":1776,"position":2},"title":"PyQGIS Kurs am 27.11. \/ 4.12. 2020 in Bern","author":"Matthias Kuhn","date":"2 Novembre 2020","format":false,"excerpt":"Der Kurs richtet sich an fortgeschrittene QGIS Anwender, die ihre F\u00e4higkeiten durch die Benutzung von Python verbessern wollen . In diesem Kurs werden verschiedene M\u00f6glichkeiten er\u00f6rtert, mit Hilfe der Python API mit QGIS zu interagieren sowie einfache graphische Oberfl\u00e4chen mit PyQt zu implementieren.Die folgenden Themen werden behandelt: Benutzung der Python\u2026","rel":"","context":"In &quot;Unkategorisiert&quot;","block_context":{"text":"Unkategorisiert","link":"https:\/\/www.opengis.ch\/de\/category\/unkategorisiert\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2020\/11\/AdobeStock_251268362.resized.jpeg?fit=1120%2C747&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2020\/11\/AdobeStock_251268362.resized.jpeg?fit=1120%2C747&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2020\/11\/AdobeStock_251268362.resized.jpeg?fit=1120%2C747&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2020\/11\/AdobeStock_251268362.resized.jpeg?fit=1120%2C747&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2020\/11\/AdobeStock_251268362.resized.jpeg?fit=1120%2C747&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":7545,"url":"https:\/\/www.opengis.ch\/fr\/2019\/09\/16\/cours-pyqgis-23-1-30-1-2020-a-lausanne\/","url_meta":{"origin":1776,"position":3},"title":"Cours PyQGIS 23.1.\/30.1.2020 \u00e0 Lausanne","author":"Matthias Kuhn","date":"16 Settembre 2019","format":false,"excerpt":"Le cours est destin\u00e9 aux utilisateurs avanc\u00e9s de QGIS qui souhaitent accro\u00eetre leurs possibilit\u00e9s gr\u00e2ce \u00e0 l\u2019utilisation de python dans QGIS. Lors de cette formation, nous aborderons diff\u00e9rentes possibilit\u00e9s d\u2019interaction avec l\u2019API QGIS ainsi que la cr\u00e9ation d\u2019interfaces graphiques simples avec PyQt.Les th\u00e8mes suivants seront trait\u00e9s: Utilisation de la console\u2026","rel":"","context":"In &quot;Non classifi\u00e9(e)&quot;","block_context":{"text":"Non classifi\u00e9(e)","link":"https:\/\/www.opengis.ch\/fr\/category\/non-classifiee\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3691,"url":"https:\/\/www.opengis.ch\/it\/2018\/04\/13\/porting-qgis-plugins-to-api-v3-strategy-and-tools\/","url_meta":{"origin":1776,"position":4},"title":"Porting QGIS plugins to API v3 &#8211; Strategy and tools","author":"Marco Bernasocchi","date":"13 Aprile 2018","format":false,"excerpt":"The Release of QGIS 3.0 was a great success and with the first LTR (3.4) scheduled for release this fall, it is now the perfect time to port your plugins to the new API. QGIS 3.0 is the first major release since September 2013 when QGIS 2.0 was released. During\u2026","rel":"","context":"In &quot;Featured&quot;","block_context":{"text":"Featured","link":"https:\/\/www.opengis.ch\/it\/category\/featured\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":154,"url":"https:\/\/www.opengis.ch\/it\/2010\/12\/06\/qgis-plugins-starter-plugin\/","url_meta":{"origin":1776,"position":5},"title":"Qgis plugins starter plugin","author":"Marco Bernasocchi","date":"6 Dicembre 2010","format":false,"excerpt":"Today I published my first QGis Python plugin. It does allow to configure a list of available plugins actions to execute in one click. It is published in pyqgis contributed repository and the source is developed on My GitHub Cheers Marco","rel":"","context":"In &quot;GIS&quot;","block_context":{"text":"GIS","link":"https:\/\/www.opengis.ch\/it\/category\/gis\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_shortlink":"https:\/\/wp.me\/pbdBtI-sE","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/1776","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/comments?post=1776"}],"version-history":[{"count":1,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/1776\/revisions"}],"predecessor-version":[{"id":11153,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/1776\/revisions\/11153"}],"wp:attachment":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/media?parent=1776"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/categories?post=1776"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/tags?post=1776"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}