Generate Fortran namelist modules, Markdown docs, and template namelists from a small JSON Schema-like specification with Fortran-focused extensions.
- Schema input in YAML or JSON.
- Core keywords from JSON schema:
type,properties,required,default,examples,title,description. - Fortran extensions:
x-fortran-namelist,x-fortran-kind,x-fortran-len,x-fortran-shape,x-fortran-flex-tail-dims,x-fortran-default-*. - Outputs: Fortran module, helper module, Markdown docs, template namelist.
- Config-driven CLI for batching multiple schemas.
- No support for derived types:
- Only scalars and arrays of scalars are supported.
- Could be emulated with nested objects, but one would need to decide where the respective fortran types are defined or used from.
- No support for complex types:
- JSON doesn't have a native complex type.
- Could be emulated with:
- Lists of length 2 with metadata, like f90nml does for JSON conversion.
- Objects with
realandimagproperties. - Strings with a specific format like pydantic does.
These keywords extend JSON Schema with Fortran-specific requirements.
- Location: schema root.
- Type: string.
- Meaning: name of the Fortran namelist block.
Example:
x-fortran-namelist: optimization- Location: integer/number properties or array
items. - Type: string.
- Meaning: Fortran kind identifier (mapped via
[kinds]in the config). - If omitted, plain
integer/realis used.
Example:
count:
type: integer
x-fortran-kind: i4- Location: string properties or array
items. - Type: integer literal or identifier.
- Meaning: Fortran character length (
character(len=...)). - Identifiers must be defined in
[constants]in the config and be integers.
Example:
name:
type: string
x-fortran-len: buf- Location: array properties.
- Type: integer, identifier, or list of integers/identifiers.
- Meaning: Fortran array dimensions; identifiers are resolved via
[constants]. - Required; deferred-size dimensions are not supported.
- Nested arrays are not supported. Use a single array with a shape list for multi-dimensional arrays.
Example:
values:
type: array
x-fortran-shape: [3, 2, max_iter]
items:
type: number
x-fortran-kind: dp- Location: array properties.
- Type: integer.
- Meaning: number of trailing dimensions that may be shorter than the declared shape (0 disables flexibility).
- Must be between 0 and the array rank; only trailing dimensions are supported.
- Defaults and logical arrays are not supported for flexible arrays.
- The generated type exposes
filled_shape()to compute the used extent.
Example:
values:
type: array
x-fortran-shape: [3, 2, max_iter]
x-fortran-flex-tail-dims: 1
items:
type: number
x-fortran-kind: dp- Location: array properties with
default. - Type: string (
ForC, defaultF). - Meaning: memory order used when reshaping defaults.
Example:
x-fortran-default-order: C- Location: array properties with
default. - Type: boolean.
- Meaning: repeat the provided default values to fill the full shape.
- Array defaults must be lists; to broadcast a scalar, set
defaultonitemsinstead. - Cannot be used together with
x-fortran-default-pad.
Example:
x-fortran-default-repeat: true- Location: array properties with
default. - Type: scalar or list of scalars.
- Meaning: pad values used to fill the array if the default list is shorter than the shape.
- Cannot be used together with
x-fortran-default-repeat.
Example:
x-fortran-default-pad: 0Combined example:
values_repeat:
type: array
x-fortran-shape: [2, 3]
items:
type: integer
x-fortran-kind: i4
default: [1, 2]
x-fortran-default-repeat: true
values_pad_c:
type: array
x-fortran-shape: [2, 3]
items:
type: integer
x-fortran-kind: i4
default: [1, 2, 3]
x-fortran-default-order: C
x-fortran-default-pad: 0Only a subset of JSON Schema validation keywords is implemented.
Validation is opt-in: call is_valid() on the generated type to check required values, enum and bound constraints.
Enums are supported for strings and integers only.
For arrays, enums are defined on items (not on the array itself).
- Keywords:
enum - The generated Fortran module exposes public
*_enum_valuesarrays and elemental*_in_enumhelpers. - String enums compare against
trim(value); enum literals are stored with the field length.
You can add minimum/maximum constraints for integer or real values.
For arrays, the bounds apply to each item and must be defined on items.
- Keywords:
minimum,maximum,exclusiveMinimum,exclusiveMaximum - Applies to:
integerandnumber(realin Fortran) - For arrays: bounds belong on
items, not the array property
Example (scalars):
tolerance:
type: number
x-fortran-kind: dp
minimum: 0.0
exclusiveMaximum: 1.0Example (array items):
counts:
type: array
x-fortran-shape: 3
items:
type: integer
minimum: 1The CLI reads a TOML config file. Paths are resolved relative to the config file location.
Controls the generated helper module.
path(string, required to generate helper): output file for the helper module.module(string, optional): Fortran module name (default:nml_helper).buffer(int, optional): line buffer length for the helper module.header(string, optional): text inserted at the top of the helper file.
Named constants used for dimensions and string lengths.
- Each entry is a table with
value(int/float) and optionaldoc. - Values must be plain numbers (no kind suffixes).
Example:
[constants.max_iter]
value = 4
doc = "Maximum number of iterations."Defines the kind module and allowed kinds.
module(string): Fortran module touse.real(list of strings): allowed real kinds.integer(list of strings): allowed integer kinds.map(table, optional): schema kind name → module kind name.
Optional extra module documentation appended after the generated \brief and
\details. Multiline strings are supported and Doxygen formatting is allowed.
module(string, optional): extra module documentation block.md_doxygen_id_from_name(bool, optional): add{#<namelist>}to Markdown header (defaultfalse).md_add_toc_statement(bool, optional): insert[TOC]after the Markdown header (defaultfalse).
Schema entries to generate per-namelist outputs.
schema(string): schema file path.mod_path(string, optional): Fortran module output path.doc_path(string, optional): Markdown output path.
If a path is omitted, that output is not generated.
Template namelist output configuration.
output(string): template namelist output path.schemas(list of strings): schemas included in the template file.doc_mode:plainordocumented.value_mode:empty,filled,minimal-empty, orminimal-filled.
Optional values can override per-namelist fields for filled modes:
[templates.values.optimization]
niterations = 4
tolerance = 0.1The command line interface is available as nml-tools or nmlt.
Common flags: -h/--help, -V/--version, -v/-q (repeatable).
Primary subcommands:
generate: run the full pipeline (helper, Fortran modules, docs, templates).gen-fortran: generate helper + Fortran modules only.gen-markdown: generate Markdown docs only.gen-template: generate template namelists only.validate: validate a namelist file against schema definitions.
Generate all outputs:
nml-tools generate --config nml-config.tomlGenerate specific outputs:
nml-tools gen-fortran --config nml-config.toml
nml-tools gen-markdown --config nml-config.toml
nml-tools gen-template --config nml-config.tomlValidation is check-only (defaults are not applied) and implements only a subset of JSON Schema constraints (types, required, enums, bounds, string length, array shape/flex). Unknown keys in a namelist or namelist blocks not covered by provided schemas are errors.
Config-driven:
nml-tools validate --config nml-config.toml input.nmlSchema-only:
nml-tools validate --schema demo.yml --input demo.nml
nml-tools validate --schema a.yml --schema b.yml combined.nmlConstants are resolved from [constants] in the config, or provided ad hoc:
nml-tools validate --schema demo.yml --constants MAX_ITER=10 input.nmlArray values are validated as rectangular lists in Fortran order
(outer list corresponds to the last Fortran index), matching f90nml parsing.
Generated type-bound procedures return integer status codes and accept an
optional errmsg argument. No error stop is emitted by generated code.
Status codes (defined in the helper module):
| Code | Meaning |
|---|---|
NML_OK (0) |
success |
NML_ERR_FILE_NOT_FOUND (1) |
file does not exist |
NML_ERR_OPEN (2) |
failed to open file |
NML_ERR_NOT_OPEN (3) |
file not open |
NML_ERR_NML_NOT_FOUND (4) |
namelist not found |
NML_ERR_READ (5) |
read/parse error |
NML_ERR_CLOSE (6) |
close error |
NML_ERR_REQUIRED (10) |
required field missing |
NML_ERR_ENUM (11) |
enum constraint failed |
NML_ERR_NOT_SET (12) |
field not set (sentinel) |
NML_ERR_PARTLY_SET (13) |
array partially set |
NML_ERR_BOUNDS (14) |
bounds constraint failed |
NML_ERR_INVALID_NAME (20) |
unknown field name |
NML_ERR_INVALID_INDEX (21) |
invalid index for array access |
Notes:
errmsg, when present, is filled with a short message (includingiomsgon read errors).is_setreturnsNML_ERR_NOT_SETif a value is missing, andNML_ERR_INVALID_NAME/NML_ERR_INVALID_INDEXon misuse.
Generated Fortran doc-strings are currently tailored for Doxygen. Future versions may make this configurable to support other tools such as FORD or the Sphinx Fortran domain.
pip install nml-toolsSchema (demo.yml):
title: Demo namelist
description: Small example namelist for nml-tools.
x-fortran-namelist: demo
type: object
required: [count]
properties:
count:
type: integer
title: Number of steps
x-fortran-kind: i4
name:
type: string
title: Run label
x-fortran-len: 64
default: run1
weights:
type: array
title: Weight vector
x-fortran-shape: 3
items:
type: number
x-fortran-kind: dp
default: [0.1, 0.2, 0.3]Config (nml-config.toml):
[helper]
path = "out/nml_helper.f90"
module = "nml_helper"
buffer = 1024
[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"]
doc_mode = "documented"
value_mode = "filled"Generate outputs:
nml-tools generate --config nml-config.tomlExpected outputs:
out/nml_helper.f90out/nml_demo.f90out/nml_demo.mdout/demo.nml
This project implements a focused subset of JSON Schema aimed at Fortran namelist workflows, plus extensions for Fortran-specific types and shapes.
Main missing features compared to JSON Schema:
- No
$ref/$defsor remote schema resolution. - No composition keywords:
allOf,anyOf,oneOf,not. - No conditional keywords:
if/then/else. - No object constraints:
additionalProperties,patternProperties,propertyNames,dependencies. - No advanced array constraints: tuple typing,
contains,minItems,maxItems,uniqueItems. - No numeric or string validation keywords like
multipleOf,minLength,maxLength,pattern,format(bounds are supported viaminimum,maximum,exclusiveMinimum, andexclusiveMaximum). - No nested object schemas; properties are scalars or arrays of scalars only.
Use the x-fortran-* extensions to express kind, length, and shape information
needed for code generation.
