CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-f90nml

A Python module and command line tool for parsing, writing, and modifying Fortran 90 namelist files

Pending
Overview
Eval results
Files

namelist-objects.mddocs/

Namelist Objects and Formatting

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.

Capabilities

Namelist Class

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}
}

Writing and File Operations

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)

Data Manipulation Methods

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}")

Formatting Properties

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')

Cogroup Handling

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 cogroup

Usage 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})

Advanced Features

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')

Type Conversion and Validation

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}
]

Error Handling

# 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

docs

command-line.md

core-parsing.md

index.md

namelist-objects.md

parser-configuration.md

utility-functions.md

tile.json