4

I want to execute a Python macro with QGIS 3.22.14 and python39 installed via OSGEO4W and windows 11 home. The purpose is to run a script automatically when I open a project in QGIS.The problem with the Python macro always occurs, even with other scripts except when I don't work with vector. The example is used only to show the problem. The errors may change, but there is always the same situation. The code works in the console or in the standalone version, but the code does not work as Python macros.

This is my script that works properly when I run in the Python Console of QGIS:

uri = "pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:2056' typename='ac_001_1_v1_1_disponibilita_catasto_rdpp' url='https://wfs.geo.ti.ch/?MAP=/project/wfs_ac.qgz' version='auto'"
catasto = QgsVectorLayer(uri, "ac_001_1_v1_1_disponibilita_catasto_rdpp", "WFS")
QgsProject.instance().addMapLayer(catasto)

I run the SAME script in the macro: enter image description here

The result is that: enter image description here

So, I decided to run the version standalone of the working code in the console that has prooven to work with a batch file. I put all the code under def openProject().

The script is the following:

def openProject():
    from qgis.core import *
    # Supply path to qgis install location
    QgsApplication.setPrefixPath("C:/OSGeo4W/apps/qgis-ltr", True)

    # Create a reference to the QgsApplication.  Setting the
    # second argument to False disables the GUI.
    qgs = QgsApplication([], False)

    # Load providers
    qgs.initQgis()

    # Write your code here to load some layers, use processing
    # algorithms, etc.

    from qgis.analysis import QgsNativeAlgorithms
    import processing
    from processing.core.Processing import Processing
    Processing.initialize()*
    QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
    
    uri = "pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:2056' typename='ac_001_1_v1_1_disponibilita_catasto_rdpp' url='https://wfs.geo.ti.ch/?MAP=/project/wfs_ac.qgz' version='auto'"
    catasto = QgsVectorLayer(uri, "ac_001_1_v1_1_disponibilita_catasto_rdpp", "WFS")
    QgsProject.instance().addMapLayer(catasto)
    # Finally, exitQgis() is called to remove the
    # provider and layer registries from memory
    qgs.exitQgis()

def saveProject():
    pass

def closeProject():
    pass

I show the abovementioned script even as image: enter image description here

The result: enter image description here

How to solve this issue?

Maybe the solution should be using the standalone script and understanding which module to add instead of *, that is not accepted in the function.

7
  • 2
    A good lesson, one of many, from PEP 8 - Style Guide for Python Code | peps.python.org, "Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools."
    – bixb0012
    Dec 26, 2022 at 18:56
  • 1
    Good information from Stack Overflow: How to create a Minimal, Reproducible Example - Help Center - Stack Overflow. I understand the problem is with your script, but it is easier for community members to comment on specific issues that have already been isolated. I tried running some of the code and ran into various errors (self-signed certificates, incorrect parameter, etc...) and eventually gave up.
    – bixb0012
    Dec 26, 2022 at 19:10
  • 1
    Please, add these two lines in your code and give us the output (both from the QGIS python console and when run as a script): import sys then print(f"Info: {sys.path}") Dec 26, 2022 at 19:26
  • 1
    Also, re-use your path variables in a more convenient way: you defined several times exactly the same URIs... this is a bad practice. Also: regroup your imports on top of your script file. And use from qgis.core import <whatever modules you need separated by comma> Dec 26, 2022 at 19:26
  • 2
    @simone100, if you have trimmed the code down and still get the error, then update the question with the new code. Pasting new code into a comment is tough to read.
    – bixb0012
    Dec 26, 2022 at 19:42

1 Answer 1

5

This code is working from the Python 3.10.4 console on QGIS 3.26.2-Buenos Aires:

from urllib.parse import urlencode
from qgis.core import QgsVectorLayer, QgsProject

base_url = 'https://wfs.geo.ti.ch/?'
params = {
    "MAP": "/project/wfs_ac.qgz",
    "pagingEnabled": 'true',
    "restrictToRequestBBOX": '1',
    "srsname": 'EPSG:2056',
    "typename": 'ac_001_1_v1_1_disponibilita_catasto_rdpp',
    "version": 'auto',
}

uri = base_url + urlencode(params)
catasto = QgsVectorLayer(
    uri,
    "ac_001_1_v1_1_disponibilita_catasto_rdpp",
    "WFS",
)
QgsProject.instance().addMapLayer(catasto)

So when embeded into a macro, it should look like this:

from urllib.parse import urlencode
from qgis.core import (
    QgsVectorLayer,
    QgsProject,
)
from qgis.analysis import QgsNativeAlgorithms
import processing
from processing.core.Processing import Processing

def openProject():
    base_url = "https://wfs.geo.ti.ch/?"
    params = {
        "MAP": "/project/wfs_ac.qgz",
        "pagingEnabled": "true",
        "restrictToRequestBBOX": "1",
        "srsname": "EPSG:2056",
        "typename": "ac_001_1_v1_1_disponibilita_catasto_rdpp",
        "version": "auto",
    }

    uri = base_url + urlencode(params)
    catasto = QgsVectorLayer(
        uri,
        "ac_001_1_v1_1_disponibilita_catasto_rdpp",
        "WFS",
    )
    QgsProject.instance().addMapLayer(catasto)

def saveProject():
    pass

def closeProject():
    pass

Of course, macros must be enable for this one to work. If need be, go to "Settings > Options > General" to change this option:

enter image description here

Please, notice that this can be a security breach if you open a non-trusted project file, hence this warning when the option is set to "Ask":

enter image description here

Finally, your features will be loaded when opening your QGIS project:

enter image description here

I also took the liberty of rewriting the way the URL was constructed to be more flexible and pythonic. This is based on urllib, which is a Python module from the standard library.

You don't have to instantiate the QgsApplication if you are already using the GUI, doing this may lead to the following fatal error:

QGIS died on signal 11Warning: QCoreApplication::arguments: 
  Please instantiate the QApplication object first
Segmentation fault (core dumped)

If not, you may want to change Processing.initialize()* to Processing.initialize() (typo).

Also remove the line from qgis.core import *.

See also: https://gis.stackexchange.com/a/279937/65370

But you can directly use the processing algorithms depending on what you want to achieve.

Therefore, I let you figure out how to embed your remaining code in these snippets, because from your question, it seems you are not using any of the processing algorithms yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.