Repository navigation
Python bindings
The geodms bindings are a work in progress. The Windows setups provide interfaces for 64-bit CPython 3.12, 3.13 and 3.14; 3.9 is provided only by the GLOBIO (.g) setup.
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.
The setup contains one ABI-tagged geodms extension per supported CPython minor. Python automatically selects its matching file. Release builders supply the development installations through PYTHON312_ROOT, PYTHON313_ROOT, and PYTHON314_ROOT (and PYTHON39_ROOT for the GLOBIO flavour), or the corresponding ABI-specific *_INCLUDE_DIR and *_LIBRARIES pairs; the setup does not bundle Python itself.
The code examples below show how to use the functions that the geodms module exposes: loading a configuration and querying it, building a configuration in memory, setting parameter values and reading results back.
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 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 validThe GUI colours an item red when determining its meta info has failed. update_metainfo() runs
exactly that step and reports its outcome:
ok = some_item.update_metainfo() # False when the item failed
if not ok:
print(some_item.full_name(), some_item.fail_reason())update_metainfo() resolves the calculation rule, the domain and values units, the storage and
the sub-items the rule implies — everything a configuration error shows up in — and reads no
primary data. update() does read primary data, of the item and of all of its suppliers, which
for a raster attribute is a full calculation; that is why a configuration-wide check must use
update_metainfo() and not update().
Template bodies are inert and are not meant to be updated at all, so a walker skips them with
in_template() (true for a template and for everything inside one; is_template() is true for
the template item itself):
def red_items(item):
if item.in_template():
return
if not item.update_metainfo():
yield item.full_name(), item.fail_reason()
for child in item.sub_items():
yield from red_items(child)
for name, reason in red_items(config.const_root()):
print(f"{name}: {reason}")An item that failed an earlier calculation reports False here too, exactly as the tree-view
colours it red: its meta info is fine, but the item is not 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()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()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.14159After 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])The list must hold exactly one value per domain element: a list of another length is an error. The values are written tile by tile, so a domain of more than one tile is filled as well.
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'module geodms
-
version()→str: the GeoDMS version string -
ValueComposition, an enum:Single,Polygon,Sequence,MultiPoint -
ValueTypeId, an 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.dmsconfiguration -
create_config_root(name)→Config: create an empty in-memory configuration -
default_unit(value_type)→UnitItem: the shared default unit of a basic value type -
void_unit()→UnitItem: theVoidunit (domain of parameters)
class Config
-
root()→MutableTreeItem: the (mutable) root item -
const_root()→ConstTreeItem: 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,expr()→str,descr()→str -
sub_items()→list,parent()→ tree item,fail_reason()→str -
update(): calculate/update the item (and its storage, if configured) -
update_metainfo()→bool: determine the meta info without calculating;Falsefor a failed item, whose reasonfail_reason()then gives -
in_template()→bool,is_template()→bool:in_template()is true for a template and for every item inside one -
isDataItem()/asDataItem(): test / cast to aDataItem -
isUnitItem()/asUnitItem(): test / cast to a unit item
asDataItem() and asUnitItem() raise an exception, on both the read-only and the mutable tree item, for an item of another kind and for the null item that find() returns for a name that does not exist. Test with isDataItem(), isUnitItem() or is_null() first where either can happen.
ConstTreeItem additionally exposes first_subitem() and next() for tree traversal.
MutableTreeItem additionally exposes:
-
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
-
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() -
domain_unit()/values_unit()→UnitItem,value_composition() -
size()→int,update() -
get_value_as_float(i),get_value_as_int(i),get_value_as_str(i) -
get_values_as_float_list(),get_values_as_int_list() -
LockAndGetStringValue(i)→str: read the value at indexias a string
class MutableDataItem
-
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()
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 configuredA complete in-memory example (build a configuration without a model script and read
results back) is available in python/tst/InMemoryConfig.py.
- 15.0.1: the geodms module, with the bindings that load a configuration and query it.
- 20.5.0: building a configuration in memory, setting parameter values and Primary Data Access, with
ValueTypeId,create_config_root(),default_unit(),void_unit(),const_root(),full_name(),descr(),sub_items(),parent(),fail_reason(), the building methods ofMutableTreeItem, the classesUnitItem,MutableUnitItemandMutableDataItem, and the members ofDataItemother thanis_null(),name()andLockAndGetStringValue(). - 20.23.1:
update_metainfo(),in_template()andis_template();fail_reason()on an item that has not failed; the exception ofasDataItem()andasUnitItem()for an item of another kind or a null item; andset_values_from_float_list()andset_values_from_int_list()on a domain of more than one tile.
GeoDMS ©Object Vision BV. Source code distributed under GNU GPL-3. Documentation distributed under CC BY-SA 4.0.