A Python module and command line tool for parsing, writing, and modifying Fortran 90 namelist files
—
Low-level utility functions and specialized classes for advanced users who need fine-grained control over parsing, type conversion, and array indexing. These components provide the foundation for f90nml's robust Fortran namelist processing capabilities.
Functions for converting between Fortran and Python data types, handling the nuances of Fortran syntax and representation.
def pyfloat(v_str):
"""
Convert string representation of Fortran floating point to Python float.
Handles Fortran-specific exponential notation including 'D' and 'E' formats,
and implicit exponent signs.
Args:
v_str: str - String representation of Fortran floating point number
Returns:
float: Equivalent Python floating point value
Raises:
ValueError: If string cannot be converted to float
"""
def pycomplex(v_str):
"""
Convert string representation of Fortran complex number to Python complex.
Parses Fortran complex format: (real_part, imaginary_part)
Args:
v_str: str - String in format "(x.x, y.y)" representing complex number
Returns:
complex: Equivalent Python complex number
Raises:
ValueError: If string is not in valid complex format
"""
def pybool(v_str, strict_logical=True):
"""
Convert string representation of Fortran logical to Python boolean.
Supports various Fortran logical formats: .true./.false., .t./.f., true/false, t/f
Args:
v_str: str - String representation of Fortran logical value
strict_logical: bool - If True, requires Fortran logical format (default: True)
Returns:
bool: Equivalent Python boolean value
Raises:
ValueError: If string is not a valid logical constant
"""
def pystr(v_str):
"""
Convert string representation of Fortran string to Python string.
Handles quoted strings and escaped quote characters within strings.
Args:
v_str: str - Fortran string with or without delimiters
Returns:
str: Processed Python string with escaped quotes resolved
"""Usage Examples:
import f90nml.fpy as fpy
# Convert Fortran floating point formats
float_val = fpy.pyfloat('1.23E+4') # Scientific notation
float_val = fpy.pyfloat('1.23D-4') # Fortran double precision notation
float_val = fpy.pyfloat('1.23+4') # Implicit exponent sign
# Convert Fortran complex numbers
complex_val = fpy.pycomplex('(1.5, -2.3)') # Standard complex format
# Convert Fortran logical values
bool_val = fpy.pybool('.true.') # Standard Fortran format
bool_val = fpy.pybool('.t.') # Abbreviated format
bool_val = fpy.pybool('true', strict_logical=False) # Relaxed parsing
# Convert Fortran strings
str_val = fpy.pystr("'Hello World'") # Single-quoted string
str_val = fpy.pystr('"He said ""Hi"""') # Escaped quotesIterator class for traversing multidimensional arrays using Fortran's column-major indexing convention.
class FIndex:
"""
Column-major multidimensional index iterator.
Provides iteration over multidimensional array indices following
Fortran's column-major storage convention, essential for correctly
handling complex array assignments in namelists.
"""
def __init__(self, bounds, first=None):
"""
Initialize index iterator with dimension bounds.
Args:
bounds: list of tuples - [(start, end, step), ...] for each dimension
first: int, optional - Global starting index override
"""
def __iter__(self):
"""Return iterator object."""
def __next__(self):
"""
Get next index tuple in column-major order.
Returns:
tuple: Index coordinates for current position
Raises:
StopIteration: When all indices have been traversed
"""Usage Examples:
from f90nml.findex import FIndex
# Create iterator for 2D array with bounds (1:3, 1:2)
bounds = [(1, 4, 1), (1, 3, 1)] # (start, end+1, step)
idx_iter = FIndex(bounds)
# Iterate through indices in column-major order
for indices in idx_iter:
print(f"Array index: {indices}")
# Output: (1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)
# Handle arrays with custom starting indices
bounds = [(10, 13, 1), (5, 8, 1)] # Array(10:12, 5:7)
idx_iter = FIndex(bounds)
for indices in idx_iter:
print(f"Custom index: {indices}")
# Output: (10, 5), (11, 5), (12, 5), (10, 6), (11, 6), (12, 6), (10, 7), (11, 7), (12, 7)
# Handle step sizes for strided access
bounds = [(1, 10, 2), (1, 6, 2)] # Every other element
idx_iter = FIndex(bounds)
for indices in idx_iter:
print(f"Strided index: {indices}")
# Output: (1, 1), (3, 1), (5, 1), (7, 1), (9, 1), (1, 3), (3, 3), (5, 3), (7, 3), (9, 3), (1, 5), ...Tokenizer class for lexical analysis of Fortran namelist syntax, providing fine-grained control over parsing behavior.
class Tokenizer:
"""
Fortran namelist tokenizer for lexical analysis.
Provides low-level tokenization of Fortran namelist source code,
handling string parsing, comment recognition, and punctuation
according to Fortran language rules.
"""
def __init__(self):
"""Initialize tokenizer with default configuration."""
def parse(self, line):
"""
Tokenize a line of Fortran namelist source.
Args:
line: str - Line of Fortran source code to tokenize
Returns:
list: List of token strings from the input line
"""Usage Examples:
from f90nml.tokenizer import Tokenizer
# Create tokenizer
tokenizer = Tokenizer()
# Tokenize namelist lines
line = "&config_nml input='data.nc' steps=100 /"
tokens = tokenizer.parse(line)
print(tokens)
# Output: ['&', 'config_nml', 'input', '=', "'data.nc'", 'steps', '=', '100', '/']
# Handle complex expressions
line = "matrix(1:3, 2:4) = 1.0, 2.0, 3.0, 4.0, 5.0, 6.0"
tokens = tokenizer.parse(line)
print(tokens)
# Output: ['matrix', '(', '1', ':', '3', ',', '2', ':', '4', ')', '=', '1.0', ',', '2.0', ...]
# Configure comment tokens
tokenizer.comment_tokens = '!#' # Support both ! and # comments
line = "value = 42 # This is a comment"
tokens = tokenizer.parse(line)
print(tokens)
# Output: ['value', '=', '42', ' # This is a comment']These utilities are primarily used internally by f90nml but can be leveraged for advanced use cases:
# Custom parser with specialized type conversion
parser = f90nml.Parser()
parser.strict_logical = False # Enable relaxed boolean parsing
# Direct access to type conversion for validation
try:
value = f90nml.fpy.pyfloat(user_input)
print(f"Valid float: {value}")
except ValueError:
print("Invalid floating point format")
# Array iteration for custom processing
bounds = [(1, 4, 1), (1, 3, 1)]
for idx in f90nml.findex.FIndex(bounds):
# Process array element at index idx
process_element(idx)
# Custom tokenization for preprocessing
tokenizer = f90nml.tokenizer.Tokenizer()
tokenizer.comment_tokens = '!#%' # Custom comment characters
for line in source_lines:
tokens = tokenizer.parse(line)
# Process tokens before parsing
processed_tokens = preprocess(tokens)These utilities integrate seamlessly with the main f90nml functions:
read() and reads() during parsingFor most users, the high-level functions (read(), write(), patch()) provide sufficient functionality. These utilities are valuable for:
Install with Tessl CLI
npx tessl i tessl/pypi-f90nml