Skip to content

script_builder.py

ofrak.gui.script_builder

ActionType (IntEnum)

An enumeration.

ScriptAction dataclass

Encapsulates the structure of a single action within the script, which consists of the string representation of the code for that action and the action's type.

ScriptBuilder

Builds and maintains runnable OFRAK scripts as sequences of actions, with each script tied to a session.

add_action(self, resource, action, action_type) async

Adds an action to the script session queue to which the selected resource belongs. An action is a string representing the code that is being run on the resource based on an action that has occurred in the GUI.

Actions are queued so that invalid actions which result in runtime exceptions within OFRAK do not make it into the final script. Once an action is queued and the corresponding OFRAK calls have run, the caller must explicitly call clear_script_queue or commit_to_script depending on whether an exception was raised or not, respectively.

Parameters:

Name Type Description Default
resource Resource

Resource upon which the action is being taken

required
action str

A string describing the code being run based on a GUI action

required
action_type ActionType

An instance of ActionType categorizing the action

required
Source code in ofrak/gui/script_builder.py
async def add_action(
    self,
    resource: Resource,
    action: str,
    action_type: ActionType,
) -> None:
    """
    Adds an action to the script session queue to which the selected resource belongs. An action
    is a string representing the code that is being run on the resource based on an action that
    has occurred in the GUI.

    Actions are queued so that invalid actions which result in runtime exceptions within OFRAK
    do not make it into the final script. Once an action is queued and the corresponding OFRAK
    calls have run, the caller must explicitly call `clear_script_queue` or `commit_to_script`
    depending on whether an exception was raised or not, respectively.

    :param resource: Resource upon which the action is being taken
    :param action: A string describing the code being run based on a GUI action
    :param action_type: An instance of `ActionType` categorizing the action
    """
    var_name = await self._add_variable(resource)
    qualified_action = action.format(resource=var_name)
    await self._add_action_to_session_queue(resource, qualified_action, action_type)

get_script(self, resource) async

Returns the most up-to-date version of the script for the session to which the resource belongs.

Parameters:

Name Type Description Default
resource Resource

Resource belonging to the session for which the script is to be returned

required

Returns:

Type Description
List[str]

List of strings where each entry is a line in the script

Source code in ofrak/gui/script_builder.py
async def get_script(self, resource: Resource) -> List[str]:
    """
    Returns the most up-to-date version of the script for the session to which the resource
    belongs.

    :param resource: Resource belonging to the session for which the script is to be returned

    :return: List of strings where each entry is a line in the script
    """
    root_resource = await self._get_root_resource(resource)
    return self._get_script(root_resource.get_id())

commit_to_script(self, resource) async

Commits the staged actions and variable names in the queue to the script session following a one or more valid actions being run.

Parameters:

Name Type Description Default
resource Resource

Resource belonging to the session whose queue will be committed

required
Source code in ofrak/gui/script_builder.py
async def commit_to_script(self, resource: Resource) -> None:
    """
    Commits the staged actions and variable names in the queue to the script session following
    a one or more valid actions being run.

    :param resource: Resource belonging to the session whose queue will be committed
    """
    root_resource = await self._get_root_resource(resource)
    session = self._get_session(root_resource.get_id())
    for id, name in session.resource_variable_names_queue.items():
        session.resource_variable_names[id] = name
    session.actions += session.actions_queue
    session.actions_queue = []
    session.resource_variable_names_queue = {}

clear_script_queue(self, resource) async

Clears the script session queue of all staged actions and variable names following an invalid action being run.

Parameters:

Name Type Description Default
resource Resource

Resource belonging to the session whose queue will be cleared

required
Source code in ofrak/gui/script_builder.py
async def clear_script_queue(self, resource: Resource) -> None:
    """
    Clears the script session queue of all staged actions and variable names following an
    invalid action being run.

    :param resource: Resource belonging to the session whose queue will be cleared
    """
    root_resource = await self._get_root_resource(resource)
    session = self._get_session(root_resource.get_id())
    session.actions_queue = []
    session.resource_variable_names_queue = {}

_add_variable(self, resource) async private

Replaces references to a particular resource selected in the GUI with a generated variable name based on uniquely identifying characteristics of the resource. This overcomes the issue of referencing the same resource across OFRAK contexts due to the randomly generated resource IDs changing.

Parameters:

Name Type Description Default
resource Resource

Resource that needs to be uniquely identified in the script

required

Returns:

Type Description
str

a unique variable name

Source code in ofrak/gui/script_builder.py
async def _add_variable(self, resource: Resource) -> str:
    """
    Replaces references to a particular resource selected in the GUI with a generated variable
    name based on uniquely identifying characteristics of the resource. This overcomes the issue
    of referencing the same resource across OFRAK contexts due to the randomly generated
    resource IDs changing.

    :param resource: Resource that needs to be uniquely identified in the script

    :return: a unique variable name
    """
    if await self._var_exists(resource):
        return await self._get_variable_from_session(resource)

    root_resource = await self._get_root_resource(resource)
    if resource.get_id() == root_resource.get_id():
        await self._add_variable_to_session_queue(resource, "root_resource")
        return "root_resource"

    parent = await resource.get_parent()
    if not await self._var_exists(parent):
        await self._add_variable(parent)

    name = ""
    # Cannot propagate exceptions to the server as this would interfere with user actions
    # regardless of whether they're interested in the script. Currently only _get_selector()
    # and _generate_name() can lead to exceptions raised within ScriptBuilder.
    try:
        selector = await self._get_selector(resource)
        name = await self._generate_name(resource)
        await self._add_action_to_session_queue(
            resource,
            rf"""
    {name} = {selector}""",
            ActionType.UNDEF,
        )
        await self._add_variable_to_session_queue(resource, name)
    except SelectableAttributesError as e:
        name = await self._generate_missing_name(resource, e)
        LOGGER.exception("Could not find selectable attributes for resource")
        return name
    except:
        LOGGER.exception("Exception raised in add_variable")
    return name

_get_root_resource(self, resource) async private

Maps a given resource to its root for efficient retrieval of the root resource because getting the root resource is likely the most performed operation in ScriptBuilder.

Source code in ofrak/gui/script_builder.py
async def _get_root_resource(self, resource: Resource) -> Resource:
    """
    Maps a given resource to its root for efficient retrieval of the root resource because
    getting the root resource is likely the most performed operation in `ScriptBuilder`.
    """
    resource_id = resource.get_id()
    if resource_id in self.root_cache:
        return self.root_cache[resource_id]
    ancestors = list(await resource.get_ancestors())
    root = ancestors[-1] if ancestors else resource
    self.root_cache[resource_id] = root
    return root

ScriptSession dataclass

A script, consisting of an ordered sequence of script actions and a mapping between resources and their autogenerated variable names.

SelectableAttributesError (Exception)

Prompt the user for an attribute to select with