Nml-tools: schema-driven Fortran namelist modules, docs, and templates

Hi all,

Maintaining namelist-driven workflows is often painful: every change needs to be mirrored in reference files, documentation, and Fortran read modules, and you still typically lack validation and defaults.

I would like to share nml-tools, a small CLI + Python library that generates Fortran namelist modules, Markdown docs, and template namelists from a compact YAML/JSON spec (a focused subset of JSON Schema with Fortran extensions).

Highlights:

  • YAML or JSON schema input, plus x-fortran-* extensions (namelist name, kind, len, shape, defaults broadcasting)
  • Outputs: Fortran modules containing derived types representing the namelist + shared helper module, Markdown docs, and template namelists
  • Config-driven CLI for batching multiple schemas (nml-config.toml)
  • Validation mode to check namelist files against the schema
  • MIT licensed

Presence checking uses type-specific sentinels (null-char, -huge, NaN).

Example namelist that the schema below would generate/validate:

&demo
  dice = 1
  weights(:) = 0.1, 0.2, 0.3, 0.4, 0.5, 0.6
/

Minimal example of a schema (YAML):

x-fortran-namelist: "demo"
type: "object"
properties:
  dice:
    type: "integer"
    x-fortran-kind: "i4"
    default: 3
    enum: [1, 2, 3, 4, 5, 6]
    title: "Dice Roll"
  weights:
    type: array
    x-fortran-shape: [3, 2]
    items:
      type: "number"
      x-fortran-kind: "dp"
      minimum: 0.0
required:
  - "weights"

Generate outputs:

nml-tools generate --config nml-config.toml

Minimal nml-config.toml:

[helper]
path = "out/nml_helper.f90"

[kinds]
module = "iso_fortran_env"
real = ["real64"]
integer = ["int32"]
map = { dp = "real64", i4 = "int32" }

[[namelists]]
schema = "demo.yml"
mod_path = "out/nml_demo.f90"
doc_path = "out/nml_demo.md"

[[templates]]
output = "out/demo.nml"
schemas = ["demo.yml"]

Current limitations:

  • No derived types or complex types; only scalars and arrays of scalars
  • No nested objects or advanced JSON Schema features

Repo: GitHub - MuellerSeb/nml-tools: Toolbox for Fortran Namelists
Install: pip install nml-tools

Feedback is very welcome, especially on missing Fortran features, schema keywords, or ideas for better interoperability with existing namelist workflows.

6 Likes

And here a short demonstration on how to use the generated derived type representing a namelist:

program read_demo
  use nml_demo, only: nml_demo_t
  use nml_helper, only: NML_OK
  implicit none

  type(nml_demo_t) :: cfg
  integer :: stat
  character(len=256) :: errmsg

  stat = cfg%from_file("demo.nml", errmsg=errmsg)
  if (stat /= NML_OK) then
    write(*, *) "read failed: ", trim(errmsg)
    stop stat
  end if

  stat = cfg%is_valid(errmsg=errmsg)
  if (stat /= NML_OK) then
    write(*, *) "validation failed: ", trim(errmsg)
    stop stat
  end if

  write(*, *) "dice =", cfg%dice
end program read_demo