Source code for fgen.data_models.unitless_value
"""
Data model of a value, excluding units
"""
from __future__ import annotations
from typing import Any
from attrs import define, field, validators
from fgen.fortran_parsing import FortranDataType
_NUMERIC_TYPE_STRINGS: list[str] = ["float", "int"]
"""
Strings that can appear in Python types that indicate that the Python type is numeric
"""
[docs]@define
class UnitlessValue:
"""
Data model of a value excluding units
This defines the value's Fortran data type and other metadata.
It also allows us to get the equivalent Python type.
"""
name: str
"""Name of the value"""
description: str
"""Description of the value"""
fortran_type: str = field(validator=[validators.instance_of(str)])
"""
The value's fortran type
The following built-in Fortran types are supported:
* integer
* real
* real(8)
* character
Some additional attributes are supported including:
* fixed length dimensions
* automatic explicit length dimensions
(e.g. using a variable "n" to specify the size of a dimension)
"""
is_fortran_units_holder: bool = False
"""
Is this value the attribute which specifies the units in the Fortran derived type?
If ``True``, it is not not included in Python wrappers,
instead being passed automatically to Fortran
based on the units extracted from :mod:`pint` quantities in Python.
"""
expose_getter_to_python: bool = True
"""
Should a getter for this value be exposed to Python?
If ``True``, we expose a getter for this value to Python, otherwise we don't.
"""
expose_setter_to_python: bool = False
"""
Should a setter for this value be exposed to Python?
If ``True``, we expose a setter for this value to Python, otherwise we don't.
"""
@fortran_type.validator
def _check_fortran_type(self, attribute: Any, value: str) -> None:
try:
FortranDataType.from_str(value)
except Exception as exc:
raise ValueError( # noqa: TRY003
f"Unsupported fortran type: {value}"
) from exc
@property
def is_numeric_type(self) -> bool:
"""
Whether this definition defines a numeric type or not
Returns
-------
``True`` if this definition defines a numeric type, ``False`` otherwise.
"""
pt = self.python_type_as_str()
return any(t in pt for t in _NUMERIC_TYPE_STRINGS)
@property
def is_python_str_type(self) -> bool:
"""
Whether this definition corresponds to a string
The concept of a string obviously only applies in Python.
In Fortran, the equivalent is a character type.
Returns
-------
``True`` if this definition defines a type
whose Python equivalent is string,
``False`` otherwise.
"""
pt = self.python_type_as_str()
return pt == "str"
@property
def is_python_bool_type(self) -> bool:
"""
Whether this definition corresponds to a boolean
The concept of a boolean obviously only applies in Python.
In Fortran, the equivalent is a logical type.
Returns
-------
``True`` if this definition defines a type
whose Python equivalent is boolean,
``False`` otherwise.
"""
pt = self.python_type_as_str()
return pt == "bool"
[docs] def as_fortran_data_type(self) -> FortranDataType:
"""
Convert ``self`` to its equivalent ``FortranDataType``
"""
return FortranDataType.from_str(self.fortran_type)
[docs] def python_type_as_str(self) -> str:
"""
Determine the string representation of the Python type
The python templator uses this function to translate a Python
type to a string so that it can correctly be read by Python.
If these type hints are converted to a string naively, the
corresponding string will not be able to be read by Python as a valid type hint.
Returns
-------
String representation of :attr:`python_type`
"""
return self.as_fortran_data_type().equivalent_python_type