[{"data":1,"prerenderedAt":1212},["ShallowReactive",2],{"doc:\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fexplore-pyqgis-api-with-dir-and-help":3},{"id":4,"title":5,"body":6,"description":1201,"extension":1202,"meta":1203,"navigation":235,"path":1208,"seo":1209,"stem":1210,"__hash__":1211},"docs\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fexplore-pyqgis-api-with-dir-and-help\u002Findex.md","Explore the PyQGIS API with dir() and help()",{"type":7,"value":8,"toc":1188},"minimark",[9,13,17,26,174,179,201,205,328,359,363,387,406,413,437,452,456,459,539,569,658,662,669,740,761,765,768,777,804,882,898,902,981,992,996,1060,1064,1078,1082,1091,1097,1110,1120,1126,1143,1153,1157,1184],[10,11,5],"h1",{"id":12},"explore-the-pyqgis-api-with-dir-and-help",[14,15,16],"p",{},"The PyQGIS API is enormous, the documentation is generated from C++, and the method you need is frequently one word away from the one you guessed. Introspection closes that gap faster than searching: the object in front of you knows exactly what it can do, and three lines in the console will tell you.",[14,18,19,20,25],{},"This recipe belongs to ",[21,22,24],"a",{"href":23},"\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002F","QGIS API Architecture",". It covers listing an object's methods, filtering the inherited Qt noise, reading the signature and docstring of a method, checking which class you actually have, and translating what you find into the online documentation.",[14,27,28],{},[29,30,35,39,43,50,67,76,85,91,97,103,107,111,116,120,124,129,132,139,144,149,153,158,162,166,170],"svg",{"viewBox":31,"role":32,"ariaLabel":33,"xmlns":34},"0 0 760 268","img","Diagram of a QGIS class inheritance chain showing how a vector layer inherits from map layer and from the Qt object base, with the proportion of methods contributed by each level","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[36,37,38],"title",{},"Why dir() returns three hundred names",[40,41,42],"desc",{},"A vector layer object inherits from the QGIS map layer class, which inherits from the Qt object base class. Each level contributes methods. Most of what dir returns comes from the lower levels and from Python's own attributes, while the methods specific to vector layers are a comparatively small set at the top of the chain.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","760","268","#f6f3ea",[51,52,53],"defs",{},[54,55,62],"marker",{"id":56,"viewBox":57,"refX":58,"refY":59,"markerWidth":60,"markerHeight":60,"orient":61},"dirArrow","0 0 10 10","8","5","7","auto-start-reverse",[63,64],"path",{"d":65,"fill":66},"M0 0 L10 5 L0 10 z","#59645f",[68,69,75],"text",{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","Most of what you see is inherited, not what you are looking for",[44,77],{"x":78,"y":79,"width":80,"height":81,"rx":58,"fill":82,"stroke":83,"style":84},"60","50","300","52","#eef7f4","#0f766e","stroke-width:2.5",[68,86,90],{"x":87,"y":88,"style":89,"fill":83,"textAnchor":74},"210","72","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","QgsVectorLayer",[68,92,96],{"x":87,"y":93,"style":94,"fill":95,"textAnchor":74},"92","text-anchor:middle;font-size:11px;font-family:sans-serif","#2f3b35","getFeatures, fields, startEditing",[44,98],{"x":78,"y":99,"width":80,"height":81,"rx":58,"fill":100,"stroke":101,"style":102},"116","#eff3ff","#2563eb","stroke-width:2",[68,104,106],{"x":87,"y":105,"style":89,"fill":101,"textAnchor":74},"138","QgsMapLayer",[68,108,110],{"x":87,"y":109,"style":94,"fill":95,"textAnchor":74},"158","name, id, crs, extent, isValid",[44,112],{"x":78,"y":113,"width":80,"height":81,"rx":58,"fill":114,"stroke":115,"style":102},"182","#fdf2e2","#b45309",[68,117,119],{"x":87,"y":118,"style":89,"fill":115,"textAnchor":74},"204","QObject and Python",[68,121,123],{"x":87,"y":122,"style":94,"fill":95,"textAnchor":74},"224","signals, properties, dunder names",[125,126],"line",{"x1":87,"y1":99,"x2":87,"y2":127,"stroke":66,"style":128},"106","stroke-width:2;marker-end:url(#dirArrow)",[125,130],{"x1":87,"y1":113,"x2":87,"y2":131,"stroke":66,"style":128},"172",[44,133],{"x":134,"y":79,"width":135,"height":136,"rx":137,"fill":138,"stroke":66,"style":102},"420","320","184","10","#fffdf7",[68,140,143],{"x":141,"y":142,"style":89,"fill":73,"textAnchor":74},"580","76","what dir() gives you",[44,145],{"x":146,"y":93,"width":147,"height":148,"rx":59,"fill":82,"stroke":83,"style":102},"444","272","30",[68,150,152],{"x":141,"y":151,"style":94,"fill":95,"textAnchor":74},"112","the ones you want — a few dozen",[44,154],{"x":146,"y":155,"width":147,"height":156,"rx":59,"fill":100,"stroke":101,"style":157},"128","42","stroke-width:1.5",[68,159,161],{"x":141,"y":160,"style":94,"fill":95,"textAnchor":74},"154","inherited layer methods — useful too",[44,163],{"x":146,"y":164,"width":147,"height":165,"rx":59,"fill":49,"stroke":115,"style":157},"176","46",[68,167,169],{"x":141,"y":168,"style":94,"fill":95,"textAnchor":74},"196","Qt plumbing and dunder names",[68,171,173],{"x":141,"y":172,"style":94,"fill":66,"textAnchor":74},"214","filter these out first",[175,176,178],"h2",{"id":177},"prerequisites","Prerequisites",[180,181,182,190,198],"ul",{},[183,184,185,189],"li",{},[186,187,188],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[183,191,192,193,197],{},"The Python console open — see ",[21,194,196],{"href":195},"\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-python-console-basics\u002F","QGIS Python Console Basics",".",[183,199,200],{},"A loaded layer to experiment on, though any object will do.",[175,202,204],{"id":203},"list-what-an-object-can-do","List what an object can do",[206,207,212],"pre",{"className":208,"code":209,"language":210,"meta":211,"style":211},"language-python shiki shiki-themes github-dark","layer = iface.activeLayer()\n\nmethods = [name for name in dir(layer) if not name.startswith(\"_\")]\nprint(len(methods))\n\nprint([name for name in methods if \"field\" in name.lower()])\n","python","",[213,214,215,230,237,280,295,300],"code",{"__ignoreMap":211},[216,217,219,223,227],"span",{"class":125,"line":218},1,[216,220,222],{"class":221},"s95oV","layer ",[216,224,226],{"class":225},"snl16","=",[216,228,229],{"class":221}," iface.activeLayer()\n",[216,231,233],{"class":125,"line":232},2,[216,234,236],{"emptyLinePlaceholder":235},true,"\n",[216,238,240,243,245,248,251,254,257,261,264,267,270,273,277],{"class":125,"line":239},3,[216,241,242],{"class":221},"methods ",[216,244,226],{"class":225},[216,246,247],{"class":221}," [name ",[216,249,250],{"class":225},"for",[216,252,253],{"class":221}," name ",[216,255,256],{"class":225},"in",[216,258,260],{"class":259},"sDLfK"," dir",[216,262,263],{"class":221},"(layer) ",[216,265,266],{"class":225},"if",[216,268,269],{"class":225}," not",[216,271,272],{"class":221}," name.startswith(",[216,274,276],{"class":275},"sU2Wk","\"_\"",[216,278,279],{"class":221},")]\n",[216,281,283,286,289,292],{"class":125,"line":282},4,[216,284,285],{"class":259},"print",[216,287,288],{"class":221},"(",[216,290,291],{"class":259},"len",[216,293,294],{"class":221},"(methods))\n",[216,296,298],{"class":125,"line":297},5,[216,299,236],{"emptyLinePlaceholder":235},[216,301,303,305,308,310,312,314,317,319,322,325],{"class":125,"line":302},6,[216,304,285],{"class":259},[216,306,307],{"class":221},"([name ",[216,309,250],{"class":225},[216,311,253],{"class":221},[216,313,256],{"class":225},[216,315,316],{"class":221}," methods ",[216,318,266],{"class":225},[216,320,321],{"class":275}," \"field\"",[216,323,324],{"class":225}," in",[216,326,327],{"class":221}," name.lower()])\n",[14,329,330,333,334,337,338,340,341,344,345,340,348,340,351,354,355,358],{},[186,331,332],{},"Breakdown:"," ",[213,335,336],{},"dir()"," returns every attribute name the object exposes, including everything inherited from ",[213,339,106],{},", ",[213,342,343],{},"QObject"," and Python itself — several hundred names, most of which are not what you want. Dropping names beginning with an underscore removes Python's internals immediately. The substring filter is the part that does the real work: you rarely know the exact method name, but you almost always know a word that will be in it. Searching for ",[213,346,347],{},"field",[213,349,350],{},"crs",[213,352,353],{},"select"," or ",[213,356,357],{},"commit"," narrows three hundred names to five in one line, and the answer is usually obvious from the list.",[175,360,362],{"id":361},"read-the-signature-and-the-documentation","Read the signature and the documentation",[206,364,366],{"className":208,"code":365,"language":210,"meta":211,"style":211},"help(layer.getFeatures)\n\nhelp(QgsVectorLayer.setSubsetString)\n",[213,367,368,376,380],{"__ignoreMap":211},[216,369,370,373],{"class":125,"line":218},[216,371,372],{"class":259},"help",[216,374,375],{"class":221},"(layer.getFeatures)\n",[216,377,378],{"class":125,"line":232},[216,379,236],{"emptyLinePlaceholder":235},[216,381,382,384],{"class":125,"line":239},[216,383,372],{"class":259},[216,385,386],{"class":221},"(QgsVectorLayer.setSubsetString)\n",[14,388,389,333,391,394,395,398,399,402,403,405],{},[186,390,332],{},[213,392,393],{},"help()"," on a bound method prints the signature and whatever docstring the bindings carry, which for PyQGIS is generated from the C++ header and includes the parameter and return types. Those types are the most valuable part: seeing that ",[213,396,397],{},"getFeatures()"," accepts a ",[213,400,401],{},"QgsFeatureRequest"," tells you where to look next far more directly than any tutorial. Calling ",[213,404,393],{}," on the class rather than an instance works identically and is handy when you have no object to hand. Where a method is overloaded — common in Qt-derived classes — you get every signature listed, which explains why a call that \"should\" work fails: you matched a different overload than you thought.",[14,407,408,409,412],{},"For a compact view in the console, ",[213,410,411],{},"signature"," from the standard library is often easier to read:",[206,414,416],{"className":208,"code":415,"language":210,"meta":211,"style":211},"import inspect\n\nprint(inspect.signature(QgsVectorLayer.setSubsetString))\n",[213,417,418,426,430],{"__ignoreMap":211},[216,419,420,423],{"class":125,"line":218},[216,421,422],{"class":225},"import",[216,424,425],{"class":221}," inspect\n",[216,427,428],{"class":125,"line":232},[216,429,236],{"emptyLinePlaceholder":235},[216,431,432,434],{"class":125,"line":239},[216,433,285],{"class":259},[216,435,436],{"class":221},"(inspect.signature(QgsVectorLayer.setSubsetString))\n",[14,438,439,333,441,444,445,448,449,451],{},[186,440,332],{},[213,442,443],{},"inspect.signature()"," gives one line rather than a page. It works for most PyQGIS bindings, and raises ",[213,446,447],{},"ValueError"," for the few built entirely in C++ without introspection metadata — in which case fall back to ",[213,450,393],{},", which always has something to show.",[175,453,455],{"id":454},"find-out-what-you-are-actually-holding","Find out what you are actually holding",[14,457,458],{},"Half of all PyQGIS confusion is having a different class than you assumed.",[206,460,462],{"className":208,"code":461,"language":210,"meta":211,"style":211},"print(type(layer))\nprint(type(layer).__mro__)\nprint(layer.__class__.__name__)\n\nfrom qgis.core import QgsVectorLayer\nprint(isinstance(layer, QgsVectorLayer))\n",[213,463,464,476,493,510,514,527],{"__ignoreMap":211},[216,465,466,468,470,473],{"class":125,"line":218},[216,467,285],{"class":259},[216,469,288],{"class":221},[216,471,472],{"class":259},"type",[216,474,475],{"class":221},"(layer))\n",[216,477,478,480,482,484,487,490],{"class":125,"line":232},[216,479,285],{"class":259},[216,481,288],{"class":221},[216,483,472],{"class":259},[216,485,486],{"class":221},"(layer).",[216,488,489],{"class":259},"__mro__",[216,491,492],{"class":221},")\n",[216,494,495,497,500,503,505,508],{"class":125,"line":239},[216,496,285],{"class":259},[216,498,499],{"class":221},"(layer.",[216,501,502],{"class":259},"__class__",[216,504,197],{"class":221},[216,506,507],{"class":259},"__name__",[216,509,492],{"class":221},[216,511,512],{"class":125,"line":282},[216,513,236],{"emptyLinePlaceholder":235},[216,515,516,519,522,524],{"class":125,"line":297},[216,517,518],{"class":225},"from",[216,520,521],{"class":221}," qgis.core ",[216,523,422],{"class":225},[216,525,526],{"class":221}," QgsVectorLayer\n",[216,528,529,531,533,536],{"class":125,"line":302},[216,530,285],{"class":259},[216,532,288],{"class":221},[216,534,535],{"class":259},"isinstance",[216,537,538],{"class":221},"(layer, QgsVectorLayer))\n",[14,540,541,333,543,546,547,549,550,552,553,556,557,560,561,564,565,568],{},[186,542,332],{},[213,544,545],{},"type()"," names the exact class, and the method resolution order shows the whole inheritance chain — which is how you discover that a ",[213,548,90],{}," is a ",[213,551,106],{}," and therefore has everything documented on that page too. ",[213,554,555],{},"isinstance()"," is the right check in real code, because it accepts subclasses; comparing ",[213,558,559],{},"type(layer) == QgsVectorLayer"," fails for anything derived. This is also the fastest way to diagnose the classic \"AttributeError on a valid layer\" — the object is a ",[213,562,563],{},"QgsRasterLayer",", or ",[213,566,567],{},"None",", and the missing method was never going to be there.",[14,570,571],{},[29,572,575,578,581,584,587,593,599,603,607,611,615,617,621,624,628,630,633,636,640,644,647,649,653,655],{"viewBox":573,"role":32,"ariaLabel":574,"xmlns":34},"0 0 760 248","Decision guide matching an introspection question to the right tool, covering what can this do, how is it called, what class is it, and what does the enumeration mean",[36,576,577],{},"Four questions, four one-liners",[40,579,580],{},"To ask what an object can do, use dir with a substring filter. To ask how a method is called, use help or inspect signature. To ask what class an object is, use type and the method resolution order. To ask what an enumeration value means, print the enumeration members from the class. Each row pairs the question with the exact call.",[44,582],{"x":46,"y":46,"width":47,"height":583,"fill":49},"248",[68,585,586],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"Match the question to the call",[44,588],{"x":589,"y":165,"width":590,"height":148,"rx":591,"fill":592,"stroke":66,"style":157},"16","330","6","#efeadd",[68,594,598],{"x":595,"y":596,"style":597,"fill":73,"textAnchor":74},"181","66","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","what you are asking",[44,600],{"x":601,"y":165,"width":602,"height":148,"rx":591,"fill":592,"stroke":66,"style":157},"354","390",[68,604,606],{"x":605,"y":596,"style":597,"fill":73,"textAnchor":74},"549","what to type",[44,608],{"x":589,"y":609,"width":590,"height":610,"rx":591,"fill":138,"stroke":66,"style":157},"82","38",[68,612,614],{"x":148,"y":127,"style":613,"fill":95},"font-size:11px;font-family:sans-serif","what can this object do?",[44,616],{"x":601,"y":609,"width":602,"height":610,"rx":591,"fill":82,"stroke":83,"style":157},[68,618,620],{"x":619,"y":127,"style":613,"fill":95},"368","dir(obj) with a substring filter",[44,622],{"x":589,"y":623,"width":590,"height":610,"rx":591,"fill":138,"stroke":66,"style":157},"126",[68,625,627],{"x":148,"y":626,"style":613,"fill":95},"150","how is this method called?",[44,629],{"x":601,"y":623,"width":602,"height":610,"rx":591,"fill":100,"stroke":101,"style":157},[68,631,632],{"x":619,"y":626,"style":613,"fill":95},"help(obj.method) or inspect.signature",[44,634],{"x":589,"y":635,"width":590,"height":610,"rx":591,"fill":138,"stroke":66,"style":157},"170",[68,637,639],{"x":148,"y":638,"style":613,"fill":95},"194","what class is this really?",[44,641],{"x":601,"y":635,"width":602,"height":610,"rx":591,"fill":642,"stroke":643,"style":157},"#edf8e9","#15803d",[68,645,646],{"x":619,"y":638,"style":613,"fill":95},"type(obj) and type(obj).mro",[44,648],{"x":589,"y":172,"width":590,"height":148,"rx":591,"fill":138,"stroke":66,"style":157},[68,650,652],{"x":148,"y":651,"style":613,"fill":95},"234","what does this number mean?",[44,654],{"x":601,"y":172,"width":602,"height":148,"rx":591,"fill":114,"stroke":115,"style":157},[68,656,657],{"x":619,"y":651,"style":613,"fill":95},"list the enum members on the class",[175,659,661],{"id":660},"decode-enumerations-and-constants","Decode enumerations and constants",[14,663,664,665,668],{},"Many PyQGIS calls take or return integer-backed enumeration values, and a bare ",[213,666,667],{},"2"," in the console tells you nothing.",[206,670,672],{"className":208,"code":671,"language":210,"meta":211,"style":211},"from qgis.core import QgsWkbTypes, Qgis\n\nprint(QgsWkbTypes.displayString(layer.wkbType()))\n\nprint([name for name in dir(Qgis.GeometryType) if not name.startswith(\"_\")])\nprint(int(Qgis.GeometryType.Polygon), Qgis.GeometryType.Polygon.name)\n",[213,673,674,685,689,696,700,728],{"__ignoreMap":211},[216,675,676,678,680,682],{"class":125,"line":218},[216,677,518],{"class":225},[216,679,521],{"class":221},[216,681,422],{"class":225},[216,683,684],{"class":221}," QgsWkbTypes, Qgis\n",[216,686,687],{"class":125,"line":232},[216,688,236],{"emptyLinePlaceholder":235},[216,690,691,693],{"class":125,"line":239},[216,692,285],{"class":259},[216,694,695],{"class":221},"(QgsWkbTypes.displayString(layer.wkbType()))\n",[216,697,698],{"class":125,"line":282},[216,699,236],{"emptyLinePlaceholder":235},[216,701,702,704,706,708,710,712,714,717,719,721,723,725],{"class":125,"line":297},[216,703,285],{"class":259},[216,705,307],{"class":221},[216,707,250],{"class":225},[216,709,253],{"class":221},[216,711,256],{"class":225},[216,713,260],{"class":259},[216,715,716],{"class":221},"(Qgis.GeometryType) ",[216,718,266],{"class":225},[216,720,269],{"class":225},[216,722,272],{"class":221},[216,724,276],{"class":275},[216,726,727],{"class":221},")])\n",[216,729,730,732,734,737],{"class":125,"line":302},[216,731,285],{"class":259},[216,733,288],{"class":221},[216,735,736],{"class":259},"int",[216,738,739],{"class":221},"(Qgis.GeometryType.Polygon), Qgis.GeometryType.Polygon.name)\n",[14,741,742,744,745,748,749,752,753,756,757,760],{},[186,743,332],{}," Several QGIS enumerations ship a helper that turns a value into readable text — ",[213,746,747],{},"QgsWkbTypes.displayString()"," is the one you will use most, turning an opaque geometry type code into ",[213,750,751],{},"MultiPolygon",". For the newer scoped enumerations under ",[213,754,755],{},"Qgis",", listing the members shows every legal value, and each member has a ",[213,758,759],{},"name",", which makes log messages readable. Printing the integer alongside is occasionally necessary when comparing against a value read from a file or a database column.",[175,762,764],{"id":763},"map-what-you-found-onto-the-documentation","Map what you found onto the documentation",[14,766,767],{},"Introspection tells you a method exists; the API documentation tells you what it means. Two habits connect them.",[14,769,770,773,774,776],{},[186,771,772],{},"Search the class, not the method."," The QGIS API documentation is organised by class, and the class name from ",[213,775,545],{}," takes you straight to the page listing every method with its full C++ signature and, usually, a paragraph of explanation. Inherited members are on a separate tab, which is why the method resolution order is worth knowing.",[14,778,779,333,782,785,786,340,789,792,793,796,797,800,801,803],{},[186,780,781],{},"Read the C++ types as Python ones.",[213,783,784],{},"QString"," is ",[213,787,788],{},"str",[213,790,791],{},"QList\u003CQgsFeature>"," is a Python list of features, a ",[213,794,795],{},"bool *ok"," output parameter usually becomes an extra value in a returned tuple, and a method documented as returning ",[213,798,799],{},"void"," returns ",[213,802,567],{},". Once that translation is automatic, the C++ documentation reads as Python documentation.",[14,805,806],{},[29,807,810,813,816,819,822,825,829,832,836,840,844,846,849,852,856,858,861,863,867,869,872,874,877,879],{"viewBox":808,"role":32,"ariaLabel":809,"xmlns":34},"0 0 760 252","Table translating common C plus plus types in the QGIS documentation into what they become in Python",[36,811,812],{},"Reading C++ signatures as Python",[40,814,815],{},"A QString becomes a Python string. A list of features becomes a Python list. An output boolean pointer usually becomes an extra value in a returned tuple. A void return becomes None. A const reference is simply a value. Learning these five equivalences makes the generated documentation readable without translation.",[44,817],{"x":46,"y":46,"width":47,"height":818,"fill":49},"252",[68,820,821],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"Five equivalences and the documentation reads as Python",[44,823],{"x":589,"y":165,"width":824,"height":148,"rx":591,"fill":592,"stroke":66,"style":157},"352",[68,826,828],{"x":827,"y":596,"style":597,"fill":73,"textAnchor":74},"192","what the documentation says",[44,830],{"x":831,"y":165,"width":619,"height":148,"rx":591,"fill":592,"stroke":66,"style":157},"376",[68,833,835],{"x":834,"y":596,"style":597,"fill":73,"textAnchor":74},"560","what you write",[44,837],{"x":589,"y":609,"width":824,"height":838,"rx":591,"fill":138,"stroke":66,"style":839},"32","stroke-width:1.2",[68,841,843],{"x":148,"y":842,"style":613,"fill":95},"103","QString name",[44,845],{"x":831,"y":609,"width":619,"height":838,"rx":591,"fill":82,"stroke":83,"style":157},[68,847,848],{"x":602,"y":842,"style":613,"fill":95},"an ordinary str",[44,850],{"x":589,"y":851,"width":824,"height":838,"rx":591,"fill":138,"stroke":66,"style":839},"120",[68,853,855],{"x":148,"y":854,"style":613,"fill":95},"141","QList of QgsFeature",[44,857],{"x":831,"y":851,"width":619,"height":838,"rx":591,"fill":82,"stroke":83,"style":157},[68,859,860],{"x":602,"y":854,"style":613,"fill":95},"a Python list of features",[44,862],{"x":589,"y":109,"width":824,"height":838,"rx":591,"fill":138,"stroke":66,"style":839},[68,864,866],{"x":148,"y":865,"style":613,"fill":95},"179","bool ok output parameter",[44,868],{"x":831,"y":109,"width":619,"height":838,"rx":591,"fill":114,"stroke":115,"style":157},[68,870,871],{"x":602,"y":865,"style":613,"fill":95},"an extra value in the returned tuple",[44,873],{"x":589,"y":168,"width":824,"height":838,"rx":591,"fill":138,"stroke":66,"style":839},[68,875,799],{"x":148,"y":876,"style":613,"fill":95},"217",[44,878],{"x":831,"y":168,"width":619,"height":838,"rx":591,"fill":82,"stroke":83,"style":157},[68,880,881],{"x":602,"y":876,"style":613,"fill":95},"returns None",[14,883,884,885,889,890,892,893,897],{},"The one place introspection cannot help is ",[886,887,888],"em",{},"behaviour",": whether a method commits immediately, whether it invalidates an iterator, whether it is safe on a background thread. That is what the documentation and the wider guides here are for — ",[21,891,24],{"href":23}," covers how the modules fit together, and ",[21,894,896],{"href":895},"\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fqgis-python-version-compatibility-guide\u002F","QGIS Python Version Compatibility Guide"," covers what changed between releases.",[175,899,901],{"id":900},"qgis-version-compatibility","QGIS version compatibility",[903,904,905,921],"table",{},[906,907,908],"thead",{},[909,910,911,915,918],"tr",{},[912,913,914],"th",{},"QGIS version",[912,916,917],{},"Python",[912,919,920],{},"Notes",[922,923,924,947,957,968],"tbody",{},[909,925,926,930,933],{},[927,928,929],"td",{},"3.22 LTR",[927,931,932],{},"3.9",[927,934,935,340,937,939,940,943,944,946],{},[213,936,336],{},[213,938,393],{}," and ",[213,941,942],{},"inspect"," behave identically; some scoped enumerations under ",[213,945,755],{}," do not yet exist.",[909,948,949,952,954],{},[927,950,951],{},"3.28 LTR",[927,953,932],{},[927,955,956],{},"Identical.",[909,958,959,962,965],{},[927,960,961],{},"3.34 LTR",[927,963,964],{},"3.12",[927,966,967],{},"Baseline for this page; most enumerations available in both the legacy and scoped forms.",[909,969,970,973,975],{},[927,971,972],{},"3.40 \u002F 3.44",[927,974,964],{},[927,976,977,978,980],{},"Legacy enumeration aliases are being removed release by release — check with ",[213,979,336],{}," rather than assuming an old name survives.",[14,982,983,984,987,988,991],{},"Introspection is also the fastest way to ",[886,985,986],{},"handle"," a version difference: ",[213,989,990],{},"hasattr(layer, \"someNewMethod\")"," is a one-line compatibility check that keeps a plugin working across releases.",[175,993,995],{"id":994},"troubleshooting","Troubleshooting",[180,997,998,1006,1014,1026,1039,1051],{},[183,999,1000,1005],{},[186,1001,1002,1004],{},[213,1003,336],{}," returns hundreds of names."," Filter by substring; almost nobody reads the full list.",[183,1007,1008,1013],{},[186,1009,1010,1012],{},[213,1011,393],{}," shows only the signature."," The binding carries no docstring for that method. The class page in the API documentation will have the prose.",[183,1015,1016,1023,1024,197],{},[186,1017,1018,1020,1021,197],{},[213,1019,443],{}," raises ",[213,1022,447],{}," A pure C++ binding without introspection metadata. Use ",[213,1025,393],{},[183,1027,1028,1035,1036,1038],{},[186,1029,1030,1031,1034],{},"A method exists but raises ",[213,1032,1033],{},"TypeError"," when called."," You matched a different overload. ",[213,1037,393],{}," lists them all; check the argument types.",[183,1040,1041,1044,1045,1047,1048,1050],{},[186,1042,1043],{},"An attribute is missing on an object that should have it."," Check ",[213,1046,545],{}," — it is very often ",[213,1049,567],{},", a raster layer, or a layer tree node rather than the layer itself.",[183,1052,1053,1056,1057,1059],{},[186,1054,1055],{},"A name from a tutorial does not exist."," It is QGIS 2 code, or a renamed method. Search ",[213,1058,336],{}," for a distinctive word from the old name.",[175,1061,1063],{"id":1062},"conclusion","Conclusion",[14,1065,1066,1067,1069,1070,354,1072,1074,1075,1077],{},"Three calls cover most exploration: ",[213,1068,336],{}," with a substring filter to find candidate methods, ",[213,1071,393],{},[213,1073,443],{}," to learn how to call one, and ",[213,1076,545],{}," with the method resolution order to confirm what you are holding. Decode enumerations with their display helpers, and use the class name to jump into the API documentation for the behaviour introspection cannot show you.",[175,1079,1081],{"id":1080},"frequently-asked-questions","Frequently Asked Questions",[14,1083,1084,1087,1088,1090],{},[186,1085,1086],{},"Is the console's autocomplete the same thing?","\nIt is ",[213,1089,336],{}," with a nicer interface, and it is often quicker. Introspection in code still matters for compatibility checks and for exploring objects you cannot easily type a name for.",[14,1092,1093,1096],{},[186,1094,1095],{},"Why do method names look like Qt rather than Python?","\nPyQGIS wraps a C++ API, so it keeps camel-case names and Qt conventions. It is not idiomatic Python and trying to guess snake-case equivalents will not work.",[14,1098,1099,1102,1103,1105,1106,197],{},[186,1100,1101],{},"How do I list the signals an object emits?","\nFilter ",[213,1104,336],{}," for names that are not callable methods, or check the class page in the documentation — signals are listed separately there. Connecting to one is covered in ",[21,1107,1109],{"href":1108},"\u002Fqgis-plugin-development\u002Fcustom-map-tools-and-canvas-interaction\u002Fconnect-layer-signals-pyqgis\u002F","Connect Layer Signals in PyQGIS",[14,1111,1112,1115,1116,197],{},[186,1113,1114],{},"Can I introspect Processing algorithms this way?","\nTheir parameters are described by their own metadata rather than by Python attributes. Use the Processing tools described in ",[21,1117,1119],{"href":1118},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002Frun-processing-algorithm-from-script\u002F","Run a Processing Algorithm from a Script",[14,1121,1122,1125],{},[186,1123,1124],{},"Does this work in a standalone script?","\nYes, identically — introspection needs nothing but the objects, so it works in a headless run as well as in the console.",[14,1127,1128,1131,1132,1135,1136,939,1139,1142],{},[186,1129,1130],{},"Is there a faster way to find a class I only half remember the name of?","\nFilter the module rather than an object: ",[213,1133,1134],{},"[n for n in dir(qgis.core) if \"renderer\" in n.lower()]"," lists every core class with that word in its name, which usually surfaces the one you meant in a single line. The same trick on ",[213,1137,1138],{},"qgis.gui",[213,1140,1141],{},"qgis.analysis"," covers the rest of the API, and it is considerably quicker than searching documentation for a name you cannot spell.",[14,1144,1145,1148,1149,1152],{},[186,1146,1147],{},"Can I see the source of a PyQGIS method?","\nRarely — most of it is compiled C++ with no Python source to show, so ",[213,1150,1151],{},"inspect.getsource()"," raises. Pure-Python parts of QGIS, such as the Processing framework and the plugin installer, do return their source, which makes them worth reading when you want to see how the framework itself calls the API.",[175,1154,1156],{"id":1155},"related","Related",[180,1158,1159,1164,1170,1174,1178],{},[183,1160,1161,1163],{},[21,1162,24],{"href":23}," — the guide this recipe belongs to",[183,1165,1166],{},[21,1167,1169],{"href":1168},"\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fqgis-core-gui-analysis-modules-explained\u002F","QGIS Core, GUI and Analysis Modules Explained",[183,1171,1172],{},[21,1173,896],{"href":895},[183,1175,1176],{},[21,1177,196],{"href":195},[183,1179,1180],{},[21,1181,1183],{"href":1182},"\u002Fpyqgis-fundamentals-environment-setup\u002Fdebugging-pyqgis-scripts\u002F","Debugging PyQGIS Scripts",[1185,1186,1187],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":211,"searchDepth":232,"depth":232,"links":1189},[1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200],{"id":177,"depth":232,"text":178},{"id":203,"depth":232,"text":204},{"id":361,"depth":232,"text":362},{"id":454,"depth":232,"text":455},{"id":660,"depth":232,"text":661},{"id":763,"depth":232,"text":764},{"id":900,"depth":232,"text":901},{"id":994,"depth":232,"text":995},{"id":1062,"depth":232,"text":1063},{"id":1080,"depth":232,"text":1081},{"id":1155,"depth":232,"text":1156},"Find the method you need without leaving QGIS — introspect objects with dir() and help(), filter the noise from Qt inheritance, read C++ signatures in Python, and map what you find onto the API documentation.","md",{"slug":1204,"type":1205,"breadcrumb":1206,"datePublished":1207,"dateModified":1207},"explore-pyqgis-api-with-dir-and-help","article","Explore the API","2026-08-15","\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fexplore-pyqgis-api-with-dir-and-help",{"title":5,"description":1201},"pyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fexplore-pyqgis-api-with-dir-and-help\u002Findex","vjW5g1CSXiOFlK10BhdKK9D3IV327xJvykSsxWCQLDs",1786789584627]