We’ve been using GeoPackages for a while now. For example, in Loading a vector layer we covered how to load a specific layer from a GeoPackage. However, it is easy to make a mistake when specifying the layer name. For example:

iface.addVectorLayer('E:/Geodata/NaturalEarth/natural_earth_vector.gpkg|layername=foo', '', 'ogr')

Causes an error because there is no layer called foo in the GeoPackage: “Layer is not valid: The layer E:/Geodata/NaturalEarth/natural_earth_vector.gpkg|layername=foo is not a valid layer and can not be added to the map.”

However, this error is not very clear because it does not tell us the reason why the layer is invalid. It would be much more convenient to have a way to add a GeoPackage layer that first checks if that layer actually exists. So how can we find out which layers are available in a GeoPackage? – OGR to the rescue! Using OGR, we can open the GeoPackage and get a a list of its layers:

from osgeo import ogr
my_gpkg = 'E:/Geodata/NaturalEarth/natural_earth_vector.gpkg'
gpkg_layers = [l.GetName() for l in ogr.Open(my_gpkg )]

So this is how we can get a list of all layers in a GeoPackage.

Next, we can use this list to check if a certain layer is available, for example:

print('foo' in gpkg_layers)

prints False on the console.

In contrast:

print('ne_110m_land' in gpkg_layers)

prints True on the console.

Therefore, we can use this statement to decide whether to attempt to load the layer or to display a more precise error message:

my_layer = 'foo'
if my_layer in gpkg_layers:
    iface.addVectorLayer(my_gpkg + "|layername=" + my_layer, my_layer, 'ogr')
    print('Error: there is no layer named "{}" in {}!'.format(my_layer, gpkg))

Of course, it would be nice to be able to reuse this code for different layer names. We can achieve this goal by writing a new function. Let’s call our new function add_gpkg_layer:

def add_gpkg_layer(gpkg, layer):
    layers = [l.GetName() for l in ogr.Open(gpkg)]
    if layer in layers:
        iface.addVectorLayer(gpkg + "|layername=" + layer, layer, 'ogr')
        print('Error: there is no layer named "{}" in {}!'.format(layer, gpkg))

The first line of our function definition starts with def followed by the function name and the function parameters in parenthesis and a colon at the end. The function code that follows after the colon has to be indented.

Now we can add new layers easily:

add_gpkg_layer(my_gpkg, 'foo')
add_gpkg_layer(my_gpkg, 'ne_110m_land')

Of course, we can also create a function that loads multiple layers:

def add_layers_from_gpkg(gpkg, layers):
    for layer in layers:
        add_gpkg_layer(gpkg, layer)

Note how this function reuses our previously defined add_gpkg_layer function.

With this function in place, we can now conveniently load multiple layers in one go:

add_layers_from_gpkg(my_gpkg, ['ne_110m_land', 'ne_110m_lakes'])

Finally, if we want to load all layers, we can write:

def add_all_layers_from_gpkg(gpkg):
    layers = [l.GetName() for l in ogr.Open(gpkg)]
    add_layers_from_gpkg(gpkg, layers)

Be careful when using this function with big GeoPackages because it can take a while to load all layers!

These are the basics of writing new functions in Python. Functions make it possible to reuse your code without having to copy-paste it again and again. You also saw how to use ogr.Open to create a list of all layers that are available in a GeoPackage.


PyQGIS 101 is a work in progress. I’d appreciate any feedback, particularly from beginners!

  1. badger2100 said:

    When I try running the above code (if my_layer in layers:) I receive an error message stating the “layers” is not defined. Thoughts?
    Thanks much for feedback

    • Thank you for reporting this issue. There was a small mix-up in the post. The corresponding line of code should be if my_layer in gpkg_layers

  2. gviana7 said:

    Hi.. I have the same error. Can you please help us?
    And when I run the last script it doens’t show up the layers of geopackage.

    Many thanks and thanks a lot for your support n PyQgis! :)

    • Thank you for reporting this issue. There was a small mix-up in the post. The corresponding line of code should be if my_layer in gpkg_layers

  3. Mihails said:

    Hi! I found that changing “gpkg” to “my_gpkg” in the first example on printing the error message has allowed the code to work, perhaps by properly referencing the object (or whatever you properly call it) that had been defined before. And thanks for providing this intro course – a very valuable starting point, and later perhaps it’s worth to try the Uni of Helsinki courses (my potential plan as a learner).

    • You’re right! Thanks for reporting, Mihails!

  4. LukeH said:

    Hi, how could i execute a query on a geopackage layer, and then load the results?

      • Luke said:

        Hi really sorry – think I maybe forgot to tick the ‘Notify me’ part before or maybe it got lost in the spam. Thanks for reply in any case, that’s a pretty good way of doing it. I work in PostgreSQL and gpkg are fairly new to me. Mainly I want to use them for exporting specific projects in a portable format that can be loaded into Qfield. My question about queries on a gpkg was me going off on a bit of a tangent… but what I was trying find out was if it’s possible to connect to the gpkg and then execute a query on a tables in the gpkg and return the result (that’s basically what I do with my postgis dbb) – so without loading the layers into canvas qgis canvas/toc first. Cheers

  5. Ed Hawkins said:

    Anita I was just wondering when you say big geopackage what do you consider big?

    • I was thinking of the whole Naturalearth Geopackage. It has dozens of layers with lots of features. It will take a while to load them all.

  6. Stephen Sacks said:

    I stumbled upon this page and found it to be enormously helpful, exactly what I need. Thank you. If I may, I will venture to suggest one correction. The punctuation mark which you call a “semicolon” is actually a colon. You have it right in the code (one period above another period) but the word semicolon in your explanation means a period above a comma.

    • Thank you for your message, Stephen. I’ve fixed the colon issue.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: