# Nml-tools v0.3: schema-driven Fortran namelist helpers

**URL:** <https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945>\
**Category:** Announcements\
**Created:** [June 3, 2026, 6:57pm UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945 "2026-06-03T18:57:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![MuellerSeb](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/muellerseb/32/7568_2.png) [@MuellerSeb](https://fortran-lang.discourse.group/u/MuellerSeb)\
**Post date:** [June 3, 2026, 6:57pm UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/1 "2026-06-03T18:57:40Z")

</div>

I would like to share a short update on [`nml-tools`](https://github.com/MuellerSeb/nml-tools/), a small Python tool that generates Fortran namelist modules from YAML/JSON schema-like files.

The idea is to describe each namelist once and generate the repetitive pieces from that description: Fortran declarations, `init` / `set` / `from_file` helpers, validation, Markdown documentation, template namelist files, and optionally f2py/Python wrapper code.

It is available on PyPI:

```bash
pip install nml-tools

```

## Basic Example

A schema describes the namelist block and its entries:

```yaml
title: Optimization settings
x-fortran-namelist: optimization
type: object
required: [max_iter]
properties:
  max_iter:
    type: integer
    x-fortran-kind: i4
    default: 100
  method:
    type: string
    x-fortran-len: 16
    enum: [bfgs, nelder_mead]
    default: bfgs

```

With a small project config, `nml-tools generate --config nml-config.toml` can emit the Fortran module, documentation, and a template namelist.

The config can be a standalone `nml-config.toml` file or a `[tool.nml-tools]` section inside `pyproject.toml`, which is convenient for Python/f2py packages.

## Reusable Schema Definitions

Version 0.3 adds `$defs` / `$ref` support, so common field definitions can be shared between namelists:

```yaml
$defs:
  positive_count:
    type: integer
    minimum: 1
    x-fortran-kind: i4

properties:
  n_steps:
    $ref: "#/$defs/positive_count"
    description: Number of time steps.

```

References can also point to local YAML/JSON files next to the schema, which is useful for larger applications with several namelists.

## One-Level Derived Types

`nml-tools` can now model one level of Fortran derived-type fields. A type can be generated into the helper module or imported from an application module:

```yaml
properties:
  period:
    type: object
    x-fortran-type: period_t
    required: [start_year, end_year]
    properties:
      start_year:
        type: integer
      end_year:
        type: integer

```

Generated namelist input uses normal Fortran component syntax:

```fortran
&run
  period%start_year = 2001
  period%end_year = 2010
/

```

For now this is deliberately conservative: derived-type members must be scalar intrinsic values, and nested derived types or array members are not supported.

## f2py/Python Wrappers

For projects that expose Fortran configuration to Python, v0.3 can generate f2py-facing wrapper code and a small Python shim. The Python API keeps derived values natural:

```python
cfg.set(
    period={"start_year": 2001, "end_year": 2010},
    method="bfgs",
)

```

Internally the f2py ABI stays intrinsic-only, avoiding derived-type dummy arguments across the Python/Fortran boundary. The generated wrapper works with Fortran-owned configuration objects through opaque integer handles, so Python does not need to know the layout of the generated Fortran type.

## File Profiles And Templates

There is also better support for projects where one physical namelist file contains several namelist blocks:

```toml
[[namelists]]
name = "run"
schema = "schemas/run.yml"

[[namelists]]
name = "physics"
schema = "schemas/physics.yml"

[[file_profiles]]
name = "main"
default_file = "run.nml"
namelists = ["run", "physics"]

[[templates]]
path = "templates/run.nml"
profile = "main"
doc_mode = "documented"
value_mode = "filled"

```

This lets generated templates and validation operate on the same named file layout.

The repository contains small reference examples for the main workflows, including plain Fortran generation, f2py packaging, `$ref` reuse, derived types, and multi-namelist file profiles.

Feedback from Fortran users would be very welcome, especially around the schema syntax, derived-type restrictions, and what a convenient namelist editing workflow should look like.

---

<div class="post-metadata">

**Author:** ![jorgeg](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jorgeg/32/6835_2.png) [@jorgeg](https://fortran-lang.discourse.group/u/jorgeg)\
**Post date:** [June 3, 2026, 9:54pm UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/2 "2026-06-03T21:54:03Z")

</div>

this is great, I recently discovered namelist files and instead of reinventing the wheel to read weird input files in Fortran I’ve done something similar to this. I use python to read something like json or yaml and translate it.

Does your package have a schema enforcing option? i.e. fail if it detects a key that is not allowed?

---

<div class="post-metadata">

**Author:** ![btrettel](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@btrettel](https://fortran-lang.discourse.group/u/btrettel)\
**Post date:** [June 4, 2026, 12:38am UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/3 "2026-06-04T00:38:03Z")

</div>

This is great! I wish I knew about this earlier. I had been developing my own tool, [geninput](https://github.com/btrettel/flt/blob/main/app/geninput.f90), to simultaneously generate namelist boilerplate code and LaTeX documentation. nml-tools is a lot more polished than geninput and has more features. One feature geninput has that I didn’t see mentioned in the README is the ability to specify the unit of the key, which I suggest adding.

The earliest input code generation tool I’ve seen for Fortran was discussed in the book [Writing good software in FORTRAN](https://lccn.loc.gov/87018692) by Graham Smith back in 1988. But Smith’s system doesn’t generate both code and documentation.

---

<div class="post-metadata">

**Author:** ![MuellerSeb](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/muellerseb/32/7568_2.png) [@MuellerSeb](https://fortran-lang.discourse.group/u/MuellerSeb)\
**Post date:** [June 4, 2026, 7:46am UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/4 "2026-06-04T07:46:39Z")

</div>

Thank you!

Yes, this error is catched during reading (since the namelist read fails by the Fortran standard) and a `NML_ERR_READ` error code is returned with the compiler dependent io-error message from the namelist read.

The part I was missing in namelist reading was the opposite: non present variables can’t be detected in a canonical way. That was the main motivation for me to develop nml-tools.  
This is done by setting type specific sentinels and checking for them after the namelist read.

And this helps with the schema enforcing: required variables need to overwrite the sentinel and simple restrictions like min/max/enum-values are also implemented (following json-schema).

---

<div class="post-metadata">

**Author:** ![MuellerSeb](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/muellerseb/32/7568_2.png) [@MuellerSeb](https://fortran-lang.discourse.group/u/MuellerSeb)\
**Post date:** [June 4, 2026, 7:50am UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/5 "2026-06-04T07:50:16Z")

</div>

Thank you! Since units are only meta-data to me (integration into a unit-handling framework is out of scope for nml-tools), I would not create a mechanism for unit handling (also, since I want to stay close to json-schema).

From my POV, units should be documented in the description, or maybe more prominently in the title of a variable.

---

<div class="post-metadata">

**Author:** ![btrettel](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@btrettel](https://fortran-lang.discourse.group/u/btrettel)\
**Post date:** [June 4, 2026, 1:09pm UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/6 "2026-06-04T13:09:06Z")

</div>

Another suggestion would be to make one of the example generated Markdown documentation files more prominent. The advantage of generating consistent code and documentation will become a lot more clear to people if they look at [this example](https://github.com/MuellerSeb/nml-tools/blob/main/examples/01_simple/out/nml_optimization.md) already in the repo, for instance. (Here’s [an example from my own system, geninput](http://trettel.us/blastersim/docs/pneumatic.html#pneumatic-namelist). It’s fairly different. I should add the key bounds to the generated documentation now that I’m comparing against nml-tools.)

I’ve maintained consistent namelist processing code including input validation and LaTeX documentation before, and it can be a pain. The documentation is often out of sync with the code or even incorrect. But in this case, the two are perfectly in sync. In my geninput system, I think at some point I found a bug in the code from reading the documentation, where if the two were not synchronized then the documentation likely would have reflected what was intended, hiding the bug.

---

<div class="post-metadata">

**Author:** ![MuellerSeb](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/muellerseb/32/7568_2.png) [@MuellerSeb](https://fortran-lang.discourse.group/u/MuellerSeb)\
**Post date:** [June 8, 2026, 12:40pm UTC](https://fortran-lang.discourse.group/t/nml-tools-v0-3-schema-driven-fortran-namelist-helpers/10945/7 "2026-06-08T12:40:23Z")

</div>

Agree. Currently the whole package documentation is in the readme. A dedicated RTD page would be a good idea for the future with in-depth discussion of features.
