Skip to content

example_fgen_basic.runtime_helpers#

Runtime helpers

These would be moved to fgen-runtime or a similar package

Classes:

Name Description
FinalisableWrapperBase

Base class for Fortran derived type wrappers

Functions:

Name Description
add_attribute_row

Add a row for displaying an attribute's value to a list of rows

check_initialised

Check that the wrapper object has been initialised before executing the method

get_attribute_str_value

Get the string version of an attribute's value

to_html

Convert an instance to its html representation

to_pretty

Pretty-print an instance

to_str

Convert an instance to its string representation

Attributes:

Name Type Description
INVALID_INSTANCE_INDEX int

Value used to denote an invalid instance_index.

INVALID_INSTANCE_INDEX module-attribute #

INVALID_INSTANCE_INDEX: int = -1

Value used to denote an invalid instance_index.

This can occur value when a wrapper class has not yet been initialised (connected to a Fortran instance).

FinalisableWrapperBase #

Bases: ABC

Base class for Fortran derived type wrappers

Methods:

Name Description
__str__

Get string representation of self

Attributes:

Name Type Description
exposed_attributes tuple[str, ...]

Attributes exposed by this wrapper

initialized bool

Is the instance initialised, i.e. connected to a Fortran instance?

instance_index int

Model index of wrapper Fortran instance

Source code in src/example_fgen_basic/runtime_helpers.py
@define
class FinalisableWrapperBase(ABC):
    """
    Base class for Fortran derived type wrappers
    """

    instance_index: int = field(
        validator=attrs.validators.instance_of(int),
        default=INVALID_INSTANCE_INDEX,
    )
    """
    Model index of wrapper Fortran instance
    """

    def __str__(self) -> str:
        """
        Get string representation of self
        """
        return to_str(
            self,
            self.exposed_attributes,
        )

    def _repr_pretty_(self, p: Any, cycle: bool) -> None:
        """
        Get pretty representation of self

        Used by IPython notebooks and other tools
        """
        to_pretty(
            self,
            self.exposed_attributes,
            p=p,
            cycle=cycle,
        )

    def _repr_html_(self) -> str:
        """
        Get html representation of self

        Used by IPython notebooks and other tools
        """
        return to_html(
            self,
            self.exposed_attributes,
        )

    @property
    def initialized(self) -> bool:
        """
        Is the instance initialised, i.e. connected to a Fortran instance?
        """
        return self.instance_index != INVALID_INSTANCE_INDEX

    @property
    @abstractmethod
    def exposed_attributes(self) -> tuple[str, ...]:
        """
        Attributes exposed by this wrapper
        """
        ...

    # @classmethod
    # @abstractmethod
    # def from_new_connection(cls) -> FinalisableWrapperBase:
    #     """
    #     Initialise by establishing a new connection with the Fortran module
    #
    #     This requests a new model index from the Fortran module and then
    #     initialises a class instance
    #
    #     Returns
    #     -------
    #     New class instance
    #     """
    #     ...
    #
    # @abstractmethod
    # def finalize(self) -> None:
    #     """
    #     Finalise the Fortran instance and set self back to being uninitialised
    #
    #     This method resets ``self.instance_index`` back to
    #     ``_UNINITIALISED_instance_index``
    #
    #     Should be decorated with :func:`check_initialised`
    #     """
    #     # call to Fortran module goes here when implementing
    #     self._uninitialise_instance_index()

    def _uninitialise_instance_index(self) -> None:
        self.instance_index = INVALID_INSTANCE_INDEX

exposed_attributes abstractmethod property #

exposed_attributes: tuple[str, ...]

Attributes exposed by this wrapper

initialized property #

initialized: bool

Is the instance initialised, i.e. connected to a Fortran instance?

instance_index class-attribute instance-attribute #

instance_index: int = field(
    validator=instance_of(int),
    default=INVALID_INSTANCE_INDEX,
)

Model index of wrapper Fortran instance

__str__ #

__str__() -> str

Get string representation of self

Source code in src/example_fgen_basic/runtime_helpers.py
def __str__(self) -> str:
    """
    Get string representation of self
    """
    return to_str(
        self,
        self.exposed_attributes,
    )

add_attribute_row #

