A Python module and command line tool for parsing, writing, and modifying Fortran 90 namelist files
—
High-level functions providing the primary interface for reading, writing, and modifying Fortran namelist files. These functions handle automatic type conversion, format detection, and provide the most convenient access to f90nml functionality.
Parse Fortran namelist files from disk or file objects, automatically converting Fortran data types to equivalent Python types.
def read(nml_path):
"""
Parse a Fortran namelist file and return its contents.
Args:
nml_path: str or file-like object - File path or file object to read from
Returns:
Namelist: Dictionary-like object containing parsed namelist data
Raises:
ValueError: If namelist syntax is invalid
IOError: If file cannot be read
"""Usage Examples:
# Read from file path
nml = f90nml.read('config.nml')
# Read from file object
with open('config.nml', 'r') as f:
nml = f90nml.read(f)
# Access nested values
input_file = nml['io_nml']['input_file']
timesteps = nml['run_nml']['timesteps']Parse Fortran namelist data directly from strings, useful for processing embedded configurations or dynamically generated namelists.
def reads(nml_string):
"""
Parse a Fortran namelist string and return its contents.
Args:
nml_string: str - String containing Fortran namelist syntax
Returns:
Namelist: Dictionary-like object containing parsed namelist data
Raises:
ValueError: If namelist syntax is invalid
"""Usage Examples:
# Parse simple namelist string
nml_str = '''
&run_config
timesteps = 100
dt = 0.01
output_freq = 10
/
'''
nml = f90nml.reads(nml_str)
# Parse complex data types
complex_str = '''
&data_nml
array = 1, 2, 3, 4, 5
matrix(1:2, 1:2) = 1.0, 2.0, 3.0, 4.0
use_feature = .true.
title = "Simulation Run"
/
'''
nml = f90nml.reads(complex_str)Save namelist data to disk with Fortran-compliant formatting, supporting both Namelist objects and Python dictionaries.
def write(nml, nml_path, force=False, sort=False):
"""
Save a namelist to disk using file path or file object.
Args:
nml: Namelist or dict - Namelist data to write
nml_path: str or file-like object - Output path or file object
force: bool - Overwrite existing files (default: False)
sort: bool - Sort namelist groups and variables alphabetically (default: False)
Raises:
IOError: If file exists and force=False, or file cannot be written
TypeError: If nml is not a valid namelist or dict
"""Usage Examples:
# Write to file path
nml = f90nml.read('input.nml')
nml['run_nml']['timesteps'] = 200
f90nml.write(nml, 'output.nml')
# Write to file object
with open('output.nml', 'w') as f:
f90nml.write(nml, f)
# Force overwrite existing file
f90nml.write(nml, 'output.nml', force=True)
# Write with sorted keys
f90nml.write(nml, 'output.nml', sort=True)
# Write Python dict as namelist
data = {
'config': {
'param1': 10,
'param2': 'value',
'param3': [1, 2, 3]
}
}
f90nml.write(data, 'generated.nml')Create modified versions of existing namelist files while preserving original formatting, comments, and structure. This is ideal for parameter studies and configuration management.
def patch(nml_path, nml_patch, out_path=None):
"""
Create a new namelist based on input namelist and reference dict.
Args:
nml_path: str - Path to original namelist file
nml_patch: dict - Dictionary of values to modify or add
out_path: str, optional - Output file path (default: input_path + '~')
Returns:
Namelist: The patched namelist object
Raises:
IOError: If input file cannot be read or output file cannot be written
ValueError: If patch contains invalid namelist data
"""Usage Examples:
# Simple value patching
patch_data = {
'run_config': {
'timesteps': 500,
'output_freq': 25
}
}
result = f90nml.patch('input.nml', patch_data, 'modified.nml')
# Patch with default output naming (input.nml -> input.nml~)
f90nml.patch('config.nml', patch_data)
# Add new variables to existing groups
patch_data = {
'existing_group': {
'new_parameter': 42,
'existing_parameter': 'updated_value'
}
}
f90nml.patch('base.nml', patch_data, 'patched.nml')
# Complex data type patching
complex_patch = {
'arrays_nml': {
'pressure_levels': [1000, 850, 700, 500, 300, 200, 100],
'use_advanced_solver': True,
'solver_tolerance': 1e-6
}
}
f90nml.patch('model.nml', complex_patch, 'updated_model.nml')f90nml automatically converts between Fortran and Python data types:
Fortran → Python:
.true./.false. → True/False123 → 123 (int)1.23 → 1.23 (float)'string' → 'string' (str)1, 2, 3 → [1, 2, 3] (list)(1.0, 2.0) → complex(1.0, 2.0)Python → Fortran:
True/False → .true./.false.123 → 1231.23 → 1.23'string' → 'string'[1, 2, 3] → 1, 2, 3complex(1.0, 2.0) → (1.0, 2.0)Common error scenarios and their handling:
# Handle file not found
try:
nml = f90nml.read('nonexistent.nml')
except IOError as e:
print(f"File error: {e}")
# Handle invalid namelist syntax
try:
nml = f90nml.reads('&invalid syntax')
except ValueError as e:
print(f"Parse error: {e}")
# Handle file overwrite protection
try:
f90nml.write(nml, 'existing.nml')
except IOError as e:
print(f"File exists, use force=True to overwrite")
f90nml.write(nml, 'existing.nml', force=True)Install with Tessl CLI
npx tessl i tessl/pypi-f90nml