diff --git a/.gitignore b/.gitignore index 0d8c5a2101e..f2f86d1e3cb 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,9 @@ venv .venv user.mk .vscode +shell.nix +vscode.sh +clean.sh +.envrc +.vscode-extensions +core diff --git a/Makefile b/Makefile index dc3bfeab2bb..d5d9566f607 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,13 @@ tx_force_pull_translations: $(eval comma += ,) tx pull -f --parallel --mode onlytranslated -l $(subst $(space),$(comma),$(subst en$(space),,$(subst zh_,zh-,$(LANGUAGES)))) ; +doctest-gh: + # --system-site-packages needed to keep QGIS libs in python path + export PYTHONPATH=$(PYTHONPATH):/usr/lib/python3/dist-packages && \ + . /docsenv/bin/activate --system-site-packages && LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so $(SPHINXBUILD) -b doctest . $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + doctest: LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so $(SPHINXBUILD) -b doctest . $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ diff --git a/docs/pyqgis_developer_cookbook/canvas.rst b/docs/pyqgis_developer_cookbook/canvas.rst index 9883fc91b94..94165768898 100644 --- a/docs/pyqgis_developer_cookbook/canvas.rst +++ b/docs/pyqgis_developer_cookbook/canvas.rst @@ -123,7 +123,7 @@ layers for the canvas. .. testcode:: canvas - vlayer = QgsVectorLayer('testdata/airports.shp', "Airports layer", "ogr") + vlayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") if not vlayer.isValid(): print("Layer failed to load!") @@ -136,7 +136,6 @@ layers for the canvas. # set the map canvas layer set canvas.setLayers([vlayer]) - After executing these commands, the canvas should show the layer you have loaded. diff --git a/docs/pyqgis_developer_cookbook/cheat_sheet.rst b/docs/pyqgis_developer_cookbook/cheat_sheet.rst index fa03c69367f..e032cd9dd93 100644 --- a/docs/pyqgis_developer_cookbook/cheat_sheet.rst +++ b/docs/pyqgis_developer_cookbook/cheat_sheet.rst @@ -168,7 +168,7 @@ Layers .. testcode:: cheat_sheet - layer = iface.addVectorLayer("testdata/airports.shp", "layer name you like", "ogr") + layer = iface.addVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") if not layer or not layer.isValid(): print("Layer failed to load!") diff --git a/docs/pyqgis_developer_cookbook/crs.rst b/docs/pyqgis_developer_cookbook/crs.rst index da0f32e62be..f0354821975 100644 --- a/docs/pyqgis_developer_cookbook/crs.rst +++ b/docs/pyqgis_developer_cookbook/crs.rst @@ -126,7 +126,7 @@ Output: Ellipsoid Acronym: EPSG:7030 Proj String: +proj=longlat +datum=WGS84 +no_defs Is geographic: True - Map units: DistanceUnit.Degrees + Map units: 6 .. index:: Projections diff --git a/docs/pyqgis_developer_cookbook/geometry.rst b/docs/pyqgis_developer_cookbook/geometry.rst index 2339ea05f4f..c57b3c0f4e0 100644 --- a/docs/pyqgis_developer_cookbook/geometry.rst +++ b/docs/pyqgis_developer_cookbook/geometry.rst @@ -148,18 +148,18 @@ enumeration. .. testcode:: geometry print(gPnt.wkbType()) - # output: 'WkbType.Point' + # output: 1 print(gLine.wkbType()) - # output: 'WkbType.LineString' + # output: 2 print(gPolygon.wkbType()) - # output: 'WkbType.Polygon' + # output: 3 .. testoutput:: geometry :hide: - WkbType.Point - WkbType.LineString - WkbType.Polygon + 1 + 2 + 3 As an alternative, one can use the :meth:`type() ` method which returns a value from the :meth:`QgsWkbTypes.GeometryType ` @@ -168,12 +168,12 @@ enumeration. .. testcode:: geometry print(gLine.type()) - # output: 'GeometryType.Line' + # output: 1 .. testoutput:: geometry :hide: - GeometryType.Line + 1 You can use the :meth:`displayString() ` function to get a human readable geometry type. @@ -279,7 +279,7 @@ It's also possible to modify each part of the geometry using .. testoutput:: geometry - MultiPoint ((-10334728.12541878595948219 -5360106.25905461423099041),(-10462135.16126426123082638 -5217485.4735023295506835),(-10589399.84444035589694977 -5072021.45942386891692877)) + MultiPoint ((-10334726.79314758814871311 -5360105.10101194866001606),(-10462133.82917747274041176 -5217484.34365733992308378),(-10589398.51346861757338047 -5072020.35880533326417208)) .. index:: Geometry; Predicates and operations diff --git a/docs/pyqgis_developer_cookbook/loadlayer.rst b/docs/pyqgis_developer_cookbook/loadlayer.rst index 536da7b8cda..092b5ca97d3 100644 --- a/docs/pyqgis_developer_cookbook/loadlayer.rst +++ b/docs/pyqgis_developer_cookbook/loadlayer.rst @@ -48,38 +48,21 @@ them here. Vector Layers ============= -To create and add a vector layer instance to the project, specify the layer's data source -identifier, name for the layer and provider's name: - -.. testcode:: loadlayer - - # get the path to the shapefile e.g. /home/project/data/ports.shp - path_to_airports_layer = "testdata/airports.shp" - - # The format is: - # vlayer = QgsVectorLayer(data_source, layer_name, provider_name) - - vlayer = QgsVectorLayer(path_to_airports_layer, "Airports layer", "ogr") - if not vlayer.isValid(): - print("Layer failed to load!") - else: - QgsProject.instance().addMapLayer(vlayer) - -The data source identifier is a string and it is specific to each vector data -provider. Layer's name is used in the layer list widget. It is important to -check whether the layer has been loaded successfully. If it was not, an invalid -layer instance is returned. +To create and add a vector layer instance to the project, specify the layer's data source identifier. +The data source identifier is a string and it is specific to each vector data provider. +An optional layer name is used for identifying the layer in the :guilabel:`Layers` panel. +It is important to check whether the layer has been loaded successfully. +If it was not, an invalid layer instance is returned. For a geopackage vector layer: .. testcode:: loadlayer - # get the path to a geopackage e.g. /usr/share/qgis/resources/data/world_map.gpkg - path_to_gpkg = os.path.join(QgsApplication.pkgDataPath(), "resources", "data", "world_map.gpkg") + # get the path to a geopackage + path_to_gpkg = "testdata/data/data.gpkg" # append the layername part - gpkg_countries_layer = path_to_gpkg + "|layername=countries" - # e.g. gpkg_places_layer = "/usr/share/qgis/resources/data/world_map.gpkg|layername=countries" - vlayer = QgsVectorLayer(gpkg_countries_layer, "Countries layer", "ogr") + gpkg_airports_layer = path_to_gpkg + "|layername=airports" + vlayer = QgsVectorLayer(gpkg_airports_layer, "Airports layer", "ogr") if not vlayer.isValid(): print("Layer failed to load!") else: @@ -87,11 +70,11 @@ For a geopackage vector layer: The quickest way to open and display a vector layer in QGIS is the :meth:`addVectorLayer() ` -method of the :class:`QgisInterface `: +method of the :class:`QgisInterface ` class: .. testcode:: loadlayer - vlayer = iface.addVectorLayer(path_to_airports_layer, "Airports layer", "ogr") + vlayer = iface.addVectorLayer(gpkg_airports_layer, "Airports layer", "ogr") if not vlayer: print("Layer failed to load!") @@ -105,23 +88,36 @@ providers: .. index:: pair: Loading; GDAL layers -* GDAL library (Shapefile and many other file formats) --- data source is the - path to the file: +* The ogr provider from the GDAL library supports a `wide variety of formats + `_, + also called drivers in GDAL speak. + Examples are ESRI Shapefile, Geopackage, Flatgeobuf, Geojson, ... + For single-file formats the filepath usually suffices as uri. + For geopackages or dxf, a pipe separated suffix allows to specify the layer to load. + + * for ESRI Shapefile: + + .. code:: + + uri = "testdata/airports.shp" + vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr") + QgsProject.instance().addMapLayer(vlayer) - * for Shapefile: + * for Geopackage (note the internal options in data source uri): .. testcode:: loadlayer - vlayer = QgsVectorLayer("testdata/airports.shp", "layer_name_you_like", "ogr") - QgsProject.instance().addMapLayer(vlayer) + uri = "testdata/data/data.gpkg|layername=airports" + vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr") + QgsProject.instance().addMapLayer(vlayer) * for dxf (note the internal options in data source uri): .. testcode:: loadlayer - uri = "testdata/sample.dxf|layername=entities|geometrytype=Polygon" - vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr") - QgsProject.instance().addMapLayer(vlayer) + uri = "testdata/sample.dxf|layername=entities|geometrytype=Polygon" + vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr") + QgsProject.instance().addMapLayer(vlayer) .. index:: pair: Loading; PostGIS layers @@ -225,7 +221,6 @@ providers: uri = "https://demo.mapserver.org/cgi-bin/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=ms:cities" vlayer = QgsVectorLayer(uri, "my wfs layer", "WFS") - The uri can be created using the standard ``urllib`` library: .. testcode:: loadlayer diff --git a/docs/pyqgis_developer_cookbook/raster.rst b/docs/pyqgis_developer_cookbook/raster.rst index 0309d9fae76..bcf91d1e915 100644 --- a/docs/pyqgis_developer_cookbook/raster.rst +++ b/docs/pyqgis_developer_cookbook/raster.rst @@ -114,7 +114,7 @@ The following code assumes ``rlayer`` is a .. testoutput:: raster - RasterLayerType.GrayOrUndefined + 0 .. testcode:: raster diff --git a/docs/pyqgis_developer_cookbook/vector.rst b/docs/pyqgis_developer_cookbook/vector.rst index 6b53fdc20f0..2f57b5164f6 100644 --- a/docs/pyqgis_developer_cookbook/vector.rst +++ b/docs/pyqgis_developer_cookbook/vector.rst @@ -73,18 +73,25 @@ by calling :meth:`fields() ` on a .. testcode:: vectors - vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr") + vlayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") for field in vlayer.fields(): print(field.name(), field.typeName()) .. testoutput:: vectors - ID Integer64 - fk_region Integer64 - ELEV Real - NAME String - USE String + fid Integer64 + id Integer64 + scalerank Integer64 + featurecla String + type String + name String + abbrev String + location String + gps_code String + iata_code String + wikipedia String + natlscale Real The :meth:`displayField() ` and :meth:`mapTipTemplate() ` methods provide @@ -96,13 +103,13 @@ methods you can easily get both: .. testcode:: vectors - vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr") + vlayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") print(vlayer.displayField()) .. testoutput:: vectors - NAME + name .. note:: If you change the ``Display Name`` from a field to an expression, you have to use :meth:`displayExpression() ` @@ -593,7 +600,9 @@ For deletion of fields just provide a list of field indexes. # Alternate methods for removing fields # first create temporary fields to be removed (f1-3) - layer.dataProvider().addAttributes([QgsField("f1",QVariant.Int),QgsField("f2",QVariant.Int),QgsField("f3",QVariant.Int)]) + layer.dataProvider().addAttributes([QgsField("f1", QVariant.Int), + QgsField("f2", QVariant.Int), + QgsField("f3", QVariant.Int)]) layer.updateFields() count=layer.fields().count() # count of layer fields ind_list=list((count-3, count-2)) # create list @@ -701,7 +710,7 @@ field: .. testcode:: vectors - vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr") + vlayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") feat = QgsVectorLayerUtils.createFeature(vlayer) @@ -710,7 +719,7 @@ you to quickly get the values of a field or expression: .. testcode:: vectors - vlayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr") + vlayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") # select only the first feature to make the output shorter vlayer.selectByIds([1]) val = QgsVectorLayerUtils.getValues(vlayer, "NAME", selectedOnly=True) @@ -718,7 +727,7 @@ you to quickly get the values of a field or expression: .. testoutput:: vectors - (['AMBLER'], True) + (['Sahnewal'], True) .. index:: Vector layers; Creating @@ -981,7 +990,7 @@ The following example code illustrates creating and populating a memory provider # add a feature fet = QgsFeature() fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10))) - fet.setAttributes(["Johny", 2, 0.3]) + fet.setAttributes(["Johnny", 2, 0.3]) pr.addFeatures([fet]) # update layer's extent when new features have been added @@ -1008,7 +1017,7 @@ Finally, let's check whether everything went well fields: 3 features: 1 extent: 10.0 10.0 10.0 10.0 - F: 1 ['Johny', 2, 0.3] + F: 1 ['Johnny', 2, 0.3] .. index:: Vector layers; Symbology @@ -1228,8 +1237,8 @@ arrangement) from qgis.PyQt import QtGui - myVectorLayer = QgsVectorLayer("testdata/airports.shp", "airports", "ogr") - myTargetField = 'ELEV' + myVectorLayer = QgsVectorLayer("testdata/data/data.gpkg|layername=airports", "Airports layer", "ogr") + myTargetField = 'scalerank' myRangeList = [] myOpacity = 1 # Make our first symbol and range... diff --git a/doctest.dockerfile b/doctest.dockerfile index f90117a9ad3..b32c890b88a 100644 --- a/doctest.dockerfile +++ b/doctest.dockerfile @@ -1,9 +1,12 @@ -FROM qgis/qgis:release-3_34 +FROM qgis/qgis:3.34 # Install requirement first to use caching COPY REQUIREMENTS.txt /documentation/REQUIREMENTS.txt -RUN pip3 install -r /documentation/REQUIREMENTS.txt + +# make the venv in /docsenv +WORKDIR / +RUN python3 -m venv docsenv && . docsenv/bin/activate && pip3 install -r /documentation/REQUIREMENTS.txt WORKDIR /documentation -CMD make doctest +CMD make doctest-gh