add_attribute_row(
    attribute_name: str,
    attribute_value: str,
    attribute_rows: list[str],
) -> list[str]

Add a row for displaying an attribute's value to a list of rows

Parameters:

Name Type Description Default
attribute_name str

Attribute's name

required
attribute_value str

Attribute's value

required
attribute_rows list[str]

Existing attribute rows

required

Returns:

Type Description
Attribute rows, with the new row appended
Source code in src/example_fgen_basic/runtime_helpers.py
def add_attribute_row(
    attribute_name: str, attribute_value: str, attribute_rows: list[str]
) -> list[str]:
    """
    Add a row for displaying an attribute's value to a list of rows

    Parameters
    ----------
    attribute_name
        Attribute's name

    attribute_value
        Attribute's value

    attribute_rows
        Existing attribute rows


    Returns
    -------
        Attribute rows, with the new row appended
    """
    attribute_rows.append(
        f"<tr><th>{attribute_name}</th><td style='text-align:left;'>{attribute_value}</td></tr>"  # noqa: E501
    )

    return attribute_rows

check_initialised #

check_initialised(
    method: Callable[Concatenate[Wrapper, P], T],
) -> Callable[Concatenate[Wrapper, P], T]

Check that the wrapper object has been initialised before executing the method

Parameters:

Name Type Description Default
method Callable[Concatenate[Wrapper, P], T]

Method to wrap

required

Returns:

Type Description
Callable[Concatenate[Wrapper, P], T]

Wrapped method

Raises:

Type Description
InitialisationError

Wrapper is not initialised

Source code in src/example_fgen_basic/runtime_helpers.py
def check_initialised(
    method: Callable[Concatenate[Wrapper, P], T],
) -> Callable[Concatenate[Wrapper, P], T]:
    """
    Check that the wrapper object has been initialised before executing the method

    Parameters
    ----------
    method
        Method to wrap

    Returns
    -------
    :
        Wrapped method

    Raises
    ------
    InitialisationError
        Wrapper is not initialised
    """

    @wraps(method)
    def checked(
        ref: Wrapper,
        *args: P.args,
        **kwargs: P.kwargs,
    ) -> Any:
        if not ref.initialized:
            raise NotInitialisedError(ref, method)

        return method(ref, *args, **kwargs)

    return checked  # type: ignore

get_attribute_str_value #

get_attribute_str_value(
    instance: FinalisableWrapperBase, attribute: str
) -> str

Get the string version of an attribute's value

Parameters:

Name Type Description Default
instance FinalisableWrapperBase

Instance from which to get the attribute

required
attribute str

Attribute for which to get the value

required

Returns:

Type Description
String version of the attribute's value, with graceful handling of errors.
Source code in src/example_fgen_basic/runtime_helpers.py
def get_attribute_str_value(instance: FinalisableWrapperBase, attribute: str) -> str:
    """
    Get the string version of an attribute's value

    Parameters
    ----------
    instance
        Instance from which to get the attribute

    attribute
        Attribute for which to get the value

    Returns
    -------
        String version of the attribute's value, with graceful handling of errors.
    """
    try:
        return f"{attribute}={getattr(instance, attribute)}"
    except UnallocatedMemoryError:
        # TODO: change this when we move to better error handling
        return f"{attribute} is unallocated"

to_html #

to_html(
    instance: FinalisableWrapperBase,
    exposed_attributes: Iterable[str],
) -> str

Convert an instance to its html representation

Parameters:

Name Type Description Default
instance FinalisableWrapperBase

Instance to convert

required
exposed_attributes Iterable[str]

Attributes from Fortran that the instance exposes

required

Returns:

