Skip to content

Python bindings

Maarten Hilferink edited this page Jun 25, 2026 · 19 revisions

Note that currently, as in GeoDms 20.5.0 d.d. 25/06/2026, the geodms bindings are a work in progress and only available for python versions 3.13.2.

This page describes the geodms module, which embeds the GeoDMS engine inside Python (load a configuration, find items, update them). This is a different mechanism from exchanging data files between a GeoDMS configuration and a separate Python script: for that, write/read tabular data as parquet (or csv) and, if needed, let the GeoDMS run the script on demand via exec_ec. See GeoDMS through Python for an overview of all three integration architectures.

Update, d.d. 12/03/2026: we currently compilie PyDms.pyd with Python 3.13 installed and the environment variables PYTHON3_INCLUDE_DIR and PYTHON3_LIBRARIES referring to that installation.

GeoDMS version 15.0.1 introduces the geodms module for python. This document describes through code examples how to use the currently exposed set of geodms functionalities.

Version note. The configuration-building and primary data access bindings — creating containers, units, attributes and parameters in memory (without a model script), setting parameter and attribute values, and reading results back — described in the sections Building a configuration in memory, Setting parameter values and Querying results (Primary Data Access) below are available in GeoDMS version 20.5.0 and later. The basic load-and-query bindings are available since 15.0.1.

In order to import the geodms module in python make sure the installation folder is added to your path so that the module can be found:

import sys
sys.path.append('C:/"Program Files"/ObjectVision/GeoDms14.15.2')
from geodms import *

Retrieving the geodms version:

dms_version = version()

Initializing the geodms module:

dms_engine = Engine()

Loading and querying a configuration

Loading a dms configuration:

dms_config = dms_engine.load_config('./prj/config.dms')

Get the root item of a loaded dms configuration:

root = dms_config.root()

Finding an item in a loaded dms configuration from the root item:

parameters = root.find("/parameters")

Testing if the item is found by asserting that it is not null:

if (parameters.is_null()):
    raise Exception(f"Cannot find output item: '/parameters'")

Get the name (or full path) of a found item:

item_name      = parameters.name()
item_full_name = parameters.full_name()

Get the dms expression of a found item:

item_expr = parameters.expr()

Iterating over the direct sub-items of a container (the kind of an item follows from isUnitItem() / isDataItem()):

for child in root.sub_items():
    kind = 'unit' if child.isUnitItem() else ('attr' if child.isDataItem() else 'container')
    print(child.name(), kind)

Inspecting an item that failed to calculate:

reason = some_item.fail_reason()   # empty string when the item is valid

Change the expression of a found item:

out_dir = root.find("/parameters/input/OutDir")
out_dir.set_expr("path/to/new/out/dir")

Update an item:

target_item_fullname = "dms/target/item"
target_item = root.find(target_item_fullname)
if target_item.is_null():
  raise Exception(f"Cannot find output item: {target_item}")

target_item.update()

Building a configuration in memory

(GeoDMS 20.5.0 and later.) Instead of loading a .dms model script, a configuration can be built from scratch in Python. Start from an empty configuration root:

engine = Engine()
config = engine.create_config_root('demo')   # an empty in-memory configuration
root   = config.root()

Add sub-containers, units, attributes and parameters:

# a sub-container
data = root.add_container('data')

# a domain unit of a basic value type, sized by an expression. A domain's element
# count comes from its calculation rule; range(uint32, 0, n) defines an n-element domain.
entities = root.create_unit('Entity', 'uint32')
entities.set_expr('range(uint32, 0, 5)')

# an attribute over that domain, with a values unit of a basic value type
value = data.add_attribute('value', entities.asConst(), 'float64')

# an attribute with an explicit domain unit, values unit and value composition
geometry = data.add_data_item('geometry', point_domain, point_values, ValueComposition.Polygon)

# a parameter (Void domain) of a basic value type
nr_entries = root.add_param('nrEntries', 'uint32')

Attach a storage manager (e.g. to read a source file), or force in-memory / calculator-only operation:

src = root.add_container('src')
src.set_storage_manager('path/to/source.gpkg', 'gdal.vect', read_only=True)

derived.disable_storage()

Define derived items purely by an expression, exactly as in a model script:

doubled = data.add_attribute('doubled', entities.asConst(), 'float64')
doubled.set_expr('value * 2.0')

total = root.add_param('total', 'float64')
total.set_expr('sum(value)')

The Engine also exposes the shared default unit of a basic value type (handy as a values unit) and the Void unit (the domain of every parameter):

f64  = engine.default_unit('float64')
void = engine.void_unit()

Setting parameter values

(GeoDMS 20.5.0 and later.) Parameters (items with a Void domain) can be assigned a value directly:

nr_entries.set_param_int(5)
pi    = root.add_param('pi', 'float64');  pi.set_param_float(3.14159)
label = root.add_param('label', 'string'); label.set_param_str('hello from python')

print(pi.get_param_float())   # 3.14159

Querying results (Primary Data Access)

(GeoDMS 20.5.0 and later.) After updating an item, its values can be read back through the Primary Data Access functions. Cast a tree item to a DataItem (or use a MutableDataItem returned by the builders) and read scalar or bulk values:

result = root.find('/data/doubled')
result.update()                       # (re)calculate first

