[{"data":1,"prerenderedAt":1938},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Flist-and-load-geopackage-sublayers-pyqgis":3},{"id":4,"title":5,"body":6,"description":1927,"extension":1928,"meta":1929,"navigation":271,"path":1934,"seo":1935,"stem":1936,"__hash__":1937},"docs\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Flist-and-load-geopackage-sublayers-pyqgis\u002Findex.md","List and Load GeoPackage Sublayers in PyQGIS",{"type":7,"value":8,"toc":1914},"minimark",[9,13,27,36,190,195,217,221,239,429,454,461,561,565,568,632,637,641,647,911,942,1052,1056,1069,1228,1254,1258,1261,1718,1731,1735,1772,1776,1822,1826,1832,1836,1845,1857,1867,1876,1880,1910],[10,11,5],"h1",{"id":12},"list-and-load-geopackage-sublayers-in-pyqgis",[14,15,16,17,21,22,26],"p",{},"A shapefile is one layer. A GeoPackage, an Esri File Geodatabase, a KML with folders, a multi-sheet spreadsheet or a NetCDF with several variables is a ",[18,19,20],"em",{},"container",", and opening the file only tells QGIS where to look — not which of the forty things inside it you want. Hard-coding ",[23,24,25],"code",{},"|layername=roads"," works until the data supplier renames the table; iterating what is actually there works every time.",[14,28,29,30,35],{},"This recipe belongs to ",[31,32,34],"a",{"href":33},"\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002F","Layer Data Sources & Formats in PyQGIS",". It uses the provider registry's sublayer query to list a container's contents, loads them selectively, and deals with the containers that mix vector tables, rasters and non-spatial tables in one file.",[14,37,38],{},[39,40,45,49,53,60,77,86,95,101,111,116,119,123,128,132,137,141,146,150,155,163,169,175,178,182,186],"svg",{"viewBox":41,"role":42,"ariaLabel":43,"xmlns":44},"0 0 760 300","img","One GeoPackage file holding several kinds of content: two vector tables, a raster tile table, an attribute-only table and stored layer styles, each reported as a separate sublayer","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[46,47,48],"title",{},"What is inside one .gpkg",[50,51,52],"desc",{},"A single GeoPackage file is drawn as a container. Inside are roads as a line table, buildings as a polygon table, an orthophoto stored as raster tiles, an inspections table with no geometry, and the layer_styles table. querySublayers reports the first four as separate sublayers with their provider key, type and feature count; layer_styles is an internal table and is not offered as a layer.",[54,55],"rect",{"x":56,"y":56,"width":57,"height":58,"fill":59},"0","760","300","#f6f3ea",[61,62,63],"defs",{},[64,65,72],"marker",{"id":66,"viewBox":67,"refX":68,"refY":69,"markerWidth":70,"markerHeight":70,"orient":71},"gpkgSubArrow","0 0 10 10","8","5","7","auto-start-reverse",[73,74],"path",{"d":75,"fill":76},"M0 0 L10 5 L0 10 z","#2f3b35",[78,79,85],"text",{"x":80,"y":81,"style":82,"fill":83,"textAnchor":84},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","One file, many layers of different kinds",[54,87],{"x":88,"y":89,"width":58,"height":90,"rx":91,"fill":92,"stroke":93,"style":94},"24","48","230","12","#fffdf7","#59645f","stroke-width:2.5",[78,96,100],{"x":97,"y":98,"style":99,"fill":83,"textAnchor":84},"174","72","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","city_base.gpkg",[54,102],{"x":103,"y":104,"width":105,"height":106,"rx":107,"fill":108,"stroke":109,"style":110},"44","86","260","30","6","#eef7f4","#0f766e","stroke-width:1.5",[78,112,115],{"x":97,"y":113,"style":114,"fill":76,"textAnchor":84},"106","text-anchor:middle;font-size:10px;font-family:sans-serif","roads · LineString",[54,117],{"x":103,"y":118,"width":105,"height":106,"rx":107,"fill":108,"stroke":109,"style":110},"124",[78,120,122],{"x":97,"y":121,"style":114,"fill":76,"textAnchor":84},"144","buildings · Polygon",[54,124],{"x":103,"y":125,"width":105,"height":106,"rx":107,"fill":126,"stroke":127,"style":110},"162","#eff3ff","#2563eb",[78,129,131],{"x":97,"y":130,"style":114,"fill":76,"textAnchor":84},"182","ortho_2025 · raster tiles",[54,133],{"x":103,"y":134,"width":105,"height":106,"rx":107,"fill":135,"stroke":136,"style":110},"200","#fdf2e2","#b45309",[78,138,140],{"x":97,"y":139,"style":114,"fill":76,"textAnchor":84},"220","inspections · no geometry",[54,142],{"x":103,"y":143,"width":105,"height":106,"rx":107,"fill":144,"stroke":145,"style":110},"238","#e8e4d8","#9aa39d",[78,147,149],{"x":97,"y":148,"style":114,"fill":93,"textAnchor":84},"258","layer_styles · internal",[151,152],"line",{"x1":153,"y1":125,"x2":80,"y2":125,"stroke":76,"style":154},"324","stroke-width:2;marker-end:url(#gpkgSubArrow)",[54,156],{"x":157,"y":158,"width":159,"height":160,"rx":161,"fill":92,"stroke":162,"style":94},"388","64","348","196","10","#15803d",[78,164,168],{"x":165,"y":166,"style":99,"fill":167,"textAnchor":84},"562","90","#166534","querySublayers(path)",[78,170,174],{"x":171,"y":172,"style":173,"fill":76},"408","120","font-size:9.5px;font-family:monospace","ogr   vector  roads         2 140",[78,176,177],{"x":171,"y":121,"style":173,"fill":76},"ogr   vector  buildings    18 902",[78,179,181],{"x":171,"y":180,"style":173,"fill":76},"168","gdal  raster  ortho_2025",[78,183,185],{"x":171,"y":184,"style":173,"fill":76},"192","ogr   vector  inspections     611",[78,187,189],{"x":165,"y":188,"style":114,"fill":93,"textAnchor":84},"232","provider · type · name · feature count",[191,192,194],"h2",{"id":193},"prerequisites","Prerequisites",[196,197,198,214],"ul",{},[199,200,201,205,206,209,210,213],"li",{},[202,203,204],"strong",{},"QGIS 3.40 LTR"," or newer. ",[23,207,208],{},"querySublayers"," was added in 3.22; the older ",[23,211,212],{},"subLayers()"," approach is shown in the compatibility notes.",[199,215,216],{},"A container file — the examples use a GeoPackage, but File Geodatabases, KML\u002FKMZ, XLSX and NetCDF are queried the same way.",[191,218,220],{"id":219},"list-what-a-container-holds","List what a container holds",[14,222,223,226,227,230,231,234,235,238],{},[23,224,225],{},"QgsProviderRegistry.querySublayers"," asks every provider that can read the file to report what it finds, and returns one ",[23,228,229],{},"QgsProviderSublayerDetails"," per sublayer. A GeoPackage therefore comes back with vector tables from the ",[23,232,233],{},"ogr"," provider and raster tables from ",[23,236,237],{},"gdal"," in a single list.",[240,241,246],"pre",{"className":242,"code":243,"language":244,"meta":245,"style":245},"language-python shiki shiki-themes github-dark","from qgis.core import Qgis, QgsProviderRegistry, QgsWkbTypes\n\npath = \"\u002Fdata\u002Fdeliveries\u002Fcity_base.gpkg\"\nregistry = QgsProviderRegistry.instance()\n\ndetails = registry.querySublayers(path)\nfor d in details:\n    is_vector = d.type() == Qgis.LayerType.Vector\n    geom = QgsWkbTypes.displayString(d.wkbType()) if is_vector else \"raster\"\n    print(f\"{d.providerKey():\u003C6} {d.name():\u003C20} {geom:\u003C16} {d.featureCount()}\")\n","python","",[23,247,248,266,273,286,297,302,313,328,345,368],{"__ignoreMap":245},[249,250,252,256,260,263],"span",{"class":151,"line":251},1,[249,253,255],{"class":254},"snl16","from",[249,257,259],{"class":258},"s95oV"," qgis.core ",[249,261,262],{"class":254},"import",[249,264,265],{"class":258}," Qgis, QgsProviderRegistry, QgsWkbTypes\n",[249,267,269],{"class":151,"line":268},2,[249,270,272],{"emptyLinePlaceholder":271},true,"\n",[249,274,276,279,282],{"class":151,"line":275},3,[249,277,278],{"class":258},"path ",[249,280,281],{"class":254},"=",[249,283,285],{"class":284},"sU2Wk"," \"\u002Fdata\u002Fdeliveries\u002Fcity_base.gpkg\"\n",[249,287,289,292,294],{"class":151,"line":288},4,[249,290,291],{"class":258},"registry ",[249,293,281],{"class":254},[249,295,296],{"class":258}," QgsProviderRegistry.instance()\n",[249,298,300],{"class":151,"line":299},5,[249,301,272],{"emptyLinePlaceholder":271},[249,303,305,308,310],{"class":151,"line":304},6,[249,306,307],{"class":258},"details ",[249,309,281],{"class":254},[249,311,312],{"class":258}," registry.querySublayers(path)\n",[249,314,316,319,322,325],{"class":151,"line":315},7,[249,317,318],{"class":254},"for",[249,320,321],{"class":258}," d ",[249,323,324],{"class":254},"in",[249,326,327],{"class":258}," details:\n",[249,329,331,334,336,339,342],{"class":151,"line":330},8,[249,332,333],{"class":258},"    is_vector ",[249,335,281],{"class":254},[249,337,338],{"class":258}," d.type() ",[249,340,341],{"class":254},"==",[249,343,344],{"class":258}," Qgis.LayerType.Vector\n",[249,346,348,351,353,356,359,362,365],{"class":151,"line":347},9,[249,349,350],{"class":258},"    geom ",[249,352,281],{"class":254},[249,354,355],{"class":258}," QgsWkbTypes.displayString(d.wkbType()) ",[249,357,358],{"class":254},"if",[249,360,361],{"class":258}," is_vector ",[249,363,364],{"class":254},"else",[249,366,367],{"class":284}," \"raster\"\n",[249,369,371,375,378,381,384,387,390,393,396,399,402,405,407,409,412,415,417,419,422,424,426],{"class":151,"line":370},10,[249,372,374],{"class":373},"sDLfK","    print",[249,376,377],{"class":258},"(",[249,379,380],{"class":254},"f",[249,382,383],{"class":284},"\"",[249,385,386],{"class":373},"{",[249,388,389],{"class":258},"d.providerKey()",[249,391,392],{"class":254},":\u003C6",[249,394,395],{"class":373},"}",[249,397,398],{"class":373}," {",[249,400,401],{"class":258},"d.name()",[249,403,404],{"class":254},":\u003C20",[249,406,395],{"class":373},[249,408,398],{"class":373},[249,410,411],{"class":258},"geom",[249,413,414],{"class":254},":\u003C16",[249,416,395],{"class":373},[249,418,398],{"class":373},[249,420,421],{"class":258},"d.featureCount()",[249,423,395],{"class":373},[249,425,383],{"class":284},[249,427,428],{"class":258},")\n",[14,430,431,434,435,438,439,442,443,446,447,450,451,453],{},[202,432,433],{},"Breakdown:"," Each details object carries the provider key, the layer type, the table name, the geometry type for vector sublayers, and a feature count — plus the full ",[23,436,437],{},"uri()"," that opens that one sublayer, so you never assemble ",[23,440,441],{},"|layername="," strings yourself. Internal tables such as ",[23,444,445],{},"layer_styles",", ",[23,448,449],{},"gpkg_metadata"," and R-tree index tables are not reported, which is what you want. For a raster-only container like a multi-subdataset NetCDF, the list contains only ",[23,452,237],{}," entries, one per variable.",[14,455,456,457,460],{},"A feature count of ",[23,458,459],{},"-1"," means \"not counted\". Some formats report counts cheaply from metadata; others would have to read every row, and by default the query does not do that for them.",[14,462,463],{},[39,464,467,470,473,476,479,484,490,494,498,502,507,511,514,517,520,523,526,531,534,537,540,544,547,550,553,556,558],{"viewBox":465,"role":42,"ariaLabel":466,"xmlns":44},"0 0 760 270","Two query modes: a fast scan that only reads the container's table list and a full query that opens each table to count features and detect geometry types, trading speed for detail",[46,468,469],{},"Fast scan or full detail",[50,471,472],{},"The FastScan flag reads just the table list, returns within milliseconds even for a large geodatabase, and may report unknown geometry types and feature counts of minus one. The default query opens each table, which can take seconds on a File Geodatabase with hundreds of feature classes, but returns geometry types. The CountFeatures flag additionally forces exact counts.",[54,474],{"x":56,"y":56,"width":57,"height":475,"fill":59},"270",[78,477,478],{"x":80,"y":81,"style":82,"fill":83,"textAnchor":84},"Pay for detail only when you need it",[54,480],{"x":88,"y":481,"width":482,"height":160,"rx":161,"fill":483,"stroke":162,"style":94},"50","222","#e8efe6",[78,485,489],{"x":486,"y":487,"style":488,"fill":167,"textAnchor":84},"135","76","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","FastScan",[78,491,493],{"x":486,"y":113,"style":492,"fill":76,"textAnchor":84},"text-anchor:middle;font-size:10.5px;font-family:sans-serif","table names only",[78,495,497],{"x":486,"y":496,"style":492,"fill":76,"textAnchor":84},"130","type may be unknown",[78,499,501],{"x":486,"y":500,"style":492,"fill":76,"textAnchor":84},"154","count = −1",[54,503],{"x":504,"y":505,"width":125,"height":91,"rx":506,"fill":162},"54","186","3",[78,508,510],{"x":486,"y":509,"style":114,"fill":93,"textAnchor":84},"226","for pickers and menus",[54,512],{"x":513,"y":481,"width":482,"height":160,"rx":161,"fill":126,"stroke":127,"style":94},"269",[78,515,516],{"x":80,"y":487,"style":488,"fill":127,"textAnchor":84},"default",[78,518,519],{"x":80,"y":113,"style":492,"fill":76,"textAnchor":84},"opens each table",[78,521,522],{"x":80,"y":496,"style":492,"fill":76,"textAnchor":84},"geometry type known",[78,524,525],{"x":80,"y":500,"style":492,"fill":76,"textAnchor":84},"count if cheap",[54,527],{"x":528,"y":505,"width":125,"height":91,"rx":506,"fill":529,"stroke":127,"style":530},"299","#dbeafe","stroke-width:1",[54,532],{"x":528,"y":505,"width":533,"height":91,"rx":506,"fill":127},"98",[78,535,536],{"x":80,"y":509,"style":114,"fill":93,"textAnchor":84},"for loading by type",[54,538],{"x":539,"y":481,"width":482,"height":160,"rx":161,"fill":135,"stroke":136,"style":94},"514",[78,541,543],{"x":542,"y":487,"style":488,"fill":136,"textAnchor":84},"625","CountFeatures",[78,545,546],{"x":542,"y":113,"style":492,"fill":76,"textAnchor":84},"everything above",[78,548,549],{"x":542,"y":496,"style":492,"fill":76,"textAnchor":84},"plus exact counts",[78,551,552],{"x":542,"y":500,"style":492,"fill":76,"textAnchor":84},"may read every row",[54,554],{"x":555,"y":505,"width":125,"height":91,"rx":506,"fill":135,"stroke":136,"style":530},"544",[54,557],{"x":555,"y":505,"width":106,"height":91,"rx":506,"fill":136},[78,559,560],{"x":542,"y":509,"style":114,"fill":93,"textAnchor":84},"for inventories and QA",[191,562,564],{"id":563},"choose-how-much-work-the-query-does","Choose how much work the query does",[14,566,567],{},"Flags trade speed for detail. For a picker that just needs names, a fast scan is enough; for an inventory report that needs counts, ask for them explicitly.",[240,569,571],{"className":242,"code":570,"language":244,"meta":245,"style":245},"fast = registry.querySublayers(path, Qgis.SublayerQueryFlag.FastScan)\nprint([d.name() for d in fast])\n\nfull = registry.querySublayers(path, Qgis.SublayerQueryFlag.CountFeatures)\nfor d in full:\n    print(d.name(), d.featureCount())\n",[23,572,573,583,600,604,614,625],{"__ignoreMap":245},[249,574,575,578,580],{"class":151,"line":251},[249,576,577],{"class":258},"fast ",[249,579,281],{"class":254},[249,581,582],{"class":258}," registry.querySublayers(path, Qgis.SublayerQueryFlag.FastScan)\n",[249,584,585,588,591,593,595,597],{"class":151,"line":268},[249,586,587],{"class":373},"print",[249,589,590],{"class":258},"([d.name() ",[249,592,318],{"class":254},[249,594,321],{"class":258},[249,596,324],{"class":254},[249,598,599],{"class":258}," fast])\n",[249,601,602],{"class":151,"line":275},[249,603,272],{"emptyLinePlaceholder":271},[249,605,606,609,611],{"class":151,"line":288},[249,607,608],{"class":258},"full ",[249,610,281],{"class":254},[249,612,613],{"class":258}," registry.querySublayers(path, Qgis.SublayerQueryFlag.CountFeatures)\n",[249,615,616,618,620,622],{"class":151,"line":299},[249,617,318],{"class":254},[249,619,321],{"class":258},[249,621,324],{"class":254},[249,623,624],{"class":258}," full:\n",[249,626,627,629],{"class":151,"line":304},[249,628,374],{"class":373},[249,630,631],{"class":258},"(d.name(), d.featureCount())\n",[14,633,634,636],{},[202,635,433],{}," On a GeoPackage the difference is small, because table names, geometry types and counts all live in metadata tables. On an Esri File Geodatabase with a few hundred feature classes, or a KML with thousands of placemarks spread across folders, the default query can take several seconds and a counting query much longer. The fast scan is also the right choice before the file is known to be valid — it will not try to read contents that might be corrupt.",[191,638,640],{"id":639},"load-everything-or-a-filtered-set","Load everything, or a filtered set",[14,642,643,646],{},[23,644,645],{},"toLayer"," turns a details object into a ready layer with the correct provider, so loading every vector table is a short loop. A filter on the details — type, geometry, name pattern — picks a subset without ever opening the tables you skip.",[240,648,650],{"className":242,"code":649,"language":244,"meta":245,"style":245},"import re\nfrom qgis.core import QgsProject, QgsProviderSublayerDetails\n\nproject = QgsProject.instance()\noptions = QgsProviderSublayerDetails.LayerOptions(project.transformContext())\n\nwanted = [\n    d for d in registry.querySublayers(path)\n    if d.type() == Qgis.LayerType.Vector\n    and d.wkbType() != Qgis.WkbType.NoGeometry\n    and not re.match(r\"^(tmp|bak)_\", d.name())\n]\n\ngroup = project.layerTreeRoot().insertGroup(0, \"city_base\")\nfor d in sorted(wanted, key=lambda d: d.name()):\n    layer = d.toLayer(options)\n    if layer is None or not layer.isValid():\n        print(\"skipped\", d.name())\n        continue\n    project.addMapLayer(layer, False)\n    group.addLayer(layer)\n",[23,651,652,659,670,674,684,694,698,708,721,732,746,786,792,797,817,842,853,875,888,894,905],{"__ignoreMap":245},[249,653,654,656],{"class":151,"line":251},[249,655,262],{"class":254},[249,657,658],{"class":258}," re\n",[249,660,661,663,665,667],{"class":151,"line":268},[249,662,255],{"class":254},[249,664,259],{"class":258},[249,666,262],{"class":254},[249,668,669],{"class":258}," QgsProject, QgsProviderSublayerDetails\n",[249,671,672],{"class":151,"line":275},[249,673,272],{"emptyLinePlaceholder":271},[249,675,676,679,681],{"class":151,"line":288},[249,677,678],{"class":258},"project ",[249,680,281],{"class":254},[249,682,683],{"class":258}," QgsProject.instance()\n",[249,685,686,689,691],{"class":151,"line":299},[249,687,688],{"class":258},"options ",[249,690,281],{"class":254},[249,692,693],{"class":258}," QgsProviderSublayerDetails.LayerOptions(project.transformContext())\n",[249,695,696],{"class":151,"line":304},[249,697,272],{"emptyLinePlaceholder":271},[249,699,700,703,705],{"class":151,"line":315},[249,701,702],{"class":258},"wanted ",[249,704,281],{"class":254},[249,706,707],{"class":258}," [\n",[249,709,710,713,715,717,719],{"class":151,"line":330},[249,711,712],{"class":258},"    d ",[249,714,318],{"class":254},[249,716,321],{"class":258},[249,718,324],{"class":254},[249,720,312],{"class":258},[249,722,723,726,728,730],{"class":151,"line":347},[249,724,725],{"class":254},"    if",[249,727,338],{"class":258},[249,729,341],{"class":254},[249,731,344],{"class":258},[249,733,734,737,740,743],{"class":151,"line":370},[249,735,736],{"class":254},"    and",[249,738,739],{"class":258}," d.wkbType() ",[249,741,742],{"class":254},"!=",[249,744,745],{"class":258}," Qgis.WkbType.NoGeometry\n",[249,747,749,751,754,757,760,762,765,769,772,775,778,781,783],{"class":151,"line":748},11,[249,750,736],{"class":254},[249,752,753],{"class":254}," not",[249,755,756],{"class":258}," re.match(",[249,758,759],{"class":254},"r",[249,761,383],{"class":284},[249,763,764],{"class":373},"^(",[249,766,768],{"class":767},"sns5M","tmp",[249,770,771],{"class":254},"|",[249,773,774],{"class":767},"bak",[249,776,777],{"class":373},")",[249,779,780],{"class":767},"_",[249,782,383],{"class":284},[249,784,785],{"class":258},", d.name())\n",[249,787,789],{"class":151,"line":788},12,[249,790,791],{"class":258},"]\n",[249,793,795],{"class":151,"line":794},13,[249,796,272],{"emptyLinePlaceholder":271},[249,798,800,803,805,808,810,812,815],{"class":151,"line":799},14,[249,801,802],{"class":258},"group ",[249,804,281],{"class":254},[249,806,807],{"class":258}," project.layerTreeRoot().insertGroup(",[249,809,56],{"class":373},[249,811,446],{"class":258},[249,813,814],{"class":284},"\"city_base\"",[249,816,428],{"class":258},[249,818,820,822,824,826,829,832,836,839],{"class":151,"line":819},15,[249,821,318],{"class":254},[249,823,321],{"class":258},[249,825,324],{"class":254},[249,827,828],{"class":373}," sorted",[249,830,831],{"class":258},"(wanted, ",[249,833,835],{"class":834},"s9osk","key",[249,837,838],{"class":254},"=lambda",[249,840,841],{"class":258}," d: d.name()):\n",[249,843,845,848,850],{"class":151,"line":844},16,[249,846,847],{"class":258},"    layer ",[249,849,281],{"class":254},[249,851,852],{"class":258}," d.toLayer(options)\n",[249,854,856,858,861,864,867,870,872],{"class":151,"line":855},17,[249,857,725],{"class":254},[249,859,860],{"class":258}," layer ",[249,862,863],{"class":254},"is",[249,865,866],{"class":373}," None",[249,868,869],{"class":254}," or",[249,871,753],{"class":254},[249,873,874],{"class":258}," layer.isValid():\n",[249,876,878,881,883,886],{"class":151,"line":877},18,[249,879,880],{"class":373},"        print",[249,882,377],{"class":258},[249,884,885],{"class":284},"\"skipped\"",[249,887,785],{"class":258},[249,889,891],{"class":151,"line":890},19,[249,892,893],{"class":254},"        continue\n",[249,895,897,900,903],{"class":151,"line":896},20,[249,898,899],{"class":258},"    project.addMapLayer(layer, ",[249,901,902],{"class":373},"False",[249,904,428],{"class":258},[249,906,908],{"class":151,"line":907},21,[249,909,910],{"class":258},"    group.addLayer(layer)\n",[14,912,913,915,916,919,920,923,924,927,928,932,933,936,937,941],{},[202,914,433],{}," Passing the project's transform context in ",[23,917,918],{},"LayerOptions"," keeps datum transformations consistent with the rest of the project. ",[23,921,922],{},"addMapLayer(layer, False)"," registers the layer without putting it at the top of the layer tree, and ",[23,925,926],{},"group.addLayer"," places it inside a group named after the container — the pattern from ",[31,929,931],{"href":930},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002Forganise-layer-tree-groups-pyqgis\u002F","organising the layer tree",". Excluding ",[23,934,935],{},"NoGeometry"," keeps attribute-only tables out of the map; load those separately if they will be used in ",[31,938,940],{"href":939},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002Fdefine-layer-relations-pyqgis\u002F","layer relations"," or joins. Sorting by name gives a predictable layer order regardless of how the tables were created.",[14,943,944],{},[39,945,948,951,954,957,964,967,973,978,982,988,991,997,1001,1005,1008,1012,1015,1019,1022,1026,1029,1033,1036,1040,1043,1048],{"viewBox":946,"role":42,"ariaLabel":947,"xmlns":44},"0 0 760 250","A filter pipeline over sublayer details: all reported sublayers pass through a type filter, a geometry filter and a name pattern filter before being loaded into a group, with rejected entries never opened",[46,949,950],{},"Filter the details, not the layers",[50,952,953],{},"Eleven sublayers enter. The vector-type filter removes two rasters. The geometry filter removes three attribute-only tables. The name filter removes two tables prefixed tmp or bak. Four layers remain and are loaded into a city_base group. Rejected sublayers are never opened, so filtering first is cheaper than loading everything and removing layers afterwards.",[54,955],{"x":56,"y":56,"width":57,"height":956,"fill":59},"250",[61,958,959],{},[64,960,962],{"id":961,"viewBox":67,"refX":68,"refY":69,"markerWidth":70,"markerHeight":70,"orient":71},"gpkgFiltArrow",[73,963],{"d":75,"fill":76},[78,965,966],{"x":80,"y":81,"style":82,"fill":83,"textAnchor":84},"Rejected sublayers are never opened",[54,968],{"x":969,"y":970,"width":172,"height":971,"rx":161,"fill":92,"stroke":93,"style":972},"16","70","80","stroke-width:2",[78,974,977],{"x":487,"y":975,"style":976,"fill":83,"textAnchor":84},"104","text-anchor:middle;font-size:18px;font-weight:bold;font-family:sans-serif","11",[78,979,981],{"x":487,"y":980,"style":114,"fill":76,"textAnchor":84},"128","sublayers",[151,983],{"x1":984,"y1":985,"x2":986,"y2":985,"stroke":76,"style":987},"136","110","160","stroke-width:1.8;marker-end:url(#gpkgFiltArrow)",[54,989],{"x":990,"y":970,"width":496,"height":971,"rx":161,"fill":126,"stroke":127,"style":972},"166",[78,992,996],{"x":993,"y":994,"style":995,"fill":127,"textAnchor":84},"231","100","text-anchor:middle;font-size:10.5px;font-weight:bold;font-family:sans-serif","vector only",[78,998,1000],{"x":993,"y":999,"style":114,"fill":76,"textAnchor":84},"126","−2 rasters",[151,1002],{"x1":1003,"y1":985,"x2":1004,"y2":985,"stroke":76,"style":987},"296","320",[54,1006],{"x":1007,"y":970,"width":496,"height":971,"rx":161,"fill":135,"stroke":136,"style":972},"326",[78,1009,1011],{"x":1010,"y":994,"style":995,"fill":136,"textAnchor":84},"391","has geometry",[78,1013,1014],{"x":1010,"y":999,"style":114,"fill":76,"textAnchor":84},"−3 tables",[151,1016],{"x1":1017,"y1":985,"x2":1018,"y2":985,"stroke":76,"style":987},"456","480",[54,1020],{"x":1021,"y":970,"width":496,"height":971,"rx":161,"fill":108,"stroke":109,"style":972},"486",[78,1023,1025],{"x":1024,"y":994,"style":995,"fill":109,"textAnchor":84},"551","name filter",[78,1027,1028],{"x":1024,"y":999,"style":114,"fill":76,"textAnchor":84},"−2 tmp \u002F bak",[151,1030],{"x1":1031,"y1":985,"x2":1032,"y2":985,"stroke":76,"style":987},"616","640",[54,1034],{"x":1035,"y":970,"width":533,"height":971,"rx":161,"fill":483,"stroke":162,"style":94},"646",[78,1037,1039],{"x":1038,"y":975,"style":976,"fill":167,"textAnchor":84},"695","4",[78,1041,1042],{"x":1038,"y":980,"style":114,"fill":76,"textAnchor":84},"loaded",[54,1044],{"x":172,"y":1045,"width":1046,"height":103,"rx":68,"fill":92,"stroke":93,"style":1047},"184","520","stroke-width:1.8",[78,1049,1051],{"x":80,"y":1050,"style":492,"fill":76,"textAnchor":84},"211","filtering details costs nothing; removing loaded layers costs an open each",[191,1053,1055],{"id":1054},"load-rasters-and-styles-from-the-same-file","Load rasters and styles from the same file",[14,1057,1058,1059,1061,1062,1065,1066,1068],{},"Raster sublayers load through the same ",[23,1060,645],{}," call and come back as ",[23,1063,1064],{},"QgsRasterLayer",". GeoPackages can also carry a default style per table in ",[23,1067,445],{},", which QGIS applies automatically when the layer is created — so a container prepared by a colleague arrives styled.",[240,1070,1072],{"className":242,"code":1071,"language":244,"meta":245,"style":245},"for d in registry.querySublayers(path):\n    if d.type() != Qgis.LayerType.Raster:\n        continue\n    raster = d.toLayer(options)\n    project.addMapLayer(raster, False)\n    group.insertLayer(-1, raster)\n\nroads = project.mapLayersByName(\"roads\")[0]\ncount, ids, names, descriptions, error = roads.listStylesInDatabase()\nprint(count, names)\nif count:\n    qml, err = roads.getStyleFromDatabase(ids[0])\n    print(\"style source:\", names[0], \"ok\" if not err else err)\n",[23,1073,1074,1085,1096,1100,1109,1118,1132,1136,1156,1166,1173,1180,1195],{"__ignoreMap":245},[249,1075,1076,1078,1080,1082],{"class":151,"line":251},[249,1077,318],{"class":254},[249,1079,321],{"class":258},[249,1081,324],{"class":254},[249,1083,1084],{"class":258}," registry.querySublayers(path):\n",[249,1086,1087,1089,1091,1093],{"class":151,"line":268},[249,1088,725],{"class":254},[249,1090,338],{"class":258},[249,1092,742],{"class":254},[249,1094,1095],{"class":258}," Qgis.LayerType.Raster:\n",[249,1097,1098],{"class":151,"line":275},[249,1099,893],{"class":254},[249,1101,1102,1105,1107],{"class":151,"line":288},[249,1103,1104],{"class":258},"    raster ",[249,1106,281],{"class":254},[249,1108,852],{"class":258},[249,1110,1111,1114,1116],{"class":151,"line":299},[249,1112,1113],{"class":258},"    project.addMapLayer(raster, ",[249,1115,902],{"class":373},[249,1117,428],{"class":258},[249,1119,1120,1123,1126,1129],{"class":151,"line":304},[249,1121,1122],{"class":258},"    group.insertLayer(",[249,1124,1125],{"class":254},"-",[249,1127,1128],{"class":373},"1",[249,1130,1131],{"class":258},", raster)\n",[249,1133,1134],{"class":151,"line":315},[249,1135,272],{"emptyLinePlaceholder":271},[249,1137,1138,1141,1143,1146,1149,1152,1154],{"class":151,"line":330},[249,1139,1140],{"class":258},"roads ",[249,1142,281],{"class":254},[249,1144,1145],{"class":258}," project.mapLayersByName(",[249,1147,1148],{"class":284},"\"roads\"",[249,1150,1151],{"class":258},")[",[249,1153,56],{"class":373},[249,1155,791],{"class":258},[249,1157,1158,1161,1163],{"class":151,"line":347},[249,1159,1160],{"class":258},"count, ids, names, descriptions, error ",[249,1162,281],{"class":254},[249,1164,1165],{"class":258}," roads.listStylesInDatabase()\n",[249,1167,1168,1170],{"class":151,"line":370},[249,1169,587],{"class":373},[249,1171,1172],{"class":258},"(count, names)\n",[249,1174,1175,1177],{"class":151,"line":748},[249,1176,358],{"class":254},[249,1178,1179],{"class":258}," count:\n",[249,1181,1182,1185,1187,1190,1192],{"class":151,"line":788},[249,1183,1184],{"class":258},"    qml, err ",[249,1186,281],{"class":254},[249,1188,1189],{"class":258}," roads.getStyleFromDatabase(ids[",[249,1191,56],{"class":373},[249,1193,1194],{"class":258},"])\n",[249,1196,1197,1199,1201,1204,1207,1209,1212,1215,1218,1220,1223,1225],{"class":151,"line":794},[249,1198,374],{"class":373},[249,1200,377],{"class":258},[249,1202,1203],{"class":284},"\"style source:\"",[249,1205,1206],{"class":258},", names[",[249,1208,56],{"class":373},[249,1210,1211],{"class":258},"], ",[249,1213,1214],{"class":284},"\"ok\"",[249,1216,1217],{"class":254}," if",[249,1219,753],{"class":254},[249,1221,1222],{"class":258}," err ",[249,1224,364],{"class":254},[249,1226,1227],{"class":258}," err)\n",[14,1229,1230,1232,1233,1236,1237,1240,1241,1244,1245,1248,1249,1253],{},[202,1231,433],{}," ",[23,1234,1235],{},"group.insertLayer(-1, …)"," appends rasters below the vector layers so they draw underneath. ",[23,1238,1239],{},"listStylesInDatabase"," returns how many styles are stored for the layer's table, along with their ids and names; the first entry of the list is the one marked default when one exists. ",[23,1242,1243],{},"getStyleFromDatabase"," returns the QML text, which you can apply to a different layer with ",[23,1246,1247],{},"QgsMapLayerStyle"," or save to disk — useful for moving a style out of a container into a ",[31,1250,1252],{"href":1251},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fsave-and-load-qml-style-pyqgis\u002F","QML file",".",[191,1255,1257],{"id":1256},"inventory-a-folder-of-deliveries","Inventory a folder of deliveries",[14,1259,1260],{},"Data suppliers rarely send one container. A monthly delivery might be a dozen GeoPackages and a File Geodatabase, and the first question is always the same: what arrived, and what changed since last month? A fast scan across the folder answers it in seconds and produces a table that can be diffed against the previous delivery.",[240,1262,1264],{"className":242,"code":1263,"language":244,"meta":245,"style":245},"import csv\nfrom pathlib import Path\n\ndef inventory(folder):\n    rows = []\n    for item in sorted(Path(folder).iterdir()):\n        if item.suffix.lower() not in {\".gpkg\", \".gdb\", \".sqlite\", \".kml\", \".kmz\"}:\n            continue\n        for d in registry.querySublayers(str(item), Qgis.SublayerQueryFlag.CountFeatures):\n            is_vector = d.type() == Qgis.LayerType.Vector\n            rows.append({\n                \"container\": item.name,\n                \"sublayer\": d.name(),\n                \"kind\": QgsWkbTypes.displayString(d.wkbType()) if is_vector else \"raster\",\n                \"features\": d.featureCount(),\n            })\n    return rows\n\ncurrent = inventory(\"\u002Fdata\u002Fdeliveries\u002F2026-09\")\nwith open(\"\u002Fdata\u002Fdeliveries\u002F2026-09\u002Finventory.csv\", \"w\", newline=\"\") as fh:\n    writer = csv.DictWriter(fh, fieldnames=[\"container\", \"sublayer\", \"kind\", \"features\"])\n    writer.writeheader()\n    writer.writerows(current)\n\nprevious = {(r[\"container\"], r[\"sublayer\"]) for r in\n            csv.DictReader(open(\"\u002Fdata\u002Fdeliveries\u002F2026-08\u002Finventory.csv\"))}\nadded = [r for r in current if (r[\"container\"], r[\"sublayer\"]) not in previous]\nprint(\"new sublayers this month:\", [f'{r[\"container\"]}:{r[\"sublayer\"]}' for r in added])\n",[23,1265,1266,1273,1285,1289,1301,1311,1326,1368,1373,1391,1404,1409,1417,1425,1445,1453,1458,1466,1470,1485,1522,1560,1566,1572,1577,1606,1623,1663],{"__ignoreMap":245},[249,1267,1268,1270],{"class":151,"line":251},[249,1269,262],{"class":254},[249,1271,1272],{"class":258}," csv\n",[249,1274,1275,1277,1280,1282],{"class":151,"line":268},[249,1276,255],{"class":254},[249,1278,1279],{"class":258}," pathlib ",[249,1281,262],{"class":254},[249,1283,1284],{"class":258}," Path\n",[249,1286,1287],{"class":151,"line":275},[249,1288,272],{"emptyLinePlaceholder":271},[249,1290,1291,1294,1298],{"class":151,"line":288},[249,1292,1293],{"class":254},"def",[249,1295,1297],{"class":1296},"svObZ"," inventory",[249,1299,1300],{"class":258},"(folder):\n",[249,1302,1303,1306,1308],{"class":151,"line":299},[249,1304,1305],{"class":258},"    rows ",[249,1307,281],{"class":254},[249,1309,1310],{"class":258}," []\n",[249,1312,1313,1316,1319,1321,1323],{"class":151,"line":304},[249,1314,1315],{"class":254},"    for",[249,1317,1318],{"class":258}," item ",[249,1320,324],{"class":254},[249,1322,828],{"class":373},[249,1324,1325],{"class":258},"(Path(folder).iterdir()):\n",[249,1327,1328,1331,1334,1337,1340,1342,1345,1347,1350,1352,1355,1357,1360,1362,1365],{"class":151,"line":315},[249,1329,1330],{"class":254},"        if",[249,1332,1333],{"class":258}," item.suffix.lower() ",[249,1335,1336],{"class":254},"not",[249,1338,1339],{"class":254}," in",[249,1341,398],{"class":258},[249,1343,1344],{"class":284},"\".gpkg\"",[249,1346,446],{"class":258},[249,1348,1349],{"class":284},"\".gdb\"",[249,1351,446],{"class":258},[249,1353,1354],{"class":284},"\".sqlite\"",[249,1356,446],{"class":258},[249,1358,1359],{"class":284},"\".kml\"",[249,1361,446],{"class":258},[249,1363,1364],{"class":284},"\".kmz\"",[249,1366,1367],{"class":258},"}:\n",[249,1369,1370],{"class":151,"line":330},[249,1371,1372],{"class":254},"            continue\n",[249,1374,1375,1378,1380,1382,1385,1388],{"class":151,"line":347},[249,1376,1377],{"class":254},"        for",[249,1379,321],{"class":258},[249,1381,324],{"class":254},[249,1383,1384],{"class":258}," registry.querySublayers(",[249,1386,1387],{"class":373},"str",[249,1389,1390],{"class":258},"(item), Qgis.SublayerQueryFlag.CountFeatures):\n",[249,1392,1393,1396,1398,1400,1402],{"class":151,"line":370},[249,1394,1395],{"class":258},"            is_vector ",[249,1397,281],{"class":254},[249,1399,338],{"class":258},[249,1401,341],{"class":254},[249,1403,344],{"class":258},[249,1405,1406],{"class":151,"line":748},[249,1407,1408],{"class":258},"            rows.append({\n",[249,1410,1411,1414],{"class":151,"line":788},[249,1412,1413],{"class":284},"                \"container\"",[249,1415,1416],{"class":258},": item.name,\n",[249,1418,1419,1422],{"class":151,"line":794},[249,1420,1421],{"class":284},"                \"sublayer\"",[249,1423,1424],{"class":258},": d.name(),\n",[249,1426,1427,1430,1433,1435,1437,1439,1442],{"class":151,"line":799},[249,1428,1429],{"class":284},"                \"kind\"",[249,1431,1432],{"class":258},": QgsWkbTypes.displayString(d.wkbType()) ",[249,1434,358],{"class":254},[249,1436,361],{"class":258},[249,1438,364],{"class":254},[249,1440,1441],{"class":284}," \"raster\"",[249,1443,1444],{"class":258},",\n",[249,1446,1447,1450],{"class":151,"line":819},[249,1448,1449],{"class":284},"                \"features\"",[249,1451,1452],{"class":258},": d.featureCount(),\n",[249,1454,1455],{"class":151,"line":844},[249,1456,1457],{"class":258},"            })\n",[249,1459,1460,1463],{"class":151,"line":855},[249,1461,1462],{"class":254},"    return",[249,1464,1465],{"class":258}," rows\n",[249,1467,1468],{"class":151,"line":877},[249,1469,272],{"emptyLinePlaceholder":271},[249,1471,1472,1475,1477,1480,1483],{"class":151,"line":890},[249,1473,1474],{"class":258},"current ",[249,1476,281],{"class":254},[249,1478,1479],{"class":258}," inventory(",[249,1481,1482],{"class":284},"\"\u002Fdata\u002Fdeliveries\u002F2026-09\"",[249,1484,428],{"class":258},[249,1486,1487,1490,1493,1495,1498,1500,1503,1505,1508,1510,1513,1516,1519],{"class":151,"line":896},[249,1488,1489],{"class":254},"with",[249,1491,1492],{"class":373}," open",[249,1494,377],{"class":258},[249,1496,1497],{"class":284},"\"\u002Fdata\u002Fdeliveries\u002F2026-09\u002Finventory.csv\"",[249,1499,446],{"class":258},[249,1501,1502],{"class":284},"\"w\"",[249,1504,446],{"class":258},[249,1506,1507],{"class":834},"newline",[249,1509,281],{"class":254},[249,1511,1512],{"class":284},"\"\"",[249,1514,1515],{"class":258},") ",[249,1517,1518],{"class":254},"as",[249,1520,1521],{"class":258}," fh:\n",[249,1523,1524,1527,1529,1532,1535,1537,1540,1543,1545,1548,1550,1553,1555,1558],{"class":151,"line":907},[249,1525,1526],{"class":258},"    writer ",[249,1528,281],{"class":254},[249,1530,1531],{"class":258}," csv.DictWriter(fh, ",[249,1533,1534],{"class":834},"fieldnames",[249,1536,281],{"class":254},[249,1538,1539],{"class":258},"[",[249,1541,1542],{"class":284},"\"container\"",[249,1544,446],{"class":258},[249,1546,1547],{"class":284},"\"sublayer\"",[249,1549,446],{"class":258},[249,1551,1552],{"class":284},"\"kind\"",[249,1554,446],{"class":258},[249,1556,1557],{"class":284},"\"features\"",[249,1559,1194],{"class":258},[249,1561,1563],{"class":151,"line":1562},22,[249,1564,1565],{"class":258},"    writer.writeheader()\n",[249,1567,1569],{"class":151,"line":1568},23,[249,1570,1571],{"class":258},"    writer.writerows(current)\n",[249,1573,1575],{"class":151,"line":1574},24,[249,1576,272],{"emptyLinePlaceholder":271},[249,1578,1580,1583,1585,1588,1590,1593,1595,1598,1600,1603],{"class":151,"line":1579},25,[249,1581,1582],{"class":258},"previous ",[249,1584,281],{"class":254},[249,1586,1587],{"class":258}," {(r[",[249,1589,1542],{"class":284},[249,1591,1592],{"class":258},"], r[",[249,1594,1547],{"class":284},[249,1596,1597],{"class":258},"]) ",[249,1599,318],{"class":254},[249,1601,1602],{"class":258}," r ",[249,1604,1605],{"class":254},"in\n",[249,1607,1609,1612,1615,1617,1620],{"class":151,"line":1608},26,[249,1610,1611],{"class":258},"            csv.DictReader(",[249,1613,1614],{"class":373},"open",[249,1616,377],{"class":258},[249,1618,1619],{"class":284},"\"\u002Fdata\u002Fdeliveries\u002F2026-08\u002Finventory.csv\"",[249,1621,1622],{"class":258},"))}\n",[249,1624,1626,1629,1631,1634,1636,1638,1640,1643,1645,1648,1650,1652,1654,1656,1658,1660],{"class":151,"line":1625},27,[249,1627,1628],{"class":258},"added ",[249,1630,281],{"class":254},[249,1632,1633],{"class":258}," [r ",[249,1635,318],{"class":254},[249,1637,1602],{"class":258},[249,1639,324],{"class":254},[249,1641,1642],{"class":258}," current ",[249,1644,358],{"class":254},[249,1646,1647],{"class":258}," (r[",[249,1649,1542],{"class":284},[249,1651,1592],{"class":258},[249,1653,1547],{"class":284},[249,1655,1597],{"class":258},[249,1657,1336],{"class":254},[249,1659,1339],{"class":254},[249,1661,1662],{"class":258}," previous]\n",[249,1664,1666,1668,1670,1673,1676,1678,1681,1683,1686,1688,1691,1693,1696,1698,1700,1702,1704,1706,1708,1711,1713,1715],{"class":151,"line":1665},28,[249,1667,587],{"class":373},[249,1669,377],{"class":258},[249,1671,1672],{"class":284},"\"new sublayers this month:\"",[249,1674,1675],{"class":258},", [",[249,1677,380],{"class":254},[249,1679,1680],{"class":284},"'",[249,1682,386],{"class":373},[249,1684,1685],{"class":258},"r[",[249,1687,1542],{"class":284},[249,1689,1690],{"class":258},"]",[249,1692,395],{"class":373},[249,1694,1695],{"class":284},":",[249,1697,386],{"class":373},[249,1699,1685],{"class":258},[249,1701,1547],{"class":284},[249,1703,1690],{"class":258},[249,1705,395],{"class":373},[249,1707,1680],{"class":284},[249,1709,1710],{"class":254}," for",[249,1712,1602],{"class":258},[249,1714,324],{"class":254},[249,1716,1717],{"class":258}," added])\n",[14,1719,1720,1722,1723,1726,1727,1730],{},[202,1721,433],{}," A File Geodatabase is a folder, so ",[23,1724,1725],{},"iterdir"," picks it up by its ",[23,1728,1729],{},".gdb"," suffix just like a file. Counting features is worth the extra time here, because a table that shrank from 18,000 features to 40 is the kind of change nobody announces and everybody needs to know about. Keying the comparison on container and sublayer name catches both new and renamed tables — a rename shows up as one table added and one missing, which is exactly the situation that breaks hard-coded scripts. The CSV is also a useful attachment to a delivery acceptance note.",[191,1732,1734],{"id":1733},"qgis-version-compatibility","QGIS version compatibility",[14,1736,1737,446,1739,1741,1742,1745,1746,1749,1750,1753,1754,1757,1758,1741,1761,1764,1765,1741,1768,1771],{},[23,1738,208],{},[23,1740,229],{}," and ",[23,1743,1744],{},"Qgis.SublayerQueryFlag"," arrived in QGIS 3.22. On earlier releases, open the container once and use ",[23,1747,1748],{},"layer.dataProvider().subLayers()",", which returns strings joined by ",[23,1751,1752],{},"QgsDataProvider.sublayerSeparator()"," in the form ",[23,1755,1756],{},"index!!::!!name!!::!!count!!::!!geometry type",". ",[23,1759,1760],{},"Qgis.LayerType",[23,1762,1763],{},"Qgis.WkbType"," are the 3.30+ spellings of ",[23,1766,1767],{},"QgsMapLayerType",[23,1769,1770],{},"QgsWkbTypes.Type","; the QGIS 4 series only accepts the scoped forms.",[191,1773,1775],{"id":1774},"troubleshooting","Troubleshooting",[196,1777,1778,1788,1796,1804,1812],{},[199,1779,1780,1783,1784,1787],{},[202,1781,1782],{},"An empty list."," The path is wrong, or no provider recognises the format. Check ",[23,1785,1786],{},"os.path.exists"," and try the file in the Data Source Manager.",[199,1789,1790,1793,1794,1253],{},[202,1791,1792],{},"Geometry type reported as Unknown."," A fast scan was used, or the table genuinely has mixed geometry. Query without ",[23,1795,489],{},[199,1797,1798,1803],{},[202,1799,1800,1802],{},[23,1801,645],{}," returns an invalid layer."," The table exists but cannot be read — often a File Geodatabase feature class using a format your GDAL build does not support.",[199,1805,1806,1809,1810,1253],{},[202,1807,1808],{},"Loaded layers appear unstyled."," The styles are stored under a different table name, or the default flag is not set in ",[23,1811,445],{},[199,1813,1814,1817,1818,1821],{},[202,1815,1816],{},"KML folders all appear as one layer."," Some KML files flatten folders; query with the ",[23,1819,1820],{},"LIBKML"," driver available for per-folder sublayers.",[191,1823,1825],{"id":1824},"conclusion","Conclusion",[14,1827,1828,1829,1831],{},"Never guess what a container holds. Query it, filter the details by type, geometry and name, and load only what passes — through ",[23,1830,645],{},", so the right provider and URI are chosen for you. Use a fast scan for pickers, counts for inventories, and group what you load under the container's name so the project stays readable.",[191,1833,1835],{"id":1834},"frequently-asked-questions","Frequently Asked Questions",[14,1837,1838,1841,1842,1844],{},[202,1839,1840],{},"Does this work for File Geodatabases?","\nYes. Pass the ",[23,1843,1729],{}," folder path; each feature class and table is reported as a sublayer.",[14,1846,1847,1850,1853,1854,1253],{},[202,1848,1849],{},"How do I get the URI for one sublayer without loading it?",[23,1851,1852],{},"d.uri()"," returns it, ready for ",[23,1855,1856],{},"QgsVectorLayer(d.uri(), d.name(), d.providerKey())",[14,1858,1859,1862,1863,1866],{},[202,1860,1861],{},"Can I query a remote GeoPackage?","\nOver ",[23,1864,1865],{},"\u002Fvsicurl\u002F"," yes, though each query reads parts of the file over HTTP — prefer a fast scan.",[14,1868,1869,1872,1873,1253],{},[202,1870,1871],{},"Why are some tables missing?","\nInternal and index tables are hidden on purpose. A user table can also be hidden if it is not registered in ",[23,1874,1875],{},"gpkg_contents",[191,1877,1879],{"id":1878},"related","Related",[196,1881,1882,1887,1893,1899,1904],{},[199,1883,1884,1886],{},[31,1885,34],{"href":33}," — the guide this recipe belongs to",[199,1888,1889],{},[31,1890,1892],{"href":1891},"\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Fdecode-and-build-data-source-uris-pyqgis\u002F","Decode and Build Data Source URIs in PyQGIS",[199,1894,1895],{},[31,1896,1898],{"href":1897},"\u002Fspatial-data-processing-automation\u002Fpostgis-and-database-workflows\u002Fwrite-vector-layer-to-geopackage-pyqgis\u002F","Write a Vector Layer to GeoPackage in PyQGIS",[199,1900,1901],{},[31,1902,1903],{"href":930},"Organise the Layer Tree with Groups in PyQGIS",[199,1905,1906],{},[31,1907,1909],{"href":1908},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002Frun-algorithm-over-folder-of-files-pyqgis\u002F","Run an Algorithm Over a Folder of Files in PyQGIS",[1911,1912,1913],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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);}html pre.shiki code .sns5M, html code.shiki .sns5M{--shiki-default:#DBEDFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":245,"searchDepth":268,"depth":268,"links":1915},[1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926],{"id":193,"depth":268,"text":194},{"id":219,"depth":268,"text":220},{"id":563,"depth":268,"text":564},{"id":639,"depth":268,"text":640},{"id":1054,"depth":268,"text":1055},{"id":1256,"depth":268,"text":1257},{"id":1733,"depth":268,"text":1734},{"id":1774,"depth":268,"text":1775},{"id":1824,"depth":268,"text":1825},{"id":1834,"depth":268,"text":1835},{"id":1878,"depth":268,"text":1879},"Discover every table, raster and style inside a GeoPackage, File Geodatabase or KML with QgsProviderRegistry.querySublayers, load all of them or a filtered set in one call, and avoid the slow full scan on large containers.","md",{"slug":1930,"type":1931,"breadcrumb":1932,"datePublished":1933,"dateModified":1933},"list-and-load-geopackage-sublayers-pyqgis","article","List and Load GeoPackage Sublayers","2026-09-17","\u002Fspatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Flist-and-load-geopackage-sublayers-pyqgis",{"title":5,"description":1927},"spatial-data-processing-automation\u002Flayer-data-sources-and-formats\u002Flist-and-load-geopackage-sublayers-pyqgis\u002Findex","VlnE_QG8x6_DSSTNV8f54tnc-LkrJhyvzRxcRtIaG-M",1789632908447]