Type Description
HTML representation of the instance
Source code in src/example_fgen_basic/runtime_helpers.py
def to_html(instance: FinalisableWrapperBase, exposed_attributes: Iterable[str]) -> str:
    """
    Convert an instance to its html representation

    Parameters
    ----------
    instance
        Instance to convert

    exposed_attributes
        Attributes from Fortran that the instance exposes

    Returns
    -------
        HTML representation of the instance
    """
    if not instance.initialized:
        return str(instance)

    if not exposed_attributes:
        return str(instance)

    instance_class_name = repr(instance).split("(")[0]

    attribute_rows: list[str] = []
    for att in exposed_attributes:
        try:
            att_val = getattr(instance, att)
        except UnallocatedMemoryError:
            # TODO: change this when we move to better error handling
            att_val = "Unallocated"
            attribute_rows = add_attribute_row(att, att_val, attribute_rows)
            continue

        try:
            att_val = att_val._repr_html_()
        except AttributeError:
            att_val = str(att_val)

        attribute_rows = add_attribute_row(att, att_val, attribute_rows)

    attribute_rows_for_table = "\n          ".join(attribute_rows)

    css_style = """.fgen-wrap {
  /*font-family: monospace;*/
  width: 540px;
}

.fgen-header {
  padding: 6px 0 6px 3px;
  border-bottom: solid 1px #777;
  color: #555;;
}

.fgen-header > div {
  display: inline;
  margin-top: 0;
  margin-bottom: 0;
}

.fgen-basefinalizable-cls,
.fgen-basefinalizable-instance-index {
  margin-left: 2px;
  margin-right: 10px;
}

.fgen-basefinalizable-cls {
  font-weight: bold;
  color: #000000;
}"""

    return "\n".join(
        [
            "<div>",
            "  <style>",
            f"{css_style}",
            "  </style>",
            "  <div class='fgen-wrap'>",
            "    <div class='fgen-header'>",
            f"      <div class='fgen-basefinalizable-cls'>{instance_class_name}</div>",
            f"        <div class='fgen-basefinalizable-instance-index'>instance_index={instance.instance_index}</div>",  # noqa: E501
            "        <table><tbody>",
            f"          {attribute_rows_for_table}",
            "        </tbody></table>",
            "    </div>",
            "  </div>",
            "</div>",
        ]
    )

to_pretty #

to_pretty(
    instance: FinalisableWrapperBase,
    exposed_attributes: Iterable[str],
    p: Any,
    cycle: bool,
    indent: int = 4,
) -> None

Pretty-print an instance

Parameters:

Name Type Description Default
instance FinalisableWrapperBase

Instance to convert

required
exposed_attributes Iterable[str]

Attributes from Fortran that the instance exposes

required
p Any

Pretty printing object

required
cycle bool

Whether the pretty printer has detected a cycle or not.

required
indent int

Indent to apply to the pretty printing group

4
Source code in src/example_fgen_basic/runtime_helpers.py
def to_pretty(
    instance: FinalisableWrapperBase,
    exposed_attributes: Iterable[str],
    p: Any,
    cycle: bool,
    indent: int = 4,
) -> None:
    """
    Pretty-print an instance

    Parameters
    ----------
    instance
        Instance to convert

    exposed_attributes
        Attributes from Fortran that the instance exposes

    p
        Pretty printing object

    cycle
        Whether the pretty printer has detected a cycle or not.

    indent
        Indent to apply to the pretty printing group
    """
    if not instance.initialized:
        p.text(str(instance))
        return

    if not exposed_attributes:
        p.text(str(instance))
        return

    with p.group(indent, f"{repr(instance)[:-1]}", ")"):
        for att in exposed_attributes:
            p.text(",")
            p.breakable()

            p.text(get_attribute_str_value(instance, att))

to_str #

to_str(
    instance: FinalisableWrapperBase,
    exposed_attributes: Iterable[str],
) -> str

Convert an instance to its string representation

Parameters:

Name Type Description Default
instance FinalisableWrapperBase

Instance to convert

required
exposed_attributes Iterable[str]

Attributes from Fortran that the instance exposes

required

Returns:

Type Description
String representation of the instance
Source code in src/example_fgen_basic/runtime_helpers.py
def to_str(instance: FinalisableWrapperBase, exposed_attributes: Iterable[str]) -> str:
    """
    Convert an instance to its string representation

    Parameters
    ----------
    instance
        Instance to convert

    exposed_attributes
        Attributes from Fortran that the instance exposes

    Returns
    -------
        String representation of the instance
    """
    if not instance.initialized:
        return f"Uninitialised {instance!r}"

    if not exposed_attributes:
        return repr(instance)

    attribute_values = [
        get_attribute_str_value(instance, v) for v in exposed_attributes
    ]

    return f"{repr(instance)[:-1]}, {', '.join(attribute_values)})"