
Qgis Syntax Pyqgis Api
- 8 installs
- 29 repo stars
- Updated July 8, 2026
- openaec-foundation/qgis-claude-skill-package
Helps with backend & apis tasks.
About
qgis-syntax-pyqgis-api is a Claude Code skill for backend & apis. It helps solo builders move faster with AI-assisted development.
- qgis-syntax-pyqgis-api
- Backend & APIs
- AI-coding skill
Qgis Syntax Pyqgis Api by the numbers
- 8 all-time installs (skills.sh)
- Ranked #3,619 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/qgis-claude-skill-package --skill qgis-syntax-pyqgis-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 29 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/qgis-claude-skill-package ↗ |
What it does
Helps with backend & apis tasks.
Files
qgis-syntax-pyqgis-api
Quick Reference
Scripting Contexts
| Context | iface Available | Initialization Required | Use Case |
|---|---|---|---|
| Python Console | Yes | None | Interactive exploration, quick tests |
| Standalone Script | No | QgsApplication([], False) + initQgis() | CLI tools, CI pipelines, batch processing |
| Processing Script | No (feedback instead) | None (framework handles it) | Geoprocessing algorithms |
| Plugin | Yes (via classFactory) | None | GUI extensions, toolbar tools |
Core Classes
| Class | Purpose | Key Methods |
|---|---|---|
QgsFeature | Single feature (geometry + attributes) | id(), geometry(), attributes(), __getitem__() |
QgsFeatureRequest | Filter/optimize feature queries | setFilterExpression(), setFilterRect(), setLimit(), setFlags() |
QgsGeometry | Geometry wrapper with GEOS operations | fromPointXY(), buffer(), intersection(), contains() |
QgsSpatialIndex | R-tree spatial index | addFeature(), nearestNeighbor(), intersects() |
QgsTask | Background processing | run(), finished(), setProgress(), isCanceled() |
QgsMessageLog | Log panel messages | logMessage(msg, tag, level) |
QgsMessageBar | Map canvas notifications | pushMessage(title, text, level, duration) |
QgsPoint vs QgsPointXY
| Class | Dimensions | Use With |
|---|---|---|
QgsPointXY | 2D (X, Y) only | fromPointXY(), fromPolylineXY(), fromPolygonXY() |
QgsPoint | 2D + Z + M | fromPolyline(), 3D operations |
ALWAYS use QgsPointXY for 2D operations. Use QgsPoint ONLY when Z or M values are required.
---
Critical Warnings
NEVER modify features outside an edit session. Changes are silently lost or corrupt the data source. ALWAYS use with edit(layer): or manually call startEditing() / commitChanges().
NEVER access iface, QgsProject.instance(), or any Qt widget from QgsTask.run(). These are main-thread objects. Accessing them from a background thread crashes QGIS.
NEVER raise exceptions in QgsTask.run(). ALWAYS catch exceptions internally and return False on failure.
NEVER use layer.featureCount() to check if features exist. Some providers return -1. ALWAYS use getFeatures() with setLimit(1) instead.
NEVER use print() in multithreaded code (expression functions, renderers, processing algorithms). ALWAYS use QgsMessageLog instead.
ALWAYS check for NULL geometries before operations: if not geom.isNull():.
ALWAYS use QgsDistanceArea for measurements on geographic (lat/lon) CRS. The simple area() and length() methods return values in layer units without CRS correction.
ALWAYS call layer.updateFields() after adding or removing fields via the data provider.
ALWAYS keep QgsProcessingContext and QgsProcessingFeedback alive for the duration of QgsProcessingAlgRunnerTask. Garbage collection crashes QGIS.
---
Decision Tree: Scripting Context
Need to write PyQGIS code?
|
+-- Running inside QGIS GUI?
| |
| +-- Quick test or exploration? --> Python Console (iface available)
| +-- Reusable geoprocessing? --> Processing Script (QgsProcessingAlgorithm)
| +-- GUI extension with toolbar? --> Plugin (classFactory + initGui/unload)
|
+-- Running outside QGIS?
--> Standalone Script (QgsApplication init required)Decision Tree: Feature Editing
Need to modify layer data?
|
+-- Bulk import / batch processing, no undo needed?
| --> Data Provider direct: layer.dataProvider().addFeatures([...])
|
+-- Interactive editing, undo/redo needed?
| --> Edit Buffer: with edit(layer): layer.addFeature(feat)
|
+-- Multiple edits as single undo operation?
--> Edit Commands: layer.beginEditCommand("description")Decision Tree: Spatial Queries
Need to find features by location?
|
+-- Single query against a layer?
| --> QgsFeatureRequest().setFilterRect(extent)
|
+-- Repeated queries against same dataset?
| |
| +-- Point data only?
| | --> QgsSpatialIndexKDBush (fastest, static)
| |
| +-- Mixed geometry types?
| --> QgsSpatialIndex (R-tree, dynamic)---
Essential Patterns
Standalone Script Initialization
from qgis.core import QgsApplication, QgsVectorLayer
qgs = QgsApplication([], False)
qgs.initQgis()
# ... PyQGIS work here ...
qgs.exitQgis() # ALWAYS clean upDual-Context Script (Console + Standalone)
try:
from qgis.utils import iface
layer = iface.activeLayer()
except ImportError:
from qgis.core import QgsApplication
qgs = QgsApplication([], False)
qgs.initQgis()Feature Iteration with Optimization
from qgis.core import QgsFeatureRequest
# Attributes only (skip geometry loading)
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
request.setSubsetOfAttributes(['name', 'population'], layer.fields())
for feature in layer.getFeatures(request):
print(feature['name'], feature['population'])Feature Editing with Context Manager
from qgis.core import QgsFeature, QgsGeometry, QgsPointXY, edit
with edit(layer):
feat = QgsFeature(layer.fields())
feat.setAttributes([1, 'New Point'])
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10.0, 52.0)))
layer.addFeature(feat)
# commitChanges() called automatically; rollBack() on exceptionGeometry Construction and Operations
from qgis.core import QgsGeometry, QgsPointXY
# Create geometries
point = QgsGeometry.fromPointXY(QgsPointXY(1.0, 2.0))
polygon = QgsGeometry.fromPolygonXY([[
QgsPointXY(0, 0), QgsPointXY(2, 0),
QgsPointXY(2, 2), QgsPointXY(0, 2), QgsPointXY(0, 0)
]])
# Predicates
if polygon.contains(point):
print("Point is inside polygon")
# Operations
buffered = point.buffer(10.0, 5)
intersection = polygon.intersection(buffered)Spatial Index Usage
from qgis.core import QgsSpatialIndex, QgsPointXY, QgsFeatureRequest
# Build index (bulk load is fastest)
index = QgsSpatialIndex(layer.getFeatures())
# Query nearest 5 features
nearest_ids = index.nearestNeighbor(QgsPointXY(25.4, 12.7), 5)
# Fetch actual features by ID
for fid in nearest_ids:
feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)))Background Task (QgsTask Subclass)
from qgis.core import QgsTask, QgsApplication, QgsMessageLog, Qgis
class ProcessingTask(QgsTask):
def __init__(self, description, data):
super().__init__(description, QgsTask.CanCancel)
self.data = data # Copy data BEFORE task starts
self.result = None
self.exception = None
def run(self):
"""Background thread. NEVER access iface or QgsProject here."""
try:
for i, item in enumerate(self.data):
if self.isCanceled():
return False
self.result = process(item)
self.setProgress((i + 1) / len(self.data) * 100)
return True
except Exception as e:
self.exception = e
return False
def finished(self, result):
"""Main thread. Safe for GUI updates."""
if result:
QgsMessageLog.logMessage("Done", 'MyPlugin', Qgis.Success)
elif self.exception:
QgsMessageLog.logMessage(str(self.exception), 'MyPlugin', Qgis.Critical)
task = ProcessingTask("Heavy work", data_copy)
QgsApplication.taskManager().addTask(task)User Communication
from qgis.core import QgsMessageLog, Qgis
# Log panel (always available, including background threads)
QgsMessageLog.logMessage("Info message", 'MyPlugin', Qgis.Info)
QgsMessageLog.logMessage("Warning", 'MyPlugin', Qgis.Warning)
QgsMessageLog.logMessage("Error", 'MyPlugin', Qgis.Critical)
# Message bar (main thread + iface only)
iface.messageBar().pushMessage("Title", "Text", level=Qgis.Success, duration=3)---
Common Operations
Check If Layer Has Features
request = QgsFeatureRequest().setLimit(1)
has_features = bool(list(layer.getFeatures(request)))Get Single Feature by ID
feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(42)))Add Fields to Layer
from qgis.PyQt.QtCore import QMetaType
from qgis.core import QgsField
layer.dataProvider().addAttributes([
QgsField("name", QMetaType.Type.QString),
QgsField("value", QMetaType.Type.Double),
])
layer.updateFields() # ALWAYS call after field changesEllipsoid-Accurate Measurements
from qgis.core import QgsDistanceArea, QgsUnitTypes
d = QgsDistanceArea()
d.setEllipsoid('WGS84')
area_m2 = d.measureArea(geom)
area_km2 = d.convertAreaMeasurement(area_m2, QgsUnitTypes.AreaSquareKilometers)Coordinate Transformation
from qgis.core import QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsProject
transform = QgsCoordinateTransform(
QgsCoordinateReferenceSystem("EPSG:4326"),
QgsCoordinateReferenceSystem("EPSG:3857"),
QgsProject.instance()
)
geom.transform(transform) # In-place transformationBasic Symbology
from qgis.core import QgsMarkerSymbol
symbol = QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red', 'size': '3'})
layer.renderer().setSymbol(symbol)
layer.triggerRepaint()Renderer Types Overview
| Renderer | Class | Use Case |
|---|---|---|
| Single Symbol | QgsSingleSymbolRenderer | All features same style |
| Categorized | QgsCategorizedSymbolRenderer | Discrete attribute values |
| Graduated | QgsGraduatedSymbolRenderer | Numeric ranges |
| Rule-Based | QgsRuleBasedRenderer | Expression-driven rules |
---
Data Provider vs Edit Buffer
| Aspect | Data Provider | Edit Buffer |
|---|---|---|
| Method | layer.dataProvider().addFeatures() | layer.addFeature() |
| Undo support | No | Yes |
| Edit session required | No | Yes |
| Performance | Faster for bulk operations | Slower, safer |
| Use case | Batch processing, scripts | Interactive editing |
---
Reference Links
- references/methods.md -- API signatures for QgsFeature, QgsFeatureRequest, QgsGeometry, QgsSpatialIndex, QgsTask
- references/examples.md -- Working code examples for all major patterns
- references/anti-patterns.md -- Editing, threading, and iteration anti-patterns
Official Sources
- https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/vector.html
- https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/geometry.html
- https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/tasks.html
- https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/communicating.html
qgis-syntax-pyqgis-api — Anti-Patterns
What NOT to do in PyQGIS, organized by category. Every anti-pattern includes the mistake, why it fails, and the correct alternative.
---
Feature Editing Anti-Patterns
AP-001: Modifying Features Outside Edit Session
WRONG:
feature = next(layer.getFeatures())
feature['name'] = 'Updated'
layer.updateFeature(feature) # Silently fails -- no edit session activeWHY: updateFeature() requires an active edit session. Without one, changes are silently discarded. No error is raised.
CORRECT:
from qgis.core import edit
with edit(layer):
feature = next(layer.getFeatures())
feature['name'] = 'Updated'
layer.updateFeature(feature)---
AP-002: Forgetting to Commit or Rollback
WRONG:
layer.startEditing()
layer.addFeature(feat)
# Script ends without commitChanges() or rollBack()
# Edit session stays open, blocking other operationsWHY: Orphaned edit sessions lock the layer and prevent data provider operations. If QGIS crashes, all uncommitted changes are lost.
CORRECT:
from qgis.core import edit
with edit(layer):
layer.addFeature(feat)
# Automatically calls commitChanges() on success, rollBack() on exception---
AP-003: Forgetting updateFields() After Field Changes
WRONG:
from qgis.PyQt.QtCore import QMetaType
from qgis.core import QgsField
layer.dataProvider().addAttributes([QgsField("score", QMetaType.Type.Double)])
# Missing layer.updateFields()
# Layer's field list is now out of sync with the data provider
feature['score'] = 99.5 # KeyError -- layer does not know about 'score'WHY: The layer caches its field list. After modifying fields via the data provider, the cache is stale until updateFields() is called.
CORRECT:
layer.dataProvider().addAttributes([QgsField("score", QMetaType.Type.Double)])
layer.updateFields() # Sync the layer's field cache---
AP-004: Using Data Provider for Interactive Edits
WRONG:
# User expects undo/redo to work
layer.dataProvider().changeAttributeValues({fid: {0: 'new_value'}})
# No undo available -- changes are written directly to the data sourceWHY: Data provider operations bypass the edit buffer. There is no undo/redo support. Use the edit buffer for interactive editing.
CORRECT:
from qgis.core import edit
with edit(layer):
layer.changeAttributeValue(fid, 0, 'new_value')
# Undo/redo now available via Edit menu---
Threading Anti-Patterns
AP-005: Accessing iface from Background Thread
WRONG:
class MyTask(QgsTask):
def run(self):
layer = iface.activeLayer() # CRASH -- iface is main-thread only
for f in layer.getFeatures():
self.process(f)
return TrueWHY: iface is a QgisInterface instance bound to the main Qt event loop. Accessing it from a background thread causes segmentation faults or undefined behavior.
CORRECT:
class MyTask(QgsTask):
def __init__(self, description, features):
super().__init__(description, QgsTask.CanCancel)
self.features = features # Data copied BEFORE task starts
def run(self):
for f in self.features:
self.process(f)
return True
# Copy data on main thread, then start task
features_copy = list(iface.activeLayer().getFeatures())
task = MyTask("Processing", features_copy)
QgsApplication.taskManager().addTask(task)---
AP-006: Accessing QgsProject.instance() from run()
WRONG:
class MyTask(QgsTask):
def run(self):
project = QgsProject.instance() # CRASH -- singleton is main-thread only
layer = project.mapLayersByName('roads')[0]
return TrueWHY: QgsProject.instance() is a singleton managed on the main thread. Accessing it from a background thread causes race conditions and crashes.
CORRECT:
class MyTask(QgsTask):
def __init__(self, description, layer_data):
super().__init__(description, QgsTask.CanCancel)
self.layer_data = layer_data # Pre-extracted data
# Extract data on main thread
layer = QgsProject.instance().mapLayersByName('roads')[0]
data = list(layer.getFeatures())
task = MyTask("Processing", data)---
AP-007: Raising Exceptions in QgsTask.run()
WRONG:
class MyTask(QgsTask):
def run(self):
data = load_data()
if data is None:
raise ValueError("No data found") # CRASHES QGIS
return TrueWHY: Unhandled exceptions in run() crash the QGIS application. The task framework does not catch exceptions from run().
CORRECT:
class MyTask(QgsTask):
def __init__(self, description):
super().__init__(description, QgsTask.CanCancel)
self.exception = None
def run(self):
try:
data = load_data()
if data is None:
self.exception = ValueError("No data found")
return False
return True
except Exception as e:
self.exception = e
return False
def finished(self, result):
if self.exception:
QgsMessageLog.logMessage(str(self.exception), 'MyPlugin', Qgis.Critical)---
AP-008: Passing Live Layer References to Tasks
WRONG:
class MyTask(QgsTask):
def __init__(self, layer):
super().__init__("Task", QgsTask.CanCancel)
self.layer = layer # Live reference to main-thread object
def run(self):
for f in self.layer.getFeatures(): # Accessing main-thread object
pass
return TrueWHY: Layer objects are tied to the main thread. Iterating them from a background thread causes crashes or data corruption.
CORRECT:
# Copy features on main thread
features = list(layer.getFeatures())
task = MyTask("Task", features)---
AP-009: Garbage-Collected Context/Feedback Objects
WRONG:
def run_buffer():
context = QgsProcessingContext()
feedback = QgsProcessingFeedback()
task = QgsProcessingAlgRunnerTask(alg, params, context, feedback)
QgsApplication.taskManager().addTask(task)
# context and feedback go out of scope and are garbage collected
# Task crashes when trying to access themWHY: QgsProcessingAlgRunnerTask holds raw pointers to context and feedback. If Python garbage-collects them, the task accesses freed memory.
CORRECT:
class TaskHolder:
def __init__(self):
self.context = QgsProcessingContext()
self.feedback = QgsProcessingFeedback()
self.task = QgsProcessingAlgRunnerTask(alg, params, self.context, self.feedback)
QgsApplication.taskManager().addTask(self.task)
holder = TaskHolder() # Keep reference alive---
Feature Iteration Anti-Patterns
AP-010: Using featureCount() to Check for Features
WRONG:
if layer.featureCount() > 0: # Some providers return -1
process_features(layer)WHY: Some data providers (e.g., WFS, database-backed layers with filters) return -1 or an inaccurate count from featureCount(). This check silently skips valid data.
CORRECT:
request = QgsFeatureRequest().setLimit(1)
has_features = bool(list(layer.getFeatures(request)))
if has_features:
process_features(layer)---
AP-011: Loading All Features Without Filtering
WRONG:
# Loads ALL features with ALL attributes and ALL geometries
for feature in layer.getFeatures():
name = feature['name']
print(name)WHY: Loading full features (geometry + all attributes) when only one field is needed wastes memory and time. For large layers (millions of features), this causes out-of-memory errors.
CORRECT:
request = QgsFeatureRequest()
request.setFlags(QgsFeatureRequest.NoGeometry)
request.setSubsetOfAttributes(['name'], layer.fields())
for feature in layer.getFeatures(request):
print(feature['name'])---
AP-012: Using print() in Multithreaded Code
WRONG:
class MyTask(QgsTask):
def run(self):
for f in self.features:
print(f"Processing {f.id()}") # Severe performance degradation
return TrueWHY: print() acquires the GIL and performs I/O, which is extremely slow in multithreaded contexts. In expression functions and renderers, this can freeze the entire application.
CORRECT:
from qgis.core import QgsMessageLog, Qgis
class MyTask(QgsTask):
def run(self):
for f in self.features:
QgsMessageLog.logMessage(f"Processing {f.id()}", 'MyPlugin', Qgis.Info)
return True---
Geometry Anti-Patterns
AP-013: Not Checking for NULL Geometry
WRONG:
for feature in layer.getFeatures():
area = feature.geometry().area() # Crashes if geometry is NULLWHY: Features can have NULL geometries (e.g., attribute-only records, incomplete imports). Calling methods on a NULL geometry raises an error or returns meaningless values.
CORRECT:
for feature in layer.getFeatures():
geom = feature.geometry()
if not geom.isNull():
area = geom.area()---
AP-014: Using area()/length() on Geographic CRS
WRONG:
# Layer is in EPSG:4326 (WGS84, degrees)
area = geom.area() # Returns area in square degrees -- meaninglessWHY: area() and length() return values in layer units. For geographic CRS (lat/lon), units are degrees, which are not meaningful measurements.
CORRECT:
from qgis.core import QgsDistanceArea, QgsUnitTypes
d = QgsDistanceArea()
d.setEllipsoid('WGS84')
area_m2 = d.measureArea(geom) # Returns square meters
area_km2 = d.convertAreaMeasurement(area_m2, QgsUnitTypes.AreaSquareKilometers)---
AP-015: Using QgsPoint When QgsPointXY Is Required
WRONG:
from qgis.core import QgsGeometry, QgsPoint
# QgsPoint has Z/M, but fromPointXY expects QgsPointXY
geom = QgsGeometry.fromPointXY(QgsPoint(5.0, 52.0)) # Type mismatchWHY: fromPointXY() expects a QgsPointXY (2D). Passing QgsPoint (which supports Z/M) may work in some cases but is semantically incorrect and may cause unexpected behavior.
CORRECT:
from qgis.core import QgsGeometry, QgsPointXY
geom = QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0))---
AP-016: Not Validating Geometry Before Spatial Operations
WRONG:
# Self-intersecting polygon from untrusted source
result = geom.intersection(other_geom) # May return empty or incorrect geometryWHY: Invalid geometries (self-intersections, unclosed rings) produce unpredictable results in GEOS operations. Results may be silently wrong.
CORRECT:
if not geom.isGeosValid():
geom = geom.makeValid() # Fix geometry (QGIS 3.x+)
result = geom.intersection(other_geom)---
Performance Anti-Patterns
AP-017: Not Using Spatial Index for Repeated Queries
WRONG:
# O(n*m) complexity -- scans all features for every query
for source in source_layer.getFeatures():
for target in target_layer.getFeatures():
if source.geometry().intersects(target.geometry()):
process(source, target)WHY: Nested iteration is O(n*m). For layers with thousands of features, this takes minutes or hours.
CORRECT:
from qgis.core import QgsSpatialIndex, QgsFeatureRequest
index = QgsSpatialIndex(target_layer.getFeatures())
for source in source_layer.getFeatures():
bbox = source.geometry().boundingBox()
candidates = index.intersects(bbox)
for cid in candidates:
target = next(target_layer.getFeatures(QgsFeatureRequest().setFilterFid(cid)))
if source.geometry().intersects(target.geometry()):
process(source, target)---
AP-018: Repeated Feature Lookups Without Index
WRONG:
# Each nearestNeighbor call without index scans all features
for point in points:
min_dist = float('inf')
for target in target_layer.getFeatures(): # Full scan every time
dist = point.geometry().distance(target.geometry())
if dist < min_dist:
min_dist = distCORRECT:
from qgis.core import QgsSpatialIndex
index = QgsSpatialIndex(target_layer.getFeatures())
for point in points:
nearest_id = index.nearestNeighbor(point.geometry().asPoint(), 1)[0]qgis-syntax-pyqgis-api — Working Examples
Complete, copy-paste-ready code examples for all major PyQGIS patterns.
---
1. Standalone Script Template
from qgis.core import QgsApplication, QgsVectorLayer, QgsProject
# Initialize QGIS (no GUI)
qgs = QgsApplication([], False)
qgs.initQgis()
# Load a layer
layer = QgsVectorLayer("/path/to/data.gpkg|layername=points", "points", "ogr")
if not layer.isValid():
print("Layer failed to load")
qgs.exitQgis()
exit(1)
# Work with the layer
for feature in layer.getFeatures():
print(feature.id(), feature['name'])
# ALWAYS clean up
qgs.exitQgis()---
2. Feature Access Patterns
Iterate All Features
for feature in layer.getFeatures():
fid = feature.id()
name = feature['name']
geom = feature.geometry()
if not geom.isNull():
point = geom.asPoint()
print(f"Feature {fid}: {name} at ({point.x()}, {point.y()})")Filtered Iteration with Expression
from qgis.core import QgsFeatureRequest
request = QgsFeatureRequest().setFilterExpression('"population" > 50000')
request.setSubsetOfAttributes(['name', 'population'], layer.fields())
for feature in layer.getFeatures(request):
print(f"{feature['name']}: {feature['population']}")Attributes-Only Iteration (No Geometry)
from qgis.core import QgsFeatureRequest
request = QgsFeatureRequest()
request.setFlags(QgsFeatureRequest.NoGeometry)
request.setSubsetOfAttributes(['name', 'type'], layer.fields())
for feature in layer.getFeatures(request):
print(feature['name'], feature['type'])Get Single Feature by ID
from qgis.core import QgsFeatureRequest
feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(42)))
print(feature['name'])Bounding Box Query
from qgis.core import QgsFeatureRequest, QgsRectangle
bbox = QgsRectangle(4.0, 51.0, 5.0, 52.0) # xmin, ymin, xmax, ymax
request = QgsFeatureRequest().setFilterRect(bbox)
for feature in layer.getFeatures(request):
print(feature.id(), feature['name'])Check If Layer Has Features
from qgis.core import QgsFeatureRequest
request = QgsFeatureRequest().setLimit(1)
has_features = bool(list(layer.getFeatures(request)))List All Fields
for field in layer.fields():
print(f"{field.name()} ({field.typeName()})")---
3. Feature Editing
Add Features with Context Manager
from qgis.core import QgsFeature, QgsGeometry, QgsPointXY, edit
with edit(layer):
for i in range(10):
feat = QgsFeature(layer.fields())
feat.setAttributes([i, f'Point {i}'])
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(i * 1.0, 52.0)))
layer.addFeature(feat)Modify Existing Feature Attributes
from qgis.core import QgsFeatureRequest, edit
with edit(layer):
for feature in layer.getFeatures():
feature['status'] = 'processed'
layer.updateFeature(feature)Delete Features by Expression
from qgis.core import QgsFeatureRequest, edit
request = QgsFeatureRequest().setFilterExpression('"status" = \'obsolete\'')
request.setFlags(QgsFeatureRequest.NoGeometry)
with edit(layer):
for feature in layer.getFeatures(request):
layer.deleteFeature(feature.id())Bulk Add via Data Provider (No Undo, Faster)
from qgis.core import QgsFeature, QgsGeometry, QgsPointXY
features = []
for i in range(1000):
feat = QgsFeature(layer.fields())
feat.setAttributes([i, f'Bulk {i}'])
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(i * 0.01, 52.0)))
features.append(feat)
success, added = layer.dataProvider().addFeatures(features)
if success:
layer.updateExtents()Add Fields to Layer
from qgis.PyQt.QtCore import QMetaType
from qgis.core import QgsField
layer.dataProvider().addAttributes([
QgsField("category", QMetaType.Type.QString),
QgsField("score", QMetaType.Type.Double),
])
layer.updateFields() # ALWAYS call after field changesRemove Fields from Layer
# Find field index
idx = layer.fields().indexFromName('obsolete_field')
if idx >= 0:
layer.dataProvider().deleteAttributes([idx])
layer.updateFields()Edit Commands (Single Undo Operation)
layer.startEditing()
layer.beginEditCommand("Batch update scores")
try:
for feature in layer.getFeatures():
layer.changeAttributeValue(feature.id(), layer.fields().indexFromName('score'), 99.5)
layer.endEditCommand()
except Exception:
layer.destroyEditCommand()
layer.commitChanges()Check Provider Capabilities
from qgis.core import QgsVectorDataProvider
caps = layer.dataProvider().capabilities()
can_delete = bool(caps & QgsVectorDataProvider.DeleteFeatures)
can_add = bool(caps & QgsVectorDataProvider.AddFeatures)
can_modify_attr = bool(caps & QgsVectorDataProvider.ChangeAttributeValues)
can_modify_geom = bool(caps & QgsVectorDataProvider.ChangeGeometries)
print(f"Delete: {can_delete}, Add: {can_add}, ModifyAttr: {can_modify_attr}, ModifyGeom: {can_modify_geom}")---
4. Geometry Operations
Construct All Geometry Types
from qgis.core import QgsGeometry, QgsPointXY
# Point
point = QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0))
# LineString
line = QgsGeometry.fromPolylineXY([
QgsPointXY(0, 0), QgsPointXY(1, 1), QgsPointXY(2, 0)
])
# Polygon (exterior ring, closed)
polygon = QgsGeometry.fromPolygonXY([[
QgsPointXY(0, 0), QgsPointXY(10, 0),
QgsPointXY(10, 10), QgsPointXY(0, 10), QgsPointXY(0, 0)
]])
# Polygon with hole
polygon_hole = QgsGeometry.fromPolygonXY([
[QgsPointXY(0, 0), QgsPointXY(10, 0), QgsPointXY(10, 10), QgsPointXY(0, 10), QgsPointXY(0, 0)],
[QgsPointXY(2, 2), QgsPointXY(4, 2), QgsPointXY(4, 4), QgsPointXY(2, 4), QgsPointXY(2, 2)]
])
# From WKT
from_wkt = QgsGeometry.fromWkt('MULTIPOINT(0 0, 1 1, 2 2)')Spatial Predicates
from qgis.core import QgsGeometry, QgsPointXY
polygon = QgsGeometry.fromPolygonXY([[
QgsPointXY(0, 0), QgsPointXY(10, 0),
QgsPointXY(10, 10), QgsPointXY(0, 10), QgsPointXY(0, 0)
]])
point_inside = QgsGeometry.fromPointXY(QgsPointXY(5, 5))
point_outside = QgsGeometry.fromPointXY(QgsPointXY(15, 15))
print(polygon.contains(point_inside)) # True
print(polygon.contains(point_outside)) # False
print(polygon.intersects(point_inside)) # True
print(point_inside.within(polygon)) # True
print(polygon.disjoint(point_outside)) # TrueBuffer and Set Operations
from qgis.core import QgsGeometry, QgsPointXY
point = QgsGeometry.fromPointXY(QgsPointXY(5, 5))
buffered = point.buffer(2.0, 20) # 2.0 distance, 20 segments
polygon1 = QgsGeometry.fromWkt('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))')
polygon2 = QgsGeometry.fromWkt('POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))')
union = polygon1.combine(polygon2)
intersection = polygon1.intersection(polygon2)
difference = polygon1.difference(polygon2)
sym_diff = polygon1.symDifference(polygon2)
hull = union.convexHull()
centroid = union.centroid()Geometry Validation
geom = feature.geometry()
if geom.isNull():
print("NULL geometry -- skip")
elif not geom.isGeosValid():
errors = geom.validateGeometry()
for error in errors:
print(f"Validation error: {error.what()} at {error.where()}")
else:
# Safe to perform spatial operations
area = geom.area()Iterate Multi-Part Geometry
geom = QgsGeometry.fromWkt('MULTIPOINT(0 0, 1 1, 2 2)')
for part in geom.parts():
print(part.asWkt())WKT/WKB Round-Trip
from qgis.core import QgsGeometry
# Export
original = QgsGeometry.fromWkt('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))')
wkt_str = original.asWkt()
wkb_bytes = original.asWkb()
# Import
from_wkt = QgsGeometry.fromWkt(wkt_str)
from_wkb = QgsGeometry.fromWkb(bytes(wkb_bytes))---
5. Ellipsoid-Based Measurements
from qgis.core import QgsDistanceArea, QgsUnitTypes, QgsGeometry, QgsPointXY
d = QgsDistanceArea()
d.setEllipsoid('WGS84')
# Area measurement (geographic CRS)
polygon = QgsGeometry.fromPolygonXY([[
QgsPointXY(4.0, 51.0), QgsPointXY(5.0, 51.0),
QgsPointXY(5.0, 52.0), QgsPointXY(4.0, 52.0), QgsPointXY(4.0, 51.0)
]])
area_m2 = d.measureArea(polygon)
area_km2 = d.convertAreaMeasurement(area_m2, QgsUnitTypes.AreaSquareKilometers)
print(f"Area: {area_km2:.2f} km2")
# Distance between two points
dist_m = d.measureLine(QgsPointXY(4.0, 51.0), QgsPointXY(5.0, 52.0))
dist_km = d.convertLengthMeasurement(dist_m, QgsUnitTypes.DistanceKilometers)
print(f"Distance: {dist_km:.2f} km")---
6. Coordinate Transformation
from qgis.core import (QgsCoordinateTransform, QgsCoordinateReferenceSystem,
QgsProject, QgsGeometry, QgsPointXY)
# WGS84 to Web Mercator
transform = QgsCoordinateTransform(
QgsCoordinateReferenceSystem("EPSG:4326"),
QgsCoordinateReferenceSystem("EPSG:3857"),
QgsProject.instance()
)
geom = QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0))
geom.transform(transform) # In-place
print(geom.asPoint()) # Now in EPSG:3857 coordinates---
7. Spatial Index
Build and Query
from qgis.core import QgsSpatialIndex, QgsFeatureRequest, QgsPointXY, QgsRectangle
# Build index (bulk load)
index = QgsSpatialIndex(layer.getFeatures())
# Find 5 nearest features to a point
target = QgsPointXY(5.0, 52.0)
nearest_ids = index.nearestNeighbor(target, 5)
for fid in nearest_ids:
feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)))
print(f"Feature {fid}: {feature['name']}")
# Find features in bounding box
bbox = QgsRectangle(4.0, 51.0, 6.0, 53.0)
intersecting_ids = index.intersects(bbox)
print(f"Found {len(intersecting_ids)} features in bbox")Spatial Join Pattern
from qgis.core import QgsSpatialIndex, QgsFeatureRequest
# Build index on target layer
target_index = QgsSpatialIndex(target_layer.getFeatures())
# For each source feature, find intersecting targets
for source_feat in source_layer.getFeatures():
bbox = source_feat.geometry().boundingBox()
candidate_ids = target_index.intersects(bbox)
for cid in candidate_ids:
target_feat = next(target_layer.getFeatures(QgsFeatureRequest().setFilterFid(cid)))
# Exact geometry test (index only tests bounding boxes)
if source_feat.geometry().intersects(target_feat.geometry()):
print(f"Source {source_feat.id()} intersects Target {cid}")---
8. Background Task (QgsTask Subclass)
from qgis.core import QgsTask, QgsApplication, QgsMessageLog, Qgis
class BufferTask(QgsTask):
def __init__(self, description, features, distance):
super().__init__(description, QgsTask.CanCancel)
self.features = features # Pre-copied data
self.distance = distance
self.results = []
self.exception = None
def run(self):
try:
total = len(self.features)
for i, feat in enumerate(self.features):
if self.isCanceled():
return False
geom = feat.geometry()
if not geom.isNull():
buffered = geom.buffer(self.distance, 20)
self.results.append((feat.id(), buffered))
self.setProgress((i + 1) / total * 100)
return True
except Exception as e:
self.exception = e
return False
def finished(self, result):
if result:
QgsMessageLog.logMessage(
f"Buffered {len(self.results)} features",
'BufferPlugin', Qgis.Success
)
elif self.exception:
QgsMessageLog.logMessage(
f"Buffer failed: {self.exception}",
'BufferPlugin', Qgis.Critical
)
# Copy features before creating task
features_copy = [f for f in layer.getFeatures()]
task = BufferTask("Buffering features", features_copy, 100.0)
QgsApplication.taskManager().addTask(task)---
9. Background Task from Function
from qgis.core import QgsTask, QgsApplication
def calculate_stats(task, values):
total = len(values)
running_sum = 0
for i, v in enumerate(values):
if task.isCanceled():
return None
running_sum += v
task.setProgress((i + 1) / total * 100)
return {'mean': running_sum / total, 'count': total}
def on_complete(exception, result=None):
if exception is None and result is not None:
print(f"Mean: {result['mean']}, Count: {result['count']}")
elif exception:
print(f"Error: {exception}")
task = QgsTask.fromFunction(
'Calculate statistics',
calculate_stats,
on_finished=on_complete,
values=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
)
QgsApplication.taskManager().addTask(task)---
10. Task Dependencies
from qgis.core import QgsTask, QgsApplication
task_a = QgsTask.fromFunction('Step A', step_a_func, on_finished=on_a_done, data=data_a)
task_b = QgsTask.fromFunction('Step B', step_b_func, on_finished=on_b_done, data=data_b)
# task_a depends on task_b completing first
task_a.addSubTask(task_b, [], QgsTask.ParentDependsOnSubTask)
QgsApplication.taskManager().addTask(task_a)---
11. User Communication
Log Messages
from qgis.core import QgsMessageLog, Qgis
QgsMessageLog.logMessage("Processing started", 'MyPlugin', Qgis.Info)
QgsMessageLog.logMessage("Unusual value detected", 'MyPlugin', Qgis.Warning)
QgsMessageLog.logMessage("File not found", 'MyPlugin', Qgis.Critical)
QgsMessageLog.logMessage("All features processed", 'MyPlugin', Qgis.Success)Message Bar (Main Thread Only)
from qgis.core import Qgis
# Auto-dismiss after 3 seconds
iface.messageBar().pushMessage("Done", "Processed 500 features", level=Qgis.Success, duration=3)
# Persistent error (stays until dismissed)
iface.messageBar().pushMessage("Error", "Layer failed to load", level=Qgis.Critical)Message Bar with Button
from qgis.PyQt.QtWidgets import QPushButton
from qgis.core import Qgis
widget = iface.messageBar().createMessage("Alert", "Missing CRS definition")
button = QPushButton(widget)
button.setText("Set CRS")
button.pressed.connect(set_crs_function)
widget.layout().addWidget(button)
iface.messageBar().pushWidget(widget, Qgis.Warning)Progress Bar in Message Bar
from qgis.PyQt.QtWidgets import QProgressBar
from qgis.core import Qgis
msg = iface.messageBar().createMessage("Processing...")
progress = QProgressBar()
progress.setMaximum(100)
msg.layout().addWidget(progress)
iface.messageBar().pushWidget(msg, Qgis.Info)
for i in range(100):
progress.setValue(i + 1)
# ... do work ...
iface.messageBar().clearWidgets()---
12. Basic Symbology
Single Symbol
from qgis.core import QgsMarkerSymbol
symbol = QgsMarkerSymbol.createSimple({
'name': 'circle',
'color': '#ff0000',
'size': '4',
'outline_color': '#000000',
'outline_width': '0.5'
})
layer.renderer().setSymbol(symbol)
layer.triggerRepaint()Categorized Renderer
from qgis.core import QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsMarkerSymbol
categories = [
QgsRendererCategory('residential', QgsMarkerSymbol.createSimple({'color': 'blue'}), 'Residential'),
QgsRendererCategory('commercial', QgsMarkerSymbol.createSimple({'color': 'red'}), 'Commercial'),
QgsRendererCategory('industrial', QgsMarkerSymbol.createSimple({'color': 'gray'}), 'Industrial'),
]
renderer = QgsCategorizedSymbolRenderer('landuse', categories)
layer.setRenderer(renderer)
layer.triggerRepaint()Graduated Renderer
from qgis.core import (QgsGraduatedSymbolRenderer, QgsRendererRange,
QgsClassificationRange, QgsMarkerSymbol)
ranges = [
QgsRendererRange(QgsClassificationRange('Low', 0, 1000),
QgsMarkerSymbol.createSimple({'color': 'green'})),
QgsRendererRange(QgsClassificationRange('Medium', 1000, 10000),
QgsMarkerSymbol.createSimple({'color': 'orange'})),
QgsRendererRange(QgsClassificationRange('High', 10000, 1000000),
QgsMarkerSymbol.createSimple({'color': 'red'})),
]
renderer = QgsGraduatedSymbolRenderer('population', ranges)
layer.setRenderer(renderer)
layer.triggerRepaint()Rule-Based Renderer
from qgis.core import QgsRuleBasedRenderer, QgsMarkerSymbol
root = QgsRuleBasedRenderer.Rule(QgsMarkerSymbol())
rule_large = QgsRuleBasedRenderer.Rule(
QgsMarkerSymbol.createSimple({'color': 'red', 'size': '5'}),
filterExp='"population" > 100000',
label='Large cities'
)
rule_small = QgsRuleBasedRenderer.Rule(
QgsMarkerSymbol.createSimple({'color': 'blue', 'size': '2'}),
filterExp='"population" <= 100000',
label='Small cities'
)
root.appendChild(rule_large)
root.appendChild(rule_small)
renderer = QgsRuleBasedRenderer(root)
layer.setRenderer(renderer)
layer.triggerRepaint()Simple Labeling
from qgis.core import QgsPalLayerSettings, QgsVectorLayerSimpleLabeling, QgsTextFormat
from qgis.PyQt.QtGui import QColor
settings = QgsPalLayerSettings()
settings.fieldName = 'name'
settings.enabled = True
text_format = QgsTextFormat()
text_format.setSize(10)
text_format.setColor(QColor('black'))
buffer = text_format.buffer()
buffer.setEnabled(True)
buffer.setSize(1.0)
buffer.setColor(QColor('white'))
settings.setFormat(text_format)
labeling = QgsVectorLayerSimpleLabeling(settings)
layer.setLabeling(labeling)
layer.setLabelsEnabled(True)
layer.triggerRepaint()qgis-syntax-pyqgis-api — Method Reference
API signatures for QgsFeature, QgsFeatureRequest, QgsGeometry, QgsSpatialIndex, QgsTask, and related classes.
---
QgsFeature
Represents a single feature with geometry and attributes.
Construction
QgsFeature() # Empty feature
QgsFeature(fields: QgsFields) # Feature with field schema (preferred)
QgsFeature(id: int) # Feature with specific IDAttribute Access
| Method | Return Type | Description |
|---|---|---|
id() | int | Feature ID (unique within layer) |
geometry() | QgsGeometry | Feature geometry (may be NULL) |
attributes() | list | All attribute values as list |
attribute(name: str) | any | Attribute value by field name |
attribute(index: int) | any | Attribute value by field index |
__getitem__(name_or_index) | any | Shorthand: feature['name'] or feature[0] |
fields() | QgsFields | Field schema of this feature |
isValid() | bool | Whether feature is valid |
Attribute Modification
| Method | Description |
|---|---|
setAttributes(attrs: list) | Set all attributes at once |
setAttribute(index: int, value) | Set single attribute by index |
setAttribute(name: str, value) | Set single attribute by name |
__setitem__(name_or_index, value) | Shorthand: feature['name'] = value |
setGeometry(geom: QgsGeometry) | Set feature geometry |
setId(id: int) | Set feature ID |
setFields(fields: QgsFields) | Set field schema |
initAttributes(count: int) | Initialize attribute array with NULL values |
---
QgsFeatureRequest
Controls which features are returned and what data is loaded.
Filter Methods (Chainable)
| Method | Description |
|---|---|
setFilterExpression(expr: str) | Filter by expression string |
setFilterRect(rect: QgsRectangle) | Filter by bounding box |
setFilterFid(fid: int) | Filter to single feature ID |
setFilterFids(fids: set) | Filter to set of feature IDs |
setLimit(limit: int) | Maximum number of features to return |
Optimization Methods (Chainable)
| Method | Description |
|---|---|
setFlags(flags) | Set request flags (see below) |
setSubsetOfAttributes(indices: list) | Load only specified field indices |
setSubsetOfAttributes(names: list, fields: QgsFields) | Load only specified field names |
setNoAttributes() | Load no attributes at all |
addOrderBy(fieldOrExpression: str, ascending: bool) | Sort results |
Request Flags
| Flag | Effect |
|---|---|
QgsFeatureRequest.NoGeometry | Skip geometry loading (faster when only attributes needed) |
QgsFeatureRequest.ExactIntersect | Exact geometry intersection instead of bounding box only |
QgsFeatureRequest.SubsetOfAttributes | Automatically set when using setSubsetOfAttributes() |
Usage Pattern
# Chain multiple filters
request = (QgsFeatureRequest()
.setFilterExpression('"population" > 10000')
.setSubsetOfAttributes(['name', 'population'], layer.fields())
.setLimit(100))
for feature in layer.getFeatures(request):
print(feature['name'])---
QgsGeometry
High-level geometry wrapper providing GEOS-based spatial operations.
Static Construction Methods
| Method | Creates |
|---|---|
QgsGeometry.fromPointXY(QgsPointXY) | Point geometry |
QgsGeometry.fromPolylineXY([QgsPointXY, ...]) | LineString geometry |
QgsGeometry.fromPolygonXY([[QgsPointXY, ...]]) | Polygon geometry (list of rings) |
QgsGeometry.fromMultiPointXY([QgsPointXY, ...]) | MultiPoint geometry |
QgsGeometry.fromMultiPolylineXY([[QgsPointXY, ...]]) | MultiLineString geometry |
QgsGeometry.fromMultiPolygonXY([[[QgsPointXY, ...]]]) | MultiPolygon geometry |
QgsGeometry.fromWkt(wkt: str) | From Well-Known Text |
QgsGeometry.fromWkb(wkb: bytes) | From Well-Known Binary |
QgsGeometry.fromPolyline([QgsPoint, ...]) | LineString with Z/M support |
Extraction Methods
| Method | Returns | Geometry Type |
|---|---|---|
asPoint() | QgsPointXY | Point |
asPolyline() | list[QgsPointXY] | LineString |
asPolygon() | list[list[QgsPointXY]] | Polygon (list of rings) |
asMultiPoint() | list[QgsPointXY] | MultiPoint |
asMultiPolyline() | list[list[QgsPointXY]] | MultiLineString |
asMultiPolygon() | list[list[list[QgsPointXY]]] | MultiPolygon |
Spatial Predicates (Return bool)
| Method | True When |
|---|---|
contains(other) | Other is completely inside self |
within(other) | Self is completely inside other |
intersects(other) | Geometries share any space |
touches(other) | Boundaries touch, interiors do not overlap |
crosses(other) | Geometries cross each other |
overlaps(other) | Partial overlap (same dimension geometries) |
disjoint(other) | No shared space whatsoever |
equals(other) | Geometrically identical |
Spatial Operations (Return QgsGeometry)
| Method | Result |
|---|---|
buffer(distance, segments) | Polygon at given distance around geometry |
intersection(other) | Shared area/line between geometries |
combine(other) | Union of geometries |
difference(other) | Part of self not in other |
symDifference(other) | Non-overlapping parts of both |
convexHull() | Smallest convex polygon enclosing geometry |
centroid() | Center point geometry |
pointOnSurface() | Point guaranteed inside geometry |
simplify(tolerance) | Simplified geometry (Douglas-Peucker) |
Measurement Methods
| Method | Returns | Notes |
|---|---|---|
area() | float | Polygon area in layer units (projected CRS only) |
length() | float | Line length / perimeter in layer units (projected CRS only) |
distance(other) | float | Shortest distance to other geometry |
Validation and Properties
| Method | Returns | Description |
|---|---|---|
isNull() | bool | True if geometry is NULL |
isEmpty() | bool | True if geometry has no coordinates |
isGeosValid() | bool | True if geometry passes GEOS validation |
validateGeometry() | list[QgsGeometry.Error] | Detailed validation errors |
isMultipart() | bool | True if multi-geometry |
wkbType() | QgsWkbTypes.Type | Detailed WKB type |
type() | Qgis.GeometryType | General type (Point/Line/Polygon) |
parts() | iterator | Iterate over geometry parts |
Import/Export
| Method | Description |
|---|---|
asWkt() | Export as Well-Known Text string |
asWkb() | Export as Well-Known Binary bytes |
asJson() | Export as GeoJSON string |
Transformation
| Method | Description |
|---|---|
transform(QgsCoordinateTransform) | In-place CRS transformation |
transform(QTransform) | In-place affine transformation |
Low-Level Access
| Method | Returns | Description |
|---|---|---|
get() | QgsAbstractGeometry | Mutable access to underlying geometry |
constGet() | QgsAbstractGeometry | Read-only access to underlying geometry |
---
QgsSpatialIndex
R-tree based spatial index for fast bounding box queries.
Construction
QgsSpatialIndex() # Empty index
QgsSpatialIndex(featureIterator) # Bulk load from iterator (fastest)
QgsSpatialIndex(layer.getFeatures()) # Bulk load from layerMethods
| Method | Returns | Description |
|---|---|---|
addFeature(feature) | bool | Add single feature to index |
addFeatures(features) | bool | Add multiple features |
deleteFeature(feature) | bool | Remove feature from index |
nearestNeighbor(point, neighbors) | list[int] | Feature IDs of N nearest features |
intersects(rectangle) | list[int] | Feature IDs whose bbox intersects rectangle |
Performance
- Build time: O(n log n) for bulk loading
- Query time: O(log n) for intersection and nearest neighbor
- Returns feature IDs only -- ALWAYS fetch features separately via
QgsFeatureRequest().setFilterFid()
---
QgsSpatialIndexKDBush
Specialized index for point data only. Faster than QgsSpatialIndex for point-only datasets.
| Property | Value |
|---|---|
| Geometry types | Single points only |
| Mutability | Static (cannot add after creation) |
| Speed | Significantly faster than R-tree for points |
| Feature retrieval | Returns original points directly (no second query) |
---
QgsTask
Base class for background operations.
Construction
QgsTask.__init__(self, description: str, flags: QgsTask.Flags)
QgsTask.fromFunction(description, function, on_finished=callback, **kwargs)Task Flags
| Flag | Description |
|---|---|
QgsTask.CanCancel | Task supports cancellation |
QgsTask.CancelWithoutPrompt | Cancel without user confirmation |
QgsTask.Hidden | Task not shown in task manager |
Methods to Override
| Method | Thread | Must Return | Description |
|---|---|---|---|
run() | Background | bool | Main work. Return True on success, False on failure |
finished(result: bool) | Main | Nothing | Called after run() completes. Safe for GUI access |
cancel() | Main | Nothing | Called when task is canceled |
Methods to Call
| Method | Description |
|---|---|
setProgress(percent: float) | Report progress (0-100) |
isCanceled() | Check if cancellation was requested |
setDependentLayers([layers]) | Auto-cancel if layers become unavailable |
addSubTask(task, deps, behavior) | Add dependent sub-task |
Sub-Task Behaviors
| Behavior | Description |
|---|---|
QgsTask.ParentDependsOnSubTask | Parent waits for sub-task to complete |
QgsTask.SubTaskIndependent | Sub-task runs independently |
---
QgsTaskManager
Global task scheduler accessed via QgsApplication.taskManager().
| Method | Description |
|---|---|
addTask(task) | Schedule task for execution |
activeTasks() | List of running tasks |
count() | Number of active tasks |
---
QgsDistanceArea
Ellipsoid-based measurement calculator.
Setup
d = QgsDistanceArea()
d.setEllipsoid('WGS84')
d.setSourceCrs(crs, QgsProject.instance().transformContext())Measurement Methods
| Method | Returns | Description |
|---|---|---|
measureArea(geom) | float | Area in square meters |
measurePerimeter(geom) | float | Perimeter in meters |
measureLine(point1, point2) | float | Distance between points in meters |
measureLength(geom) | float | Line length in meters |
convertAreaMeasurement(area, unit) | float | Convert area to target unit |
convertLengthMeasurement(length, unit) | float | Convert length to target unit |
---
QgsMessageLog
Static Methods
QgsMessageLog.logMessage(message: str, tag: str, level: Qgis.MessageLevel)Qgis.MessageLevel
| Level | Value | Description |
|---|---|---|
Qgis.Info | 0 | Informational |
Qgis.Warning | 1 | Warning |
Qgis.Critical | 2 | Error/critical |
Qgis.Success | 3 | Success confirmation |
---
QgsMessageBar
Accessed via iface.messageBar(). NEVER use from background threads.
| Method | Description |
|---|---|
pushMessage(title, text, level, duration) | Show message (duration=0 for persistent) |
pushWidget(widget, level) | Show custom widget message |
createMessage(title, text) | Create message widget for customization |
clearWidgets() | Remove all messages |
---
QgsField
Construction
from qgis.PyQt.QtCore import QMetaType
from qgis.core import QgsField
QgsField("name", QMetaType.Type.QString)
QgsField("value", QMetaType.Type.Int)
QgsField("amount", QMetaType.Type.Double)Common QMetaType.Type Values
| Type | Python Equivalent |
|---|---|
QMetaType.Type.QString | str |
QMetaType.Type.Int | int |
QMetaType.Type.Double | float |
QMetaType.Type.Bool | bool |
QMetaType.Type.QDate | datetime.date |
QMetaType.Type.QDateTime | datetime.datetime |