[FOSSGIS-Talk] kleine Auffälligkeiten beim featureCount()

Thomas Wölk thomas.woelk at gmail.com
Mo Mai 11 08:55:43 CEST 2026


 Drei Phänomene, drei verschiedene Ursachen.

Warum featureCount() der proc_child_lyr -2 liefert:

Das ist kein mysteriöser Wert, sondern ein Sentinel aus dem
Qgis.FeatureCountState-Enum:

# Aus qgis.h (QGIS 3.20+)
enum class FeatureCountState : int {
    Uncounted = -2,       # Feature count noch nicht berechnet
    UnknownCount = -1,    # Provider kennt den Count nicht
};

Dein Layer ist also nicht etwa „negativ befüllt“, sondern ungültig – und
der OGR-Provider hat seinen Counter noch im Initialzustand. Die Ursache
steckt in dieser Zeile:

proc_child_lyr = QgsVectorLayer('proc_child', '', 'ogr')

Du übergibst den String-Literal 'proc_child' als URI, nicht die Variable
proc_child mit dem Pfad zum Temp-Output. Ein proc_child_lyr.isValid() würde
hier False liefern. Richtig wäre:

proc_child_lyr = QgsVectorLayer(proc_child, '', 'ogr')   # ohne Quotes

Warum Punkt 2 und 3 dann immer noch unterschiedlich sind:

Selbst nach dem Quote-Fix bleiben die beiden Aufrufe konzeptionell
verschieden, und das ist gewollt:

processing.run(..., is_child_algorithm=True)

gibt im OUTPUT-Dict nur einen URI/Pfad-String zurück. Du bist selbst dafür
verantwortlich, daraus einen Layer zu bauen. Dieser Modus ist für die
Verkettung innerhalb von Modellen gedacht, wo nicht jeder Zwischenschritt
als vollwertiges Layer-Objekt instanziiert werden soll.

processing.run(..., is_child_algorithm=False)
(Default) liefert dir direkt ein lebendes QgsMapLayer-Objekt zurück, das
intern bereits über einen QgsProcessingContext aus dem URI gehoben wurde.
Daher funktioniert proc_lyr.featureCount() sofort.

Wenn du Variante 2 sauber haben willst, geh über die offizielle
Helper-Funktion, statt selbst zu basteln:

from qgis.core import QgsProcessingContext, QgsProcessingUtils

context = QgsProcessingContext()
proc_child = processing.run(
    'native:extractbyattribute', alg_params,
    context=context, is_child_algorithm=True
)['OUTPUT']
proc_child_lyr = QgsProcessingUtils.mapLayerFromString(proc_child, context)

Damit klappt Memory-Output genauso wie File-Output, ohne dass du den
Provider raten musst.

Aktuellen Zustand der GeoPackage-Tabelle abrufen:

Du hast den Grund schon richtig diagnostiziert: Der OGR-Provider cached den
Feature-Count beim Öffnen, und Trigger-Inserts auf SQLite-Ebene gehen daran
vorbei.

Drei Wege, sauber sortiert nach Aufwand:

Variante A – Layer im Speicher refreshen:

log_tbl.dataProvider().reloadData()   # ab QGIS 3.20
log_tbl.updateExtents()                # optional, für räumliche Indizes
print(log_tbl.featureCount())

reloadData() zwingt den Provider, seinen internen Cache zu verwerfen. In
den meisten Fällen reicht das. Vorsicht: Wenn dein Modell den auslösenden
Layer per QGIS-Edit-Session ändert, feuern die Trigger erst bei
commitChanges(). Vorher ist in der DB nichts zu sehen.

Variante B – über die Provider-Connection direkt SQL absetzen:

from qgis.core import QgsProviderRegistry

md = QgsProviderRegistry.instance().providerMetadata('ogr')
conn = md.createConnection('/pfad/zum/file.gpkg', {})
result = conn.executeSql(
    "SELECT COUNT(*) FROM t_sys_log_leitbild WHERE user = 'Horst'"
)
count = result[0][0]

Das ist der providerunabhängige PyQGIS-Weg und umgeht jeden Caching-Layer.
Funktioniert für GPKG, PostGIS, SpatiaLite gleichermassen.

Variante C – sqlite3 direkt:

import sqlite3
with sqlite3.connect('/pfad/zum/file.gpkg') as con:
    count = con.execute(
        "SELECT COUNT(*) FROM t_sys_log_leitbild WHERE user = ?",
        ('Horst',)
    ).fetchone()[0]

Kürzer und für GeoPackage absolut legitim, aber bindet dich an den
konkreten Treiber. Für reine Lese-Counts unproblematisch, fürs Schreiben
würde ich es vermeiden, weil du das GeoPackage-Metadaten-Management umgehst.

