A Python module and command line tool for parsing, writing, and modifying Fortran 90 namelist files
—
Dictionary-like container objects that represent Fortran namelists in Python with extensive formatting controls for generating Fortran-compliant output. Namelist objects extend Python's OrderedDict with specialized methods and properties for scientific computing workflows.
The primary container for namelist data, providing dictionary-like access with Fortran-specific functionality.
class Namelist(OrderedDict):
"""
Representation of Fortran namelist in Python environment.
Extends OrderedDict with Fortran-specific methods and formatting controls.
Automatically converts nested dicts to Namelist objects and handles
complex Fortran features like derived types and multidimensional arrays.
"""
def __init__(self, *args, default_start_index=None, **kwds):
"""
Create Namelist object from dict-like data.
Args:
*args: Positional arguments passed to OrderedDict
default_start_index: int, optional - Default start index for arrays
**kwds: Keyword arguments passed to OrderedDict
"""Usage Examples:
# Create from dictionary
data = {'config': {'param': 10, 'values': [1, 2, 3]}}
nml = f90nml.Namelist(data)
# Create with default start index
nml = f90nml.Namelist(data, default_start_index=0)
# Dictionary-like access
nml['new_group'] = {'setting': 'value'}
print(nml['config']['param'])
# Automatic dict-to-Namelist conversion
nml['derived_type'] = {
'field1': 100,
'field2': 'text',
'nested': {'subfield': 42}
}Save namelist data to files with extensive formatting control.
def write(self, nml_path, force=False, sort=False):
"""
Write Namelist to a Fortran 90 namelist file.
Args:
nml_path: str or file-like object - Output path or file object
force: bool - Overwrite existing files (default: False)
sort: bool - Sort keys alphabetically (default: False)
Raises:
IOError: If file exists and force=False
"""Usage Examples:
nml = f90nml.read('input.nml')
# Write to file
nml.write('output.nml')
# Write with sorting
nml.write('sorted_output.nml', sort=True)
# Write to file object
with open('custom.nml', 'w') as f:
nml.write(f)Specialized methods for working with namelist data structures.
def patch(self, nml_patch):
"""
Update the namelist from another partial or full namelist.
Different from update() - merges values within sections rather
than replacing entire sections.
Args:
nml_patch: dict or Namelist - Data to merge into this namelist
"""
def todict(self, complex_tuple=False):
"""
Return a standard dict equivalent to the namelist.
Args:
complex_tuple: bool - Convert complex numbers to 2-tuples (default: False)
Returns:
dict: Standard Python dictionary with metadata preserved
"""
def groups(self):
"""
Return iterator spanning values with group and variable names.
Yields:
tuple: ((group_name, variable_name), value) pairs
"""Usage Examples:
# Patch existing namelist
base_nml = f90nml.read('base.nml')
updates = {'config': {'new_param': 50}}
base_nml.patch(updates)
# Convert to standard dict
nml_dict = nml.todict()
# Convert with complex number handling for JSON serialization
json_dict = nml.todict(complex_tuple=True)
# Iterate over all variables
for (group, var), value in nml.groups():
print(f"{group}.{var} = {value}")Extensive formatting controls for customizing Fortran output appearance.
# Layout and spacing
column_width: int # Maximum characters per line (default: 72)
indent: str # Indentation string (default: ' ')
end_comma: bool # Append commas to entries (default: False)
assign_spacing: bool # Space around '=' (default: True)
index_spacing: bool # Space between array indices (default: False)
# Data representation
uppercase: bool # Uppercase names (default: False)
logical_repr: dict # Boolean string representations
true_repr: str # True value representation (default: '.true.')
false_repr: str # False value representation (default: '.false.')
float_format: str # Float formatting string (default: '')
# Array handling
default_start_index: int # Default array start index (default: None)
start_index: dict # Per-variable start indices
repeat_counter: bool # Use repeat syntax like '3*value' (default: False)
split_strings: bool # Split long strings (default: False)Usage Examples:
nml = f90nml.read('input.nml')
# Customize formatting
nml.column_width = 80
nml.indent = ' ' # 2 spaces instead of 4
nml.uppercase = True
nml.end_comma = True
# Customize logical representations
nml.true_repr = 'T'
nml.false_repr = 'F'
# or
nml.logical_repr = {True: 'T', False: 'F'}
# Float formatting
nml.float_format = '.3f' # 3 decimal places
# Array formatting
nml.repeat_counter = True # Use 3*1.0 instead of 1.0, 1.0, 1.0
nml.default_start_index = 0 # 0-based indexing
# Write with custom formatting
nml.write('formatted_output.nml')Support for namelist files with duplicate group names (cogroups).
def create_cogroup(self, group_name):
"""Convert an existing namelist group to a cogroup."""
def add_cogroup(self, key, val):
"""Append a duplicate group to the Namelist as a new group."""
class Cogroup(list):
"""List of Namelist groups which share a common key."""
def __init__(self, nml, key, *args, **kwds):
"""Generate list of cogroups linked to parent namelist."""
def update(self, args):
"""Update all cogroup elements with new values."""
keys: list # List of internal keys for this cogroupUsage Examples:
# Handle multiple groups with same name
nml_text = '''
&config
param1 = 10
/
&config
param2 = 20
/
'''
nml = f90nml.reads(nml_text)
# Access cogroup
config_groups = nml['config'] # Returns Cogroup object
print(len(config_groups)) # 2
# Access individual groups
first_config = config_groups[0]
second_config = config_groups[1]
# Update all groups in cogroup
config_groups.update({'shared_param': 100})
# Add new cogroup
nml.add_cogroup('config', {'param3': 30})Specialized functionality for complex Fortran namelist features.
class RepeatValue:
"""Container class for output using repeat counters."""
def __init__(self, n, value):
"""
Create RepeatValue for repeated data.
Args:
n: int - Number of repetitions
value: any - Value to repeat
"""
repeats: int # Number of repetitions
value: any # Value being repeated
class NmlKey(str):
"""String containing internal key for duplicate key handling."""
def __new__(cls, value='', *args, **kwargs):
"""Create NmlKey with internal key storage."""Usage Examples:
# Work with repeat values when repeat_counter is enabled
nml = f90nml.Namelist()
nml.repeat_counter = True
nml['data'] = {'array': [1, 1, 1, 2, 2]} # Will output as: 3*1, 2*2
# Handle special keys for duplicate groups
for key in nml.keys():
if isinstance(key, f90nml.NmlKey):
print(f"Internal key: {key._key}, Display key: {key}")
# Working with cogroups in complex scenarios
nml_complex = '''
&solver_config
method = 'CG'
tolerance = 1e-6
/
&solver_config
method = 'GMRES'
tolerance = 1e-8
max_iter = 100
/
&solver_config
method = 'BiCGSTAB'
tolerance = 1e-10
/
'''
nml = f90nml.reads(nml_complex)
# Iterate through all solver configurations
solver_configs = nml['solver_config']
for i, config in enumerate(solver_configs):
print(f"Solver {i+1}: {config['method']}, tol={config['tolerance']}")
# Update specific cogroup member
solver_configs[1]['preconditioner'] = 'ILU'
# Convert cogroup back to individual namelists
for i, config in enumerate(solver_configs):
config.write(f'solver_{i+1}.nml')Automatic handling of Python to Fortran type conversion:
# Automatic type promotion
nml = f90nml.Namelist()
nml['data'] = {
'integer': 42,
'float': 3.14159,
'boolean': True,
'string': 'hello world',
'array': [1, 2, 3, 4, 5],
'complex': complex(1.0, 2.0)
}
# Nested dict becomes nested Namelist
nml['derived'] = {
'field1': 10,
'nested': {
'subfield': 'value'
}
}
# Array of dicts becomes array of Namelists
nml['particles'] = [
{'x': 1.0, 'y': 2.0},
{'x': 3.0, 'y': 4.0}
]# Invalid formatting parameters
try:
nml.column_width = -1 # Invalid
except ValueError as e:
print("Column width must be non-negative")
try:
nml.indent = "invalid" # Must be whitespace only
except ValueError as e:
print("Indent must contain only whitespace")
# File writing errors
try:
nml.write('/invalid/path/file.nml')
except IOError as e:
print(f"Cannot write file: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-f90nml