di = result.asDataItem()
print(di.size())                      # number of values (= domain unit count)
print(di.get_value_as_float(0))       # a single value, by index
print(di.get_values_as_float_list())  # all values as a python list

# the same for integers and strings
print(di.get_values_as_int_list())
print(di.get_value_as_str(0))

Writing primary data into a fresh in-memory attribute is done in bulk; the list length should equal the domain element count:

value.set_values_from_float_list([1.0, 2.0, 3.0, 4.0, 5.0])
value.set_values_from_int_list([1, 2, 3, 4, 5])

A data item also exposes its domain and values unit, and the unit its entity count / numeric range:

dom = di.domain_unit()
print(dom.value_type_id(), dom.count())   # e.g. ValueTypeId.UInt32 5
print(di.values_unit().value_type_id())   # e.g. ValueTypeId.Float64
print(di.values_unit().value_type_id().name)  # 'Float64'

API reference

module geodms

  • version()str — the GeoDMS version string
  • ValueComposition — enum: Single, Polygon, Sequence, MultiPoint
  • ValueTypeId (20.5.0+) — enum of value types: Float64, Float32, UInt32, Int32, UInt16, Int16, UInt8, Int8, UInt64, Int64, Bool, UInt4, SPoint, WPoint, IPoint, UPoint, FPoint, DPoint, String, Void, Unknown

class Engine — the single engine instance for the process. Constructing it also registers a message callback that prints GeoDMS diagnostics (warnings, calculation errors) to stderr, so failures are visible rather than silently yielding undefined values.

  • Engine() — construct (only once per process)
  • load_config(config_file_name)Config — load a .dms configuration
  • create_config_root(name)Config (20.5.0+) — create an empty in-memory configuration
  • default_unit(value_type)UnitItem (20.5.0+) — shared default unit of a basic value type
  • void_unit()UnitItem (20.5.0+) — the Void unit (domain of parameters)

class Config

  • root()MutableTreeItem — the (mutable) root item
  • const_root()ConstTreeItem (20.5.0+) — a read-only root item

class ConstTreeItem / MutableTreeItem — an item in the tree

  • is_null()bool
  • find(item_path) → tree item — look up an item by path
  • name()str, full_name()str (20.5.0+), expr()str, descr()str (20.5.0+)
  • sub_items()list (20.5.0+), parent() → tree item (20.5.0+), fail_reason()str (20.5.0+)
  • update() — calculate/update the item (and its storage, if configured)
  • isDataItem() / asDataItem() — test / cast to a DataItem
  • isUnitItem() / asUnitItem() — test / cast to a unit item

ConstTreeItem additionally exposes first_subitem() and next() for tree traversal. MutableTreeItem additionally exposes (all building methods are 20.5.0+):

  • set_expr(str), set_descr(str), asConst()
  • add_container(name)MutableTreeItem
  • create_unit(name, value_type)MutableUnitItem
  • add_data_item(name, domain, values, vc=ValueComposition.Single)MutableDataItem
  • add_attribute(name, domain, values_value_type)MutableDataItem
  • add_param(name, values_value_type)MutableDataItem
  • set_storage_manager(storage_name, storage_type, read_only=True), disable_storage()

class UnitItem / MutableUnitItem (20.5.0+)

  • is_null(), name(), full_name(), value_type_id()ValueTypeId
  • count()int, get_range()(begin, end)
  • MutableUnitItem: set_expr(str) (e.g. 'range(uint32, 0, n)' to size a domain), set_count(n), set_range(begin, end), asConst()

class DataItem

  • is_null()bool
  • name(), full_name() (20.5.0+)
  • domain_unit() / values_unit()UnitItem (20.5.0+), value_composition() (20.5.0+)
  • size()int (20.5.0+), update() (20.5.0+)
  • get_value_as_float(i), get_value_as_int(i), get_value_as_str(i) (20.5.0+)
  • get_values_as_float_list(), get_values_as_int_list() (20.5.0+)
  • LockAndGetStringValue(i)str — read the value at index i as a string

class MutableDataItem (20.5.0+)

  • asDataItem() — read-only view; domain_unit(), values_unit(), value_composition(), size(), name(), full_name(), update(), set_expr(str)
  • set_values_from_float_list(list), set_values_from_int_list(list) — write primary data (list length = domain element count)
  • set_param_float(v), set_param_int(v), set_param_str(v), get_param_float()

example usage

Adapted from python/tst/UnitTests.py:

import os
import sys

# make the geodms module and its dependencies (e.g. gdal.dll) findable
geodms_path = os.path.abspath('../../bin/Release/x64')
sys.path.append(geodms_path)
os.environ['PATH'] += os.pathsep + geodms_path

from geodms import *

# initialise the engine and load a configuration
engine = Engine()
config = engine.load_config('basic_data_test.dms')

# navigate the item tree from the root
root = config.root()
param_item = root.find("/parameters/test_param")
print(param_item.is_null())     # False if found

# change an expression and (re)calculate a dependent result
param_item.set_expr("3b")
result_item = root.find("/export/IntegerAtt")
result_item.update()            # updates the item and writes its storage, if configured

A complete in-memory example (build a configuration without a model script and read results back) is available in python/tst/InMemoryConfig.py.

Clone this wiki locally