შიგთავსზე გადასვლა

PyQGIS — გავრცელებული შეცდომები და გამოსწორება

PyQGIS-ში მუშაობისას ზოგიერთი შეცდომა განმეორებადია. ეს გვერდი აღწერს ყველაზე ხშირ შეცდომებს — რას ნიშნავს თითოეული და როგორ გამოსწორდება.


📋 სწრაფი ცნობარი

შეცდომა მიზეზი
EOL while scanning string literal ბრჭყალი ან ' აკლია
AttributeError: QVariant has no attribute 'int' პატარა i — სწორია Int
NameError: name 'X' is not defined typo სახელში ან ['Region'] ნაცვლად [Region]
IndexError: list index out of range შრის სახელი პროექტში ვერ მოიძებნა
KeyError: 'field_name' სვეტი ატრიბუტულ ცხრილში არ არსებობს
AssertionError (startEditing) შრე რედაქტირების რეჟიმში უკვე გახსნილია
invalid syntax სიტყვა ან სიმბოლო გაყოფილია — ერთად უნდა იწეროს
Missing functions in IDE import qgis კოდის დასაწყისში აკლია

🔴 EOL while scanning string literal

რას ნიშნავს?

EOL = End Of Line — Python-მა სტრიქონი ბოლომდე ვერ წაიკითხა, რადგან ბრჭყალი დაკარგულია.

მიზეზი 1 — 'INPUT'-ს აკლია ' ერთ მხარეს

# ❌ შეცდომა — INPUT-ს წინ აკლია '
processing.run("native:deletecolumn", {INPUT': layer,
    'COLUMN': ['SHAPE_Leng'],
    'OUTPUT': out
})

# ✅ სწორია
processing.run("native:deletecolumn", {'INPUT': layer,
    'COLUMN': ['SHAPE_Leng'],
    'OUTPUT': out
})

მიზეზი 2 — ფაილის ბილიკს ბოლოში " აკლია

# ❌ შეცდომა
fn = r'C:\Users\Public\GIS\shapefile\roads.shp   # ← ' აკლია ბოლოში

# ✅ სწორია
fn = r'C:\Users\Public\GIS\shapefile\roads.shp'

💡 გახსოვდეს: ყოველი გახსნილი ' ან " დახურული უნდა იყოს.


🔴 AttributeError: type object 'QVariant' has no attribute 'int'

რას ნიშნავს?

QVariant-ის ატრიბუტი int (პატარა ასოებით) არ არსებობს — Python case-sensitive ენაა.

# ❌ შეცდომა — პატარა 'i'
fields.append(QgsField('ID', QVariant.int))

# ✅ სწორია — დიდი 'I'
fields.append(QgsField('ID', QVariant.Int))

სწორი მნიშვნელობები

QVariant.Int        # მთელი რიცხვი
QVariant.Double     # ათწილადი
QVariant.String     # ტექსტი
QVariant.Bool       # True / False
QVariant.Date       # თარიღი
QVariant.DateTime   # თარიღი + დრო

🔴 NameError: name 'X' is not defined

მიზეზი 1 — typo ცვლადის სახელში

# ❌ შეცდომა — 'layes' (r აკლია)
layer = layes[0]

# ✅ სწორია
layer = layers[0]
# ❌ შეცდომა — 'f' (n აკლია)
iface.addVectorLayer(f, '', 'ogr')

# ✅ სწორია
iface.addVectorLayer(fn, '', 'ogr')

მიზეზი 2 — ['Region'] ნაცვლად [Region]

FIELD პარამეტრი სტრიქონების სიას ელოდება — ბრჭყალები სავალდებულოა:

# ❌ შეცდომა — Region ბრჭყალების გარეშე, Python მას ცვლადად ეძებს
processing.run("native:dissolve", {
    'INPUT' : layer,
    'FIELD' : [Region],       # ← Python: "ცვლადი Region?"
    'OUTPUT': fn
})

# ✅ სწორია — 'Region' სტრიქონი სიაში
processing.run("native:dissolve", {
    'INPUT' : layer,
    'FIELD' : ['Region'],     # ← სვეტის სახელი სტრიქონად
    'OUTPUT': fn
})

🔴 IndexError: list index out of range

რას ნიშნავს?

mapLayersByName() ცარიელ სიას აბრუნებს — შრე ამ სახელით პროექტში ვერ მოიძებნა.

# ❌ შეცდომა — 'sadguri' სახელის შრე პროექტში არ არის
layers = QgsProject.instance().mapLayersByName('sadguri')
layer  = layers[0]   # ← IndexError: list index out of range
# ✅ სწორია — ჯერ შეამოწმე, შემდეგ გამოიყენე
layers = QgsProject.instance().mapLayersByName('sadguri')

