Skip to content

GeoDMS through Python

MaartenHilferink edited this page Jun 25, 2026 · 2 revisions

GeoDMS and Python can be combined in three different ways. Which one fits best depends on who is "in charge" (Python or the GeoDMS) and on whether the two need to share data in-process or through data files.

# Architecture Who drives Data exchange
1 Run the GeoDMS as a separate process from Python Python data files (the GeoDMS reads/writes its configured storages)
2 Run Python as a separate process from within the GeoDMS GeoDMS data files (parquet / csv)
3 Use the GeoDMS Python bindings (in-process) Python in-process, through the geodms module

1. Run the GeoDMS as a separate process from Python

Python orchestrates the workflow and calls the command line tool GeoDMSRun (GeoDmsRun.exe) to let the GeoDMS update one or more items of a configuration. The GeoDMS reads its inputs and writes its results to the files/databases configured as storages (see Data Source); Python reads those results back.

This requires no GeoDMS-specific Python code and keeps the two processes fully isolated.

import subprocess

exit_code = subprocess.call([
    r"C:\Program Files\ObjectVision\GeoDms\GeoDmsRun.exe",
    r"/L", r"C:\tmp\run.log",          # write a log file
    r"C:\prj\my_project\cfg\model.dms", # the configuration
    r"/export/result"                   # the item (path relative to the desktop root) to update
])

if exit_code != 0:
    raise RuntimeError(f"GeoDmsRun failed with exit code {exit_code}")

# now read the file that /export/result was configured to write (e.g. a .parquet or .csv)

See GeoDMSRun and User Guide GeoDMS RUN for the available command line options.

2. Run Python as a separate process from within the GeoDMS

The GeoDMS drives the workflow: it writes an input file, starts a Python script on it, and reads the script's output back — all triggered automatically the moment the output item is requested. This is useful when a calculation is easier (or only possible) in Python, but it should fit transparently inside a GeoDMS configuration.

The mechanism combines three features:

  1. write the input as a typed, fast parquet file (see parquet);
  2. start the script with exec_ec, capturing its ExitCode;
  3. read the output, with the ExitCode woven into the output StorageName so the read waits until the script has finished.

A worked end-to-end example (write input → run script → read output) is documented on the exec_ec page. The conditional, lazy triggering of such a script — only running it when its result is actually needed — is described on the Indirect-expression page.

Relevant pages:

  • exec_ec — start the script and gate the read on its ExitCode
  • parquet — exchange typed tabular data with Python (pandas / pyarrow), and relate the imported domain back to an existing domain
  • Indirect-expression — only calculate (and run) what is needed

3. Use the GeoDMS Python bindings (in-process)

The GeoDMS ships a geodms Python module (PyDms.pyd) that embeds the GeoDMS engine inside the Python process. Python can then load a configuration, navigate the item tree, change expressions, update items and read values back without starting a separate process. See Python Bindings for installation and version notes.

The bindings are a work in progress. Since GeoDMS 20.5.0 the exposed set has grown beyond orchestrating and inspecting a configuration: a configuration can also be built in memory (containers, units, attributes, parameters — no model script), parameter and attribute values can be set, and results can be read back through the Primary Data Access functions. See Python Bindings for the full, version-annotated API reference and worked examples.

exposed module, classes and functions

The exposed API (from python/dll/src/Bindings.cpp), in brief:

module geodmsversion(), and the ValueComposition and ValueTypeId enums (20.5.0+).

class EngineEngine(), load_config(file)Config, and (20.5.0+) create_config_root(name)Config, default_unit(value_type), void_unit().

class Configroot()MutableTreeItem, const_root()ConstTreeItem (20.5.0+).

class ConstTreeItem / MutableTreeItemis_null(), find(path), name(), expr(), update(), isDataItem()/asDataItem(), isUnitItem()/asUnitItem(); and (20.5.0+) full_name(), descr(), sub_items(), parent(), fail_reason(). MutableTreeItem adds set_expr(str), asConst() and the configuration-building methods add_container, create_unit, add_data_item, add_attribute, add_param, set_storage_manager, disable_storage (all 20.5.0+).

class UnitItem / MutableUnitItem (20.5.0+)value_type_id() (a ValueTypeId enum), count(), get_range(), and set_count(n) / set_range(b, e) on the mutable variant.

class DataItem / MutableDataItem — read values with LockAndGetStringValue(i) and (20.5.0+) get_value_as_float/int/str(i), get_values_as_float_list(), size(), domain_unit(), values_unit(); write values with set_value_as_float/int, set_values_from_float_list, and the parameter helpers set_param_float/int/str, 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

# find returns a null item for non-existent paths
missing = root.find("/does/not/exist")
print(missing.is_null())        # True

# 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

see also

Clone this wiki locally