The following code behaves as I expect when I run it in QGIS Python Console, but when I run it as a standalone from the console, the layer is invalid.
urlWithParams = 'type=xyz&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0'
raster_layer = QgsRasterLayer(urlWithParams, 'OpenStreetMap', 'wms')
l = raster_layer
#==stand alone==#==QGIS Console===
print(l.isValid()) # False # True
print(l.dataProvider()) # None # QgsRasterDataProvider<>
print(l.providerType()) # "wms" # "wms"
print(l.rasterType()) # 0 # 3
What do I need to set up for stand alone script to be successful with adding Open Street Maps to my project.
Complete code below
from qgis.PyQt.QtCore import Qt, QSize
from qgis.core import QgsApplication, QgsProject, \
QgsRasterLayer, QgsCoordinateReferenceSystem, \
QgsRectangle, QgsMapRendererParallelJob
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
crs = QgsCoordinateReferenceSystem("EPSG:3857")
#### APPLICATION ####
QgsApplication.setPrefixPath("/usr/bin/qgis", True)
qgs = QgsApplication([], False)
qgs.initQgis()
#### PROJECT ####
proj = QgsProject.instance()
proj.setCrs(crs)
root = proj.layerTreeRoot()
#### CANVAS ####
canvas = QgsMapCanvas()
bridge = QgsLayerTreeMapCanvasBridge(proj.layerTreeRoot(), canvas)
canvas.setCanvasColor(Qt.red)
canvas.setDestinationCrs(crs)
extent = QgsRectangle(1042595, 7522132,1131975, 7536048)
canvas.setExtent(extent)
canvas.refresh()
canvas.update()
mapSettings = canvas.mapSettings()
mapSettings.setOutputSize( QSize(800,800) )
#### LAYERS ####
urlWithParams = 'type=xyz&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0'
raster_layer = QgsRasterLayer(urlWithParams, 'OpenStreetMap', 'wms')
proj.addMapLayer(raster_layer)
assert raster_layer.isValid()
canvas.setLayers([raster_layer])
#### RENDERING ####
job = QgsMapRendererParallelJob(mapSettings)
job.start()
job.waitForFinished()
image = job.renderedImage()
image.save('foo.png')
proj.write('foo.qgz')
Environment
The Python path looks slightly different for the two cases, but I believe they are essentially running the same environment. The following code produced the exact same output.
import sys, qgis, qgis.core
print(sys.version) # 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
print(qgis.__file__) # /usr/lib/python3/dist-packages/qgis/__init__.py
print(qgis.core.Qgis.QGIS_VERSION) # 3.24.3-Tisler
Best Answer
After learning how (source), I set my code to print the error message associated with the layer being invalid:
And the resulting error summary was:
So I googled for this problem and found this Q&A (Can't get dataProvider object outside of QGIS python Interpreter).
In the end I simply had to use a different prefix path. And after that the same data providers were available in the stand alone as within QGIS, and now it the layer was valid.
More details
I set my code to also print the available data providers:
The results, when prefix path was "/usr/bin/python" were:
['DB2', 'OAPIF', 'WFS', 'arcgisfeatureserver', 'arcgismapserver', 'delimitedtext', 'ept', 'gdal', 'geonode', 'gpx', 'grass', 'grassraster', 'hana', 'mdal', 'memory', 'mesh_memory', 'mssql', 'ogr', 'pdal', 'postgres', 'postgresraster', 'spatialite', 'vectortile', 'virtual', 'virtualraster', 'wcs', 'wms']
['ept', 'gdal', 'memory', 'mesh_memory', 'ogr', 'vectortile']