Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
openaec-foundation avatar

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-api

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs8
repo stars29
Last updatedJuly 8, 2026
Repositoryopenaec-foundation/qgis-claude-skill-package

What it does

Helps with backend & apis tasks.

Files

SKILL.mdMarkdownGitHub ↗

qgis-syntax-pyqgis-api

Quick Reference

Scripting Contexts

Contextiface AvailableInitialization RequiredUse Case
Python ConsoleYesNoneInteractive exploration, quick tests
Standalone ScriptNoQgsApplication([], False) + initQgis()CLI tools, CI pipelines, batch processing
Processing ScriptNo (feedback instead)None (framework handles it)Geoprocessing algorithms
PluginYes (via classFactory)NoneGUI extensions, toolbar tools

Core Classes

ClassPurposeKey Methods
QgsFeatureSingle feature (geometry + attributes)id(), geometry(), attributes(), __getitem__()
QgsFeatureRequestFilter/optimize feature queriessetFilterExpression(), setFilterRect(), setLimit(), setFlags()
QgsGeometryGeometry wrapper with GEOS operationsfromPointXY(), buffer(), intersection(), contains()
QgsSpatialIndexR-tree spatial indexaddFeature(), nearestNeighbor(), intersects()
QgsTaskBackground processingrun(), finished(), setProgress(), isCanceled()
QgsMessageLogLog panel messageslogMessage(msg, tag, level)
QgsMessageBarMap canvas notificationspushMessage(title, text, level, duration)

QgsPoint vs QgsPointXY

ClassDimensionsUse With
QgsPointXY2D (X, Y) onlyfromPointXY(), fromPolylineXY(), fromPolygonXY()
QgsPoint2D + Z + MfromPolyline(), 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 up

Dual-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 exception

Geometry 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 changes

Ellipsoid-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 transformation

Basic Symbology

from qgis.core import QgsMarkerSymbol

symbol = QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red', 'size': '3'})
layer.renderer().setSymbol(symbol)
layer.triggerRepaint()

Renderer Types Overview

RendererClassUse Case
Single SymbolQgsSingleSymbolRendererAll features same style
CategorizedQgsCategorizedSymbolRendererDiscrete attribute values
GraduatedQgsGraduatedSymbolRendererNumeric ranges
Rule-BasedQgsRuleBasedRendererExpression-driven rules

---

Data Provider vs Edit Buffer

AspectData ProviderEdit Buffer
Methodlayer.dataProvider().addFeatures()layer.addFeature()
Undo supportNoYes
Edit session requiredNoYes
PerformanceFaster for bulk operationsSlower, safer
Use caseBatch processing, scriptsInteractive 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

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.