if not layers:
    print("❌ შრე 'sadguri' ვერ მოიძებნა — შეამოწმე სახელი Layers პანელში")
else:
    layer = layers[0]
    print(f"✅ ნაპოვნია: {layer.name()}")

💡 როგორ შეამოწმო სახელი? QGIS Layers პანელში შრეს თავზე გადაატარე — ზუსტი სახელი გამოჩნდება. კოდში სიტყვა-სიტყვით უნდა ემთხვეოდეს (მათ შორის, დიდი/პატარა ასოებიც).


🔴 KeyError: 'field_name'

მიზეზი 1 — სვეტი ატრიბუტულ ცხრილში არ არსებობს

# ❌ შეცდომა — 'fid' სვეტი ცხრილში არ არის
for feat in layer.getFeatures():
    print(feat['fid'])   # → KeyError: 'fid'
# ✅ გამოსწორება — ჯერ შეამოწმე სვეტები
print([f.name() for f in layer.fields()])
# → ['ID', 'Name', 'Area', 'Region']  ← 'fid' არ არის!

# შემდეგ გამოიყენე სწორი სახელი
for feat in layer.getFeatures():
    print(feat['ID'])

მიზეზი 2 — სვეტის სახელი ძალიან გრძელია Shapefile-ისთვის

ESRI Shapefile-ი მაქსიმუმ 10 სიმბოლოს იძლევა სვეტის სახელში:

# ❌ შეცდომა — 12 სიმბოლო, Shapefile ვერ ინახავს
layer.dataProvider().addAttributes([
    QgsField('X_coordinate', QVariant.Double)   # → KeyError: 'X_coordinate'
])

# ✅ სწორია — 10 სიმბოლოს ფარგლებში
layer.dataProvider().addAttributes([
    QgsField('X_coord', QVariant.Double)        # 7 სიმბოლო ✅
])

💡 GeoPackage (.gpkg) ან GeoJSON ფორმატებს სახელის სიგრძის შეზღუდვა არ აქვთ.


🔴 AssertionError — startEditing()

რას ნიშნავს?

შრე რედაქტირების რეჟიმში (Edit Mode) უკვე გახსნილია — ორჯერ ვერ გაიხსნება.

AssertionError
File "edit.py", line 38, in __enter__
    assert self.layer.startEditing()

გამოსწორება

# ✅ გამოსწორება A — QGIS-ში ხელით გათიშე Edit Mode (✏️ ღილაკი Toolbar-ში)

# ✅ გამოსწორება B — კოდში შეამოწმე, სანამ გახსნი
if layer.isEditable():
    layer.rollBack()        # ან layer.commitChanges()

with edit(layer):
    # ახლა უსაფრთხოდ შეგიძლია რედაქტირება
    layer.changeAttributeValue(feat.id(), idx, new_value)

⚠️ QGIS-ში Layers პანელში შრეს ✏️ პატარა ფანქრის ხატი ეკვრის თუ Edit Mode ჩართულია — გათიშე სანამ სკრიპტს გაუშვებ.


🔴 invalid syntax — Processing ფუნქციის სახელი

რას ნიშნავს?

ფუნქციის სახელი გაყოფილია — Python ვერ ცნობს გაყოფილ სახელს.

# ❌ შეცდომა — 'proces sing' გაყოფილია
proces sing.run("native:deleteduplicategeometries", {
    'INPUT' : layer,
    'OUTPUT': output
})

# ✅ სწორია — ერთად
processing.run("native:deleteduplicategeometries", {
    'INPUT' : layer,
    'OUTPUT': output
})

🔴 Missing functions in IDE

რას ნიშნავს?

გარე IDE-ში (VS Code, PyCharm) QgsVectorLayer, QgsProject და სხვა კლასები არ ჩანს, რადგან qgis მოდული შემოტანილი არ არის.

# ❌ შეცდომა — QGIS კლასები ხელმისაწვდომი არ არის
layer = QgsVectorLayer(fn, 'Layer', 'ogr')   # → NameError

# ✅ სწორია — კოდის დასაწყისში შემოიტანე
import qgis
from qgis.core import QgsVectorLayer, QgsProject, QgsVectorFileWriter

layer = QgsVectorLayer(fn, 'Layer', 'ogr')

💡 QGIS Python Console-ში ეს იმპორტი ავტომატურად ხდება. გარე IDE-ში ხელით უნდა ჩაწერო.


🗂️ ფაილის ბილიკები — სწორი ჩაწერა

Windows-ზე \ სიმბოლო Python-ში escape character-ია — სპეციალური მნიშვნელობა აქვს.

# ❌ არასწორი — \U, \P Python-ი სპეციალურ სიმბოლოდ კითხულობს
fn = 'C:\Users\Public\GIS\points.shp'