Tradeoff: Variante A ist am idiomatischsten, wenn der Log-Layer ohnehin
geladen ist. Variante B ist die robusteste, wenn das Skript auch außerhalb
eines geladenen Projekts läuft (Standalone-Tool, Headless-Processing).
Variante C nur, wenn du sicher bist, dass es immer ein GeoPackage bleibt.

— Thomas

Am 11.05.2026, 08:11:40 schrieb bmarcus via FOSSGIS-Talk-Liste <
fossgis-talk-liste at fossgis.de>:

> Hallo Listenmitglieder,
>
>
>
> ich bin zwar kein blutiger Python Anfänger, aber mit der PyGIS-API tu ich
> mich immer wieder gerne schwer.
>
> Um den Standart-Wert von Eingabeparameter eines QGIS-Modells etwas
> dynamischer zu gestalten, habe ich das Modell als Python-Skript exportiert
> und entsprechend angepasst. Um die Lauffähigkeit des Skripts zu
> gewährleisten, stehen natürlich noch weitere Änderungen an, bei denen ich
> auf ein interessantes, mir unerklärliches Phänomen bei der Bestimmung der
> Objektanzahl gestoßen bin. Nachfolgendes Skriptschnippsel
>
>
>
> log_tbl = QgsProject.instance().mapLayer(
>
>    't_sys_log_leitbild_24ced76d_bd40_43af_a214_35d4ad8b545f'
>
>    )
>
> print(f'1. Anzahl Features log: {log_tbl.featureCount()}')
>
>
>
> alg_params = {
>
>    'FIELD': 'user',
>
>    'INPUT': 't_sys_log_leitbild_24ced76d_bd40_43af_a214_35d4ad8b545f',
>
>    'OPERATOR': 0,
>
>    'VALUE': 'Horst'
>
>    'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
>
> }
>
> proc_child = processing.run(
>
>    'native:extractbyattribute', alg_params, is_child_algorithm=True
>
>    )['OUTPUT']
>
> proc_child_lyr = QgsVectorLayer('proc_child', '', 'ogr')
>
> print(f'2. Anzahl Features proc_child_lyr:
> {proc_child_lyr.featureCount()}')
>
>
>
> proc_lyr = processing.run(
>
>    'native:extractbyattribute', alg_params
>
>    )['OUTPUT']
>
> print(f'3. Anzahl Features proc_lyr: {proc_lyr.featureCount()}')
>
>
>
> führt zu folgender Ausgabe:
>
>
>
> 1. Anzahl Features log: 0
>
> 2. Anzahl Features proc_child_lyr: -2
>
> 3. Anzahl Features proc_lyr: 4
>
>
>
> Die Tabelle "t_sys_log_leitbild" nimmt über Trigger gesteuert, Änderungen
> eines Layers innerhalb eines GeoPackages entgegen. Horst hat 4 Änderungen
> an
> dem Layer durchgeführt. Die Ausgabe von 3. ist somit korrekt.
>
> Da QGIS von den Änderungen innerhalb der Datenbank nichts mitbekommen hat,
> wird für 1. eine Objektanzahl von 0 ausgegeben. Ist somit nachvollziehbar.
>
> Warum sich allerdings die Ergebnisse von 2. und 3. unterscheiden und wieso
> die Anzahl von Tabelleneinträgen negativ sein kann, bleibt mir
> schleierhaft.
> Kann hier jemand Licht ins Dunkel meiner Gehirnwindungen bringen?
>
> Zudem würde mich ebenfalls interessieren, ob es eine Methode gibt, die das
> Abrufen des aktuellen Zustands einer Datenbanktabelle ermöglicht oder ob
> eine Verbindung zur Datenbank mit SQL-Abfrage den einzig sicheren Weg
> darstellt.
>
>
>
> Mein Dank im Voraus
>
> und schöne Grüße
>
> Bernd
>
>
>
>
>
> --
> ....................................................................
> FOSSGIS-Konferenz 2027 mit OpenStreetMap-Event in Heidelberg!
> 09.-13. März 2027                 https://www.fossgis-konferenz.de/
>
> FOSSGIS Vereinstermine:
> https://fossgis.de/aktivit%C3%A4ten/termine/
>
> FOSSGIS e.V, der Verein zur Förderung von Freier Software aus dem
> GIS-Bereich und Freier Geodaten!
> https://www.fossgis.de/          https://mastodon.online/@FOSSGISeV
> ____________________________________________________________________
> FOSSGIS-Talk-Liste mailing list
> FOSSGIS-Talk-Liste at fossgis.de
> https://lists.fossgis.de/mailman/listinfo/fossgis-talk-liste
>


Mehr Informationen über die Mailingliste FOSSGIS-Talk-Liste