# ✅ ვარიანტი 1 — r"" raw string (რეკომენდებული)
fn = r'C:\Users\Public\GIS\points.shp'

# ✅ ვარიანტი 2 — ორმაგი backslash
fn = 'C:\\Users\\Public\\GIS\\points.shp'

# ✅ ვარიანტი 3 — forward slash (მუშაობს Windows-ზეც)
fn = 'C:/Users/Public/GIS/points.shp'

💡 რეკომენდაცია: გამოიყენე r'' (raw string) — ყველაზე კითხვადია და შეცდომები გამოირიცხება.


💡 iface.addVectorLayer() — სახელის პარამეტრი

iface.addVectorLayer(fn, '', 'ogr')
#                        ↑
#                  ეს არის შრის სახელი QGIS-ში
#                  '' = ცარიელი → QGIS ფაილის სახელს გამოიყენებს
# სახელის მითითებით
iface.addVectorLayer(fn, 'ჩემი შრე', 'ogr')

🔴 TypeError: '>=' not supported between instances of 'str' and 'int'

რას ნიშნავს?

Python ცდილობს სტრიქონი შეადაროს მთელ რიცხვს — ეს შეუძლებელია. >=, <=, >, < ოპერატორები ერთი ტიპის მნიშვნელობებს შორის მუშაობს.

კოდი სადაც ხდება

layers = QgsProject.instance().mapLayersByName('gis_osm_places_free_1')
layer  = layers[0]

delf  = layer.dataProvider().capabilities()
feats = layer.getFeatures()
dfeats = []

if delf & QgsVectorDataProvider.DeleteFeatures:
    for feat in feats:
        if feat['osm_id'] >= 9934538919:   # ← ❌ TypeError აქ!
            dfeats.append(feat.id())

მიზეზი

feat['osm_id'] — ატრიბუტულ ცხრილში osm_id სვეტი სტრიქონის (str) ტიპად არის შენახული, მაგრამ 9934538919 მთელი რიცხვია (int):

for feat in layer.getFeatures():
    print(type(feat['osm_id']))
# → <class 'str'>   ← სტრიქონი, არა int!

# Python ვერ ადარებს:
"9934538919" >= 9934538919   # ❌ TypeError

სვეტის ტიპის შემოწმება

for field in layer.fields():
    if field.name() == 'osm_id':
        print(f"სახელი: {field.name()}")
        print(f"ტიპი:   {field.typeName()}")   # → "String" ან "Integer"
        print(f"ტიპი:   {field.type()}")        # → 10 (String) ან 2 (Int)

გამოსწორება — int() გარდაქმნა

# ✅ str → int გარდაქმნა შედარებამდე
if delf & QgsVectorDataProvider.DeleteFeatures:
    for feat in feats:
        if int(feat['osm_id']) >= 9934538919:
            dfeats.append(feat.id())
    df = layer.dataProvider().deleteFeatures(dfeats)
    layer.triggerRepaint()

გამოსწორება — უსაფრთხო ვარიანტი try/except-ით

# ✅ თუ osm_id ზოგჯერ ცარიელია ან NULL-ია
if delf & QgsVectorDataProvider.DeleteFeatures:
    for feat in feats:
        try:
            osm_id = int(feat['osm_id'])
            if osm_id >= 9934538919:
                dfeats.append(feat.id())
        except (ValueError, TypeError):
            print(f"⚠️ Feature {feat.id()}: osm_id გარდაქმნა ვერ მოხდა → '{feat['osm_id']}'")

    if dfeats:
        df = layer.dataProvider().deleteFeatures(dfeats)
        layer.triggerRepaint()
        print(f"🗑️ წაიშალა {len(dfeats)} feature")
    else:
        print("ℹ️ წასაშლელი feature ვერ მოიძებნა")

ტიპების შედარების ცხრილი

სვეტის ტიპი feat['osm_id'] შედარება int-თან გამოსწორება
String "9934538919" ❌ TypeError int(feat['osm_id'])
Integer / Int64 9934538919 ✅ მუშაობს გარდაქმნა არ სჭირდება
Double 9934538919.0 ✅ მუშაობს int() სურვილისამებრ
NULL / None None ❌ TypeError try/except

💡 OSM მონაცემებში (osm_id) სვეტი ხშირად String-ად ინახება — ID-ები ძალიან დიდი შეიძლება იყოს. ყოველთვის შეამოწმე სვეტის ტიპი field.typeName()-ით სანამ შეადარებ.


🔴 PyQGIS Crash

processing.run("native:pointstopath", {'INPUT': fn, 'CLOSE_PATH': True, \

             'ORDER_EXPRESSION': '"ID"', 'NATURAL_SORT': False, \

             'GROUP_EXPRESSION': '', 'OUTPUT': output })
  1. მთავარი მიზეზი: ORDER_EXPRESSION-ში არასწორი სინტაქსი ან არარსებული სვეტი თუ ცხრილში სვეტი ID საერთოდ არ არსებობს, ან სინტაქსია არასწორი, QGIS-ის C++ ბირთვი (Backend) ცდილობს წაიკითხოს არარსებული მონაცემი. პითონისგან განსხვავებით, რომელიც შეცდომას ამოაგდებდა, C++ ამ დროს ხშირად მეხსიერების შეცდომას (Segmentation Fault) აწყდება და მთლიან QGIS-ს აყოლებს.

როგორ უნდა ეწეროს სწორად: ORDER_EXPRESSION ელოდება ტექსტს (String), რომელიც ველის სახელია. ორმაგი ბრჭყალები ბრჭყალებში ('"ID"') ხშირად იწვევს არევას.

გამოსავალი: თუ სვეტი არის ID, ჩაწერე უბრალოდ 'ID'. თუ ეს სვეტი საერთოდ არ არის შრეში, ეს ხაზი ან ამოიღე, ან დატოვე ცარიელი '', რადგან ეს პარამეტრი სავალდებულო არ არის (Optional).

  1. ფაილის ჩაწერის/გადაწერის პრობლემა (Lock) თუ კოდს მეორედ უშვებ და lake_line.shp უკვე გახსნილი გაქვს QGIS-ში (ინტერფეისში მარცხნივ პანელზე გიგდია), ხელსაწყო ცდილობს ამ ფაილის თავზე გადაწერას. ვინაიდან ფაილი QGIS-ს დაკავებული (Locked) აქვს, ოპერაციული სისტემა უკრძალავს ჩაწერას, რაზეც native:pointstopath ხშირად მწყობრიდან გამოდის.

როგორ გამოვასწოროთ კოდი? უსაფრთხოებისთვის უმჯობესია გამოიყენო Memory Layer (მეხსიერების დროებითი შრე) output-ად, რათა მყარ დისკზე ფაილების წერამ და გადაწერამ არ აურიოს. თუ მაინცდამაინც ფაილად შენახვა გინდა, სინტაქსი ასე შეასწორე:

import processing

fn = r'C:\Users\Public\Documents\GK\PyQGIS\shp\lake.shp'
output = r'C:\Users\Public\Documents\GK\PyQGIS\shp\lake_line.shp'

# უსაფრთხო პარამეტრები: თუ ID სვეტი არ გაქვს, საერთოდ ამოიღე ORDER_EXPRESSION
# ან ჩაწერე რეალური სვეტის სახელი, მაგალითად 'id' (ბრჭყალების გარეშე შიგნით)
params = {
    'INPUT': fn, 
    'CLOSE_PATH': True, 
    'ORDER_EXPRESSION': '', # თუ არ გჭირდება, დატოვე ცარიელი
    'NATURAL_SORT': False, 
    'GROUP_EXPRESSION': '', 
    'OUTPUT': output 
}

# გაშვებამდე შევამოწმოთ, ხომ არ არის ფაილი უკვე გახსნილი/დაბლოკილი
try:
    res = processing.run("native:pointstopath", params)
    # თუ ყველაფერმა კარგად ჩაიარა, მხოლოდ მაშინ შემოვიტანოთ ეკრანზე
    if res and 'OUTPUT' in res:
        iface.addVectorLayer(res['OUTPUT'], 'Lake Line Layer', 'ogr')
except Exception as e:
    print(f"შეცდომა ხელსაწყოს გაშვებისას: {e}")

💡 პატარა რჩევა დეველოპმენტისთვის: თუ კოდს ტესტავ, OUTPUT-ად ფაილის მისამართის ნაცვლად ჩაწერე 'TEMPORARY_OUTPUT'. ამ დროს ყველაფერი ოპერატიულ მეხსიერებაში გაკეთდება, არაფერი დაიბლოკება და QGIS-ის დაკრაშვის შანსიც მინიმუმამდე დაიყვანება.


📌 შეჯამება — შეცდომების სქემა

შეცდომა მიიღე?
      ├── EOL / SyntaxError    → ბრჭყალი ან ' აკლია
      ├── NameError            → typo სახელში? ['Field'] ბრჭყალები?
      ├── AttributeError       → QVariant.Int (დიდი I)?
      ├── IndexError           → mapLayersByName() სახელი სწორია?
      ├── KeyError             → სვეტი ცხრილში არსებობს? სახელი ≤10 სიმბოლო?
      ├── TypeError            → feat['სვეტი'] სტრიქონია? int() გარდაქმენი
      └── AssertionError       → Edit Mode გათიშული? isEditable() შეამოწმე

👉 პირველი ნაბიჯი ყოველთვის: შეცდომის ბოლო სტრიქონი წაიკითხე — იქ არის მიზეზი.