Solution API#

This section documents GLOW’s Solution API which enable the construction of a GLOW Solution (a Guided Workflow Application). The GLOW infrastructure can provide a remote GLOW server that provides the guided workflow service for a given GLOW solution.

exception ansys.saf.glow.solution.BadRequestError(detail: str)#

Bases: GlowErrorBase

The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, size too large, invalid request message framing, or deceptive request routing).

exception ansys.saf.glow.solution.ConflictError(detail: str)#

Bases: GlowErrorBase

Indicates that the request could not be processed because of conflict in the current state of the resource, such as an edit conflict between multiple simultaneous updates.

class ansys.saf.glow.solution.EntityHandle(*, is_blob: bool, original_name: str | None = None, entity_id: UUID, opaque_identifier: str, mime_type: str | None = None, encoding: str | None = None, size: int | None = None)#

Bases: BaseModel

A handle to a entity stored by a BDM provider and the associated lightweight data about it.

This lightweight, immutable object is intended to be easy to serialize and pass around across processes, services, and hosts. The actual behavior of the entity contents is up to the IStorageScope or IAsyncStorageScope.

encoding: str | None#

The Internet Assigned Numbers Authority (IANA) registered encoding name used for textual data.

This may be None if not known and should not be set for binary mime types.

This encoding name may be passed to other languages and implementations. IANA registered encoding names MUST be used.

entity_id: UUID#

A unique id that identifies the entity.

Typically this value is a new, random Guid created at the moment that the Entityandle is created from contents such as a file on disk. It should be preserved across clone and save/load operations. It is not guaranteed to be the same value if you read the same contents into an BlobHandle twice.

The UUID ‘00000000-0000-0000-0000-000000000000’ is reserved for NO_ENTITY.

is_blob: bool#

True if this entity refers to a blob. False if it refers to a collection of blobs.

mime_type: str | None#

The mime type of the data, if it is known. None otherwise.

model_config = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

opaque_identifier: str#

A custom identifier that the IStorageScope can use to identify the handle. Opaque as each BDM system may have its own form for this field. Consumers are not to assume anything about this field, even if it looks parseable.

original_name: str | None#

The original filename of the entity.

This is just the filename and does not include the path. May be None or empty if not known. May not refer to a file on the local system.

size: int | None#

Size of the data in bytes, if known.

Size must be None if is_blob is False.

Note that 0 is a valid blob size and has a different meaning than None.

class ansys.saf.glow.solution.FieldState(*values)#

Bases: StrEnum

Indicates the state of a given field in a given project. Notes —– the corresponding section explains the field state concept in more detail.

OUTOFDATE = 'OUTOFDATE'#

Indicates that the current value of the given field is potentially incorrect (inconsistent with the values of fields of which it is directly and indirectly dependent).

UPTODATE = 'UPTODATE'#

Indicates that the current value of the given field is correct (consistent with the values of fields of which it is directly and indirectly dependent).

exception ansys.saf.glow.solution.ForbiddenError(detail: str)#

Bases: GlowErrorBase

The request contained valid data and was understood by the server, but the server is refusing action. This may be due to the user not having the necessary permissions for a resource or needing an account of some sort, or attempting a prohibited action (e.g. creating a duplicate record where only one is allowed).

class ansys.saf.glow.solution.InstanceManager(**kwargs: Any)#

Bases: InstanceManagerBase[TRecoveryStateInfo], IInstanceManager[TProductClient], Generic[TProductClient, TRecoveryStateInfo]

Base class for all internal implementation of product instance managers. Derived classes provide facilities for creating and accessing product instances. The typevar TProductClient is the client class for the product managed by an InstanceManager derived class. This class must only be used for internal instance manager implementation but must not be exposed publicly to the solution.

Parameters:
instance_identificationAbstractInstanceIdentificationClient

Provides access to persisted data on a specific product instance.

method_directoryAbstractStoragePath, optional

The method file space for the method that is being executed. If it is not set, then the manager will assume it is being used outside the context of a method.

project_directory_path_on_solutionAbstractStoragePath, optional

The project files directory, which contains the product state directory. If it is not set, then the manager will assume it is being used in a desktop deployment.

max_execution_timeint, optional

Amount of time (in seconds) after which an instance managed by Ansys HPS will be shutdown. If not set, the value is set to 7200 seconds (2 hours).

Notes

It is not expected that GLOW transaction methods or GLOW clients will directly use the constructors of InstanceManager or classes derived from it. Instead, a class derived from ProductInstanceManager should be passed as an argument to each create_instance() decorator to indicate the type of product instance to create and the Client API to be used to access the created instance.

By convention derived classes implement an initialize method that has arguments specific to a given product that allow the transaction method to determine the initial state of the product instance.

the corresponding section explains the concept of product instances in more detail.

close_client() → None#

Close the product client.

close_client_object_implement() → None#

Close the product specific client object.

(Use self.instance to access the client from within this method) Subclasses may implement the logic needed to dispose the client object. This is particularly important for clients that can be created with the with statement, since it usually means that there is some disposal to do at the end. In this case, create the client without using the with in get_client_object_implement and call the dispose/close method here.

Does not raise NotImplementedError() to avoid breaking changes with existing custom managers that would fail to be constructed otherwise.

abstractmethod get_client_object_implement(hostname: str, port: int) → TProductClient#

Return the product specific client object that provides the managed product’s API.

The client object is what will be exposed by the manager’s instance property in a @transaction method. Subclasses must implement the logic to create a client exposing the product instance API.

Parameters:
hostname: str

The hostname on which the product is running.

port: int

The port on which the product is running.

property instance: TProductClient#

The product specific client object that provides the managed product’s API.

Returns:
TProductClient

The product specific client object that provides the managed product’s API.

class ansys.saf.glow.solution.MethodIdentifier(step_name: str, method_name: str)#

Bases: object

A reference to a transaction method in a Solution derived class.

Parameters:
step_namestr

Name of the step containing the method. A ‘step’ is a field on a StepsModel derived class. The name of a step is the name of the field. The StepsModel derived class is the type of the steps field which defines the set of steps in a Solution derived class.

method_namestr

The Python identifier of the method on the step.

Notes

the corresponding section explains the transaction method concept in more detail.

property method_name: str#

Name of the method.

Returns:
str

Name of the method.

property step_name: str#

Name of the step containing the method.

Returns:
str

Name of the step containing the method. A ‘step’ is a field on a StepsModel derived class. The name of a step is the name of the field. The StepsModel derived class is the type of the steps field which defines the set of steps in a Solution derived class.

class ansys.saf.glow.solution.MethodState(*, status: MethodStatus, result: Any | None = None, status_code: int | None = None, exception_message: str | None = None, exception_stack: str | None = None)#

Bases: BaseModel

The state of a transaction method in the context of a project. Notes —– the corresponding section explains the transaction method concept in more detail.

exception_message: str | None#

If an error occurred (status is Failed), then this field contains the exception message for the failure.

If status is not Failed, then this field is None.

exception_stack: str | None#

If an error occurred (status is Failed), then this field contains the stack trace for the failure.

If status is not Failed, then this field is None.

model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

raise_for_error(exceptions_by_code: dict[int, type[Exception]])#

Raise an exception base on the status_code if an error occurred (when status is Failed).

result: Any | None#

The value returned by the method, if any.

status: MethodStatus#

The state of the method.

status_code: int | None#

If an error occurred, this field indicates the result of the method execution encoded according to the HTTP response status code standard.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status.

class ansys.saf.glow.solution.MethodStatus(*values)#

Bases: StrEnum

The execution state of a transaction method in the context of a project. Notes —– the corresponding section explains the transaction method concept in more detail.

Completed = 'completed'#

The last execution of the method in the project was successful.

The method has run at least once in the project.

Failed = 'failed'#

The last execution of the method in the project failed.

The method has run at least once in the project.

RunRequired = 'run-required'#

The method has never been run in the project.

Running = 'running'#

The method is currently running in the project.

class ansys.saf.glow.solution.Migration(*, version: int, migration_transformation: MigrationTransformation)#

Bases: BaseModel

This class links a specific solution migration with the solution version to which this migration should be applied.

model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ansys.saf.glow.solution.MigrationContext(solution: dict[str, Any], project_storage_scope: IStorageScope, file_manager: ProjectFilesManager, project_id: str, settings: Settings)#

Bases: object

This class defines the API to perform the migration of a solution and stores the solution to be migrated.

create_entity_handle(path_to_existing_entity: Path, target_relative_path: Path | None = None) → dict[str, Any]#

Return an EntityHandle object, in its JSON structure form, pointing at a new copy of the referenced file or directory. This method performs a copy from a file anywhere accessible to the GLOW API server, into the BDM system.

Parameters:
path_to_existing_entityPath

The path to the existing file or directory that should be copied.

target_relative_pathPath | None, optional

The relative path where the new entity should be stored relative to the BDM storage scope root. If not provided, the name of the existing entity will be used as the target path.

Returns:
dict[str, Any]

The entity handle in its JSON structure form, pointing to the newly created entity.

get_path_from_entity_handle(entity_handle: dict[str, Any]) → Path | None#

Attempt to interpret the entity_handle argument as a EntityHandle object, in its JSON structure form, and return the path to a copy of the entity or None if the handle is NO_ENTITY. The entity should not be modified or deleted.

Parameters:
entity_handledict[str, Any]

The entity handle in its JSON structure form.

Returns:
Path | None

The path to a copy of the entity if it exists, or None if the handle is NO_ENTITY. The entity should not be modified or deleted.

property project_directory: Path#

Return the root of the project directory.

property solution: dict[str, Any]#

Returns the solution model in its JSON structure form, as it will be loaded into the database during migration.

At the beginning of the migration process, this structure represents either the data loaded from the GLOW database during an upgrade, or the data parsed from a .safx file during an import.

The migration transformation is expected to modify this structure so that it conforms to the target solution schema.

property steps: dict[str, Any]#

Returns the solution steps model in its JSON structure form, as it will be loaded into the database during migration.

At the beginning of the migration process, this structure represents either the data loaded from the GLOW database during an upgrade, or the data parsed from a .safx file during an import.

The migration transformation is expected to modify this structure so that it conforms to the target solution schema.

class ansys.saf.glow.solution.MigrationTransformation#

Bases: BaseModel

This class defines a specific migration of the solution stored in the MigrationContext object.

migrate(ctx: MigrationContext) → None#

Modify the solution stored in a MigrationContext to achieve a certain migration.

model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

exception ansys.saf.glow.solution.NotFoundError(detail: str)#

Bases: GlowErrorBase

The requested resource could not be found but may be available in the future.

class ansys.saf.glow.solution.ProductInstanceManager(**kwargs: Any)#

Bases: ABC, IInstanceManager[TProductClient], Generic[TProductClient, TRecoveryStateInfo]

A wrapper over an InstanceManager internal implementation for use as a public API. This is the API that is publicly exposed and consumed by solution developers for product instance management. A limited set of members of InstanceManager are exposed by ProductInstanceManager that are enough for ProductInstanceManager to implement the IInstanceManager interface.

In order to create a custom product instance manager that can be used by solutions, create a class derived from ProductInstanceManager that specifies which InstanceManager implementation to use. This is done by providing the instance_manager_impl parameter in class kwargs. The instance_manager_impl parameter should be derived from InstanceManager[TProductClient]. The derived class must define two methods: __init__ and initialize. Those methods are simply passing the parameters to the underlying internal InstanceManager implementation. The sole purpose of those methods is to define proper docstrings for solution developers.

Since a ProductInstanceManager object can be created indirectly via the @instance decorator, or directly within a transaction method, it is not possible to overload __init__ with a different signature.

To create an instance of ProductInstanceManager within a transaction, the exact same arguments that are passed to the initialize method are expected to be passed to the ProductInstanceManager constructor. For example, if def initialize(version: int) is implemented in a class derived from InstanceManager, then the corresponding ProductInstanceManager should have a constructor that has a version argument. For this reason, proper docstrings on __init__(**kwargs) to explain what arguments are expected is therefore highly recommended.

Notes

If ProductInstanceManager class requires additional members to be implemented to enable a derived class to be instantiated then please give an overview of those members here.

Examples

>>> class MyProductInstanceManager(
>>>     ProductInstanceManager[MyProductClient],
>>>     instance_manager_impl_type=InternalInstanceManagerImpl
>>> ):
>>>     def __init__(self, **kwargs: Any):
>>>         '''Documentation describing what arguments are expected from this product instance.
>>>         The arguments must be the same as the signature of the initialize method, i.e. version
>>>         in this example
>>>
>>>         Parameters
>>>         ----------
>>>         version : int
>>>             The version of the product to be used.
>>>
>>>         '''
>>>         super().__init__(**kwargs)
>>>
>>>     def initialize(self, version: Optional[str] = None):
>>>         '''Docstring for initialize. This must be the exact copy of the initialize method
>>>         from the InstanceManager internal implementation.
>>>         '''
>>>         super().start(version=version)
classmethod get_versions() → list[str]#

Return a list of versions of the product that are available in this deployment that can be accessed as product instances.

Returns:
list of str

Return a list of versions of the product that are available in this deployment that can be accessed as shared product instances. Any value in the list can be passed to the initialize method (on a derived class) to indicate the version of the instance to be created.

property instance: TProductClient#

The underlying product client.

is_instance_healthy() → bool#

Return if the instance is healthy.

property product_version: str#

Get the version of the current running product instance.

shutdown() → None#

Shut the product instance down.

start(*args: Any, **kwargs: Any) → None#

Start the instance. This must be called from the derived class within the initialize() method.

property state_directory: PurePath#

The product instance state directory path of the remote product. This directory is usually used by the product instance to save state and output files.

Notes

The return path is only valid in the context of the product and therefore cannot be used directly from the solution side. Instead, this path needs to be accessed from the product api or from the product storage scope within a @transaction method. For example, if the product has a method to save data to a specific directory, you can do the following: >>> self.product_mgr.instance.save_data(self.product_mgr.state_directory / “data_file.dat”) Similarly, you can use the product storage scope to persist files within that directory as entity handles: >>> data_handle = self.product_mgr.storage_scope.store_from_state_directory(self.state_directory / “data.dat”)

class ansys.saf.glow.solution.RecoveryStateInfo(*, product_instance_state_dirname: str = '', **extra_data: Any)#

Bases: LiveHandlesModel

A base pydantic model that can be used to save and restore product instance state information. A good usage example is to store the values passed to the instance manager’s initialized method so that the same values can be reused within the load_state_implement.

In order to store recovery state info within your instance manager implementation (the class inheriting from InstanceManager[T]) you need to: - define a derived class from this model: MyRecoveryStateInfo(RecoveryStateInfo) - call self.recovery_state_info = my_recovery_state_info where my_recovery_state_info is an instance of MyRecoveryStateInfo: my_recovery_state_info = MyRecoveryStateInfo(...)

To restore those information, simply use: my_state_info = self.recovery_state_info

Notes

All fields in your custom RecoveryStateInfo class must have default values. The class must be instantiable without any arguments. This is required for mocking the custom product instance manager in tests using the saf-sdk-testing package.

When set, the recovery state info is saved automatically after save_state_implement is being called.

Examples

>>> class MyRecoveryStateInfo(RecoveryStateInfo):
>>>     project_file: EntityHandle = NO_ENTITY
>>>     product_value: int = 0
>>> class InternalInstanceManager(InstanceManager[Product]):
>>>
>>>     def initialize(
>>>         self,
>>>         product_value: int,
>>>         project_file: EntityHandle,
>>>     ):
>>>         self.initialize_service(SERVICE_NAME, version)
>>>         recovery_state_info = MyStateInfo(
>>>             product_value=product_value,
>>>             project_file=project_file
>>>         )
>>>         # Store the recovery state info model so that it can be reused
>>>         # when restoring the product instance and upload the project file
>>>         # onto the product instance's protected file system.
>>>         self.recovery_state_info = restore_state_info
>>>
>>>     def load_state_implement(self) -> None:
>>>         state_info = self.recovery_state_info
>>>         # Re-opening the product instance with the values previously stored into the
>>>         # recovery state info
>>>         project_file_absolute_path = self.storage_scope.get_cached(state_info.project_file)
>>>         self.instance.open(project_file_absolute_path, state_info.product_value)
model_config = {'extra': 'allow', 'revalidate_instances': 'always', 'validate_assignment': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

product_instance_state_dirname: str#

Name of the directory where the product instance state files are stored.

class ansys.saf.glow.solution.RecursiveDictionaryOfEntityHandles#

Bases: dict[str, EntityHandle | RecursiveDictionaryOfEntityHandles]

A recursive dictionary structure for storing entity handles in a nested hierarchy that maps a filesystem-like directory structure.

class ansys.saf.glow.solution.Solution(*, display_name: str, version: int = 1, migrations: list[Migration] = [])#

Bases: BaseModel, ABC

Classes derived from this class contain the definition of a Solution. A Solution is a user guided workflow application in the GLOW framework.

Instances of this class are referred to as ‘projects’. Project files are the persisted form of a Solution instance.

Notes

the corresponding section provides information on how create an application that uses a class derived from Solution. the corresponding section provides information on how to modify a class derived from Solution.

Solution is derived from the pydantic BaseModel class to enable parsing and validation of project data. A Solution definition follows pydantic conventions when defining its schem . You can read more about pydantic here.

authenticate_hps(hps_server_url: str | None = None, client_id: str | None = None) → None#

Authenticate into the configured HPS system.

Parameters:
hps_server_url: str, optional

HPS endpoint that the HPS client will connect to.

client_id: str, optional

Client ID of the HPS system in OAuth.

delete() → None#

Delete the project.

delete_file(target_filepath: str) → None#

Remove a file from the project directory.

Parameters:
target_file_pathstr

Path of the file to be deleted in the project directory relative to the root of the project directory.

delete_files(pattern: str, rmdir: bool = False) → None#

Remove the files matching the relative glob pattern in the directory from the project.

Parameters:
patternstr

The glob pattern specifying sets of filenames with wildcard characters as listed by the glob module: https://docs.python.org/3/library/glob.html

rmdir: bool

Specify whether empty directories must be removed or not.

Examples

>>>    # Delete all python files
>>>    project.delete_files("**/*.py")
display_name: str#

The name of the Solution that identifies the Solution to the end user. This name is displayed in UIs that are exposed to the end user. Declare this field in a derived class to set a value appropriate to that Solution.

Examples

>>> class FluidsSolution(Solution):
>>>     display_name: str = "Fluids"
download_file(filepath: str, destination: Path) → None#

Download a file in the project directory.

Parameters:
filepathstr

Path of the source file in the project directory relative to the root of the project directory.

destinationPath

File path which will be created or overwritten with the content of the file referenced by filepath.

export(destination: Path) → None#

Export the project into a directory as an archive file.

The project file will be saved in as <display_name>.safx in the directory specified by destination

Parameters:
destinationPath

Path of the directory where the safx archive is exported.

classmethod get_other_methods_with_same_instance(method: MethodIdentifier) → set[MethodIdentifier]#

For a given transaction method, return the other transaction methods that use or create any of the same shared product instances used or created by the given method.

Parameters:
methodansys.saf.glow.solution.MethodIdentifier

Transaction method in this Solution.

Returns:
set of ansys.saf.glow.solution.MethodIdentifier

Transaction methods that use or create any of the shared product instances that are used or created by method.

Notes

the corresponding section explains the transaction method concept in more detail. the corresponding section explains the shared product instance concept in more detail.

classmethod get_step_instance_names(query_step_name: str) → set[str]#

Return the names of the shared product instances in a given step in the Solution.

Parameters:
query_step_namestr

Name of the step. A ‘step’ is a field on a StepsModel derived class. The name of a step is the name of the field. The StepsModel derived class is the type of the steps field which defines the set of steps in a Solution derived class.

Returns:
set of str

Names of the shared product instances in the step referred to by query_step_name.

get_steps() → StepsModel#

The set of objects derived from StepModel that comprise project data and implement Solution functionality through their methods. Declare this field in a derived class to provide the steps for that Solution. The type of the derived field is itself derived from StepsModel.

Examples

>>> class FluidsSolution(Solution):
>>>     steps: FluidsSteps
classmethod get_steps_fields() → dict[str, type[StepModel]]#

Return a dictionary of the step classes in the Solution.

Returns:
dict

Dictionary where the keys are the names of steps and the values are the step classes derived from StepModel. Step names are the field names of the Solution StepsModel. The step classes are the types of the fields of the StepsModel.

StepsModel is the base class of the steps field of the Solution.

get_storage_scope() → Generator[IStorageScope, None, None]#

Return a storage scope context to enable access to blob storage (e.g. store or retrieve files or directories). Unlike the storage_scope property, this must be used with the with-statement when the project client is not created using a context manager. Note that this is not the recommended way to use the storage scope and must only be used for advanced usage.

Returns:
ContextManager[IStorageScope]

the project storage scope

Examples

>>>    client = Client(...)
>>>    project = client.get_project(...)
>>>    with project.get_storage_scope as scope:
>>>        ...
classmethod initialize() → Solution#

Initialize the solution with default values.

property live_handles: list[EntityHandle]#

A list of entity handles that are referring to blobs and are stored in project fields.

model_config = {'extra': 'forbid', 'validate_assignment': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

modify_info(display_name: str | None = None, description: str | None = None) → None#

Modify project information.

Leave a field as None to keep it unchanged. Set a field to an empty string to remove it.

Parameters:
display_namestr, optional

The new display name.

descriptionstr, optional

The new description.

Examples

>>>    project.modify_info(display_name="new_display_name")
>>>    project.modify_info(description="Updated description")
>>>    project.modify_info(display_name="new_display_name", description="Updated description")
property project_description: str#

The description of the project.

Returns:
str

Project’s description.

property project_display_name: str#

The display name of the project that identifies the project to the end user.

The value of this property is meant to be used in UIs that are exposed to the end user. (This is not an alias for display_name. display_name refers to the Solution’s display name, which has the same value for all projects whereas project_display_name is for this specific project.)

Returns:
str

Project’s display name.

property project_id: str#

The ID of the project that identifies the project at the API level.

Returns:
str

Project ID.

property project_name: str#

The name of the project (format projects/<project_id>) that identifies the project at the API level.

Returns:
str

Project name.

property storage_scope: IStorageScope#

Return a storage scope context to enable access to blob storage (e.g. store or retrieve files or directories). This must be used when the project client is created using a context manager. Note that this is the recommended way to use storage scope client side and is what must be used within dash callbacks.

Returns:
IStorageScope

the project storage scope

Examples

>>>    with Client(...) as client:
>>>        project = client.get_project(...)
>>>        scope = project.storage_scope
>>>        text = scope.get_text(...)
>>>        ...

or when using Dash:

>>>   @callback(State("url", "pathname"))
>>>   def something(project: MySolution):
>>>       text_file_content = project.storage_scope.get_text(...)
>>>       ...
upload_data_uri_as_file(target_filepath: str, data_uri: str) → None#

Write the content of a data URI to a remote file.

Parameters:
target_file_pathstr

Path of the destination file in the project directory relative to the root of the project directory.

data_uristr

Data URI which is the source of the data that will be written to the destination file.

The data URI is a scheme consisting of a mime type and a base64 encoded string. For example: data:text/plain;base64,SGVsbG8gV29ybGQh

upload_file(target_filepath: str, binary_fileobj: BinaryIO) → None#

Upload the content of the binary file-like object to a file in the project directory.

Parameters:
target_file_pathstr

Path of the destination file in the project directory relative to the root of the project directory.

binary_fileobjBinaryIO

Binary file-like object which is the source of the data that will be written to the destination file.

The binary file-like object is simply the returned value of with open() with binary mode.

Examples

>>>    with open('myfile.jpg', mode='rb') as binary_fileobj:
>>>        project.upload_file("my_directory", "myfile.jpg", binary_fileobj)
property url: str#

URL of the project.

Returns:
str

URL of the project.

version: int#

The data schema version of the Solution. Declare this field in a derived class to indicate the schema version for that Solution.

Examples

>>> class FluidsSolution(Solution):
>>>     version: int = 2
class ansys.saf.glow.solution.SolutionConfiguration(*, glow_schema_version: int = 1, solution_schema_version: int = 1)#

Bases: BaseModel

Contains the configuration of the Solution. This configuration applies to all users and projects of the Solution.

The configuration can be retrieved and modified using the REST API with the route /solution-configuration.

To retrieve the configuration within a transaction, specify a parameter with type SolutionConfiguration.

The configuration can also be retrieved from the Client using the project property solution_configuration.

Examples

Retrieving the Solution configuration from within a transaction:

>>> @transaction(self=StepSpec())
>>> def my_transaction(self, config: SolutionConfiguration) -> None:
>>>     my_method(config.config_field)
>>>     ...

Retrieving the Solution configuration from the Client:

>>> project.solution_configuration.configuration_field
model_config = {'extra': 'forbid'}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class ansys.saf.glow.solution.StepModel(*, state: dict[str, FieldState] = {})#

Bases: LiveHandlesModel, ABC

A derived class defines the schema and methods for a subsection of the application defined by a Solution derived class.

Notes

You can read more about creating a class derived from StepModel the corresponding section.

StepModel is derived from the pydantic BaseModel class to enable parsing and validation of step data. A StepModel derived class follows pydantic conventions when defining its schema. You can read more about pydantic here.

A StepModel derived class becomes part of a Solution by its use as the type of a field on a StepsModel derived class that is in turn the type of the steps field of the Solution. (“Solution” here means a class derived from the Solution class.)

property data_repository: DataRepository#

Returns data repository instance if it’s configured. Otherwise it raises an exception.

get_data(datapath: str = '', substitute_file_handles_with_urls: bool = False, substitute_directory_handles_as_dictionaries: bool = False) → Any#

Get data of a step field at any level within its data structure. This is useful to retrieve only a subset of a large nested custom data structure stored in a step field. It gives you the ability to traverse the data structure using a URI path syntax.

Parameters:
datapathstr, default ""

A URI path to a nested data item. The path is used to traverse persisted data to locate the data to be returned by the method. If datapath is empty it refers to all the data in the step. If non empty, it can refer to a step field, an entity handle or any nested data item within the step field.

The syntax and semantics of the path is as follow:
  • The path is composed of segments separated by slashes (/).

  • The first segment of the path refers to a step field name.

  • Subsequent segments represent a key in a dictionary, an index in a list, a field of a custom model or an entity handle.

  • If a segment is an entity handle referencing a directory, the next segment refers to a file or sub-directory within the directory referenced by the entity handle.

  • If a segment is an entity handle referencing a file, or a simple field, no further segments are allowed.

  • Examples of valid paths:
    • "" (refers to the whole content of the step)

    • "field_name" (refers to the entire content of the step field named field_name)

    • "dict_field_name/key1/key2" (refers to the value associated with key2 in a nested dictionary structure within the step field dict_field_name)

    • "list_field_name/0" (refers to the value of the first element of a list within the step field list_field_name)

    • "entity_field_name/subdir/file.txt" (refers to the file file.txt within the sub-directory subdir of the directory referenced by the entity handle named entity-field-name)

    • "my_model/my_field" (refers to the field my_field within a custom pydantic model my_model)

If a key contains / or \ characters, they should be escaped as \/ or \\ respectively.

substitute_file_handles_with_urlsbool, default False

If True each entity handle that refers to a file in the returned data will be replaced with a URL that refers to the file. (The URL is not based on the filesystem location of the file but instead it refers to a GLOW API server end point that can resolve the content of the file wherever the content is located.)

This flag is useful for rendering data in a web application because the URLs can be passed directly to a browser which can then download the file content when needed. This approach is especially useful when the number of files in a given data set varies depending on how the user interacts with the solution.

The returned URLs will be prefixed by the value of the GLOW_EXTERNAL_API_URL environment variable if set. If GLOW_EXTERNAL_API_URL is not set the returned URLs will be prefixed by a URL derived from the GLOW_API_HOST environment variable (with a default of 127.0.0.1 if not set) and the GLOW_API_PORT environment variable (with a default of 5432 if not set).

Returns:
Any

The data item located at the specified datapath in a json form.

get_entity_url(entity_field_name: str) → str#

Return the content of the referenced entity step field.

Parameters:
entity_field_namestr

The name of a step field containing an entity handle that points to a file.

Returns:
str

Contents of the file associated to the entity step field.

get_fields(field_names: list[str] | None = None) → dict[str, Any]#

Return a dictionary with the values of the requested fields.

Parameters:
field_nameslist of str

Names of the fields to retrieve the value of.

Returns:
dict of [str, Any]

Dictionary containing the values of the requested fields.

classmethod get_instance_method_names() → list[str]#

Return the list of transaction methods on this step that create or use shared product instances.

Returns:
list of str

List of transaction methods on this step that create or use shared product instances.

Notes

You can read more about how transaction methods create or use shared product instances the corresponding section.

classmethod get_instance_references() → list[str]#

Return reference strings for the shared product instances that are created or used in this step.

Returns:
list of str

Reference strings for the shared product instances that are created or used in this step. A reference string is either a name without a period (.) or two names separated by a period. If there are two names, then the first is the name of a step and the second is the name of an instance. If there is only one name, then the name refers to an instance created in this step.

Notes

You can read more about how transaction methods create or use shared product instances the corresponding section.

classmethod get_long_running_method_names() → list[str]#

Return the list of long-running transaction methods on this step.

Returns:
list of str

List of long-running transaction methods on this step.

Notes

the corresponding section describes the concept of long running methods in detail.

get_long_running_method_state(method_name: str) → MethodState#

Return the state of a long-running transaction method on this step.

Parameters:
method_namestr

Name of a long-running transaction method on this step.

Returns:
ansys.saf.glow.solution.MethodState

State of the given method.

Notes

the corresponding section describes the concept of long running methods in detail.

get_method_state(method_name: str) → MethodState#

Return the state of a transaction method on this step.

Parameters:
method_namestr

Name of a transaction method on this step.

Returns:
ansys.saf.glow.solution.MethodState

State of the given method.

classmethod get_transaction_method_names() → list[str]#

Return the list of transaction methods on this step.

Returns:
list of str

The list of transaction methods on this step.

Notes

You can read more about how transaction methods are defined the corresponding section.

model_config = {'extra': 'forbid', 'revalidate_instances': 'always', 'validate_assignment': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

set_fields(fields: dict[str, Any]) → None#

Set the value of the referenced fields on this step.

Parameters:
fieldsdict

Dictionary of field names and their values.

state: dict[str, FieldState]#

A mapping from the names of each fields on the step to the state of the field.

Notes

This field is described in more detail the corresponding section.

property storage_scope: IStorageScope#

Return a storage scope to enable access to blob storage (e.g. store or retrieve files or directories).

property transaction: Transaction#

Execution context of the currently running transaction method. The returned object enables access to GLOW infrastructure functionality for the step during execution of a transaction method.

Returns:
ansys.saf.glow.solution.Transaction

Execution context of the currently running transaction method.

Notes

the corresponding section provides an example of using the transaction property.

class ansys.saf.glow.solution.StepSpec(download: list[str] | None = None, upload: list[str] | None = None)#

Bases: object

Definition of the fields on a given step that are to be transferred between a method’s execution environment and a project at the beginning and end of the method’s execution.

The definition determines whether fields are either accessible or modifiable within the method’s execution.

Parameters:
downloadlist of str, optional

Names of fields on the step whose values are transferred from the project to the method execution environment before the method starts.

These are the only fields that are accessible with the method.

uploadlist of str, optional

Names of fields on the step whose values are transferred from the method execution environment to the project after the method has completed.

These are the only fields that are modifiable within the method.

Notes

StepSpec objects are normally passed as arguments to instances of the transaction() decorator which decorate transaction methods. You can read about the role of StepSpec objects in transaction method definitions the corresponding section.

property download: list[str]#

Names of fields on the step whose values are transferred from the project to the method execution environment before the method starts.

These are the only fields that are accessible within the method.

Returns:
list of str

Names of fields on the step whose values are transferred from the project to the method execution environment before the method starts.

property upload: list[str]#

Names of fields on the step whose values are transferred from the method execution environment to the project after the method has completed.

These are the only fields that are modifiable within the method.

Returns:
list of str

Names of fields on the step whose values are transferted from the method execution environment to the project after the method has completed.

class ansys.saf.glow.solution.StepsModel#

Bases: BaseModel, ABC

Collection of steps for a Solution derived class (a “Solution”). A step is a subsection of a Solution.

A class derived from StepsModel will define the set of steps in a Solution by containing a set of fields each derived from a class of StepModel. These steps form a Solution when the class derived from StepsModel is the type of the steps field of the Solution.

The name of a StepModel field is the “name” of the step. Each field can have, and typically has, a unique type derived from StepModel.

Notes

You can read more about how a Solution is defined using StepsModel the corresponding section.

StepsModel is derived from the pydantic BaseModel class to enable parsing and validation of project data. You can read more about pydantic here.

Examples

>>> class FluidsSteps(StepsModel):
>>>     my_step: MyStep
>>>     my_second_step: MySecondStep
model_config = {'extra': 'forbid'}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

classmethod validate_steps(value: Any, info: ValidationInfo)#

Return the value.

Raises an exception if the value parameter doesn’t contain StepModel.

Parameters:
valueany
fieldpydantic.ValidationInfo

Validation information of the field containing the Solution steps.

Returns:
Any:

The value parameter.

class ansys.saf.glow.solution.Transaction#

Bases: object

Execution context of a transaction method. Enables access to GLOW infrastructure functionality during the execution of a transaction method.

Notes

the corresponding section provides an example of this class being accessed through the transaction property on StepModel.

property access_token: str | None#

The current access token authorizing the execution of the transaction method.

Returns:
str | None

The current access token authorizing the execution of the transaction method.

get_asset_entity_handle(asset_relative_path: str) → EntityHandle#

Get the entity handle referring to the specified asset.

Parameters:
asset_relative_path: str

The relative path of an asset in the “method_asset” directory. It could refer to a file or a directory. For encrypted file, the asset_relative_path should omit the .encrypted suffix.

Returns:
EntityHandle

The entity handle referring to the asset.

Examples

>>> class MyStep(StepModel):
>>>    @transaction(self=StepSpec())
>>>    def read_asset_file(self) -> None:
>>>        asset_handle = self.transaction.get_asset_entity_handle("dir/encrypted_asset.txt")
>>>        asset_content = self.storage_scope.get_text(asset_handle)
>>>        ...
get_user_info(fields: list[str] | None = None) → UserInfo#

Get specific information about the user who executed the transaction method.

Parameters:
fieldslist of str, optional

List of fields to retrieve from the user information.

Returns:
ansys.saf.glow.solution.UserInfo

User information extracted from the token in the request’s header including the requested fields.

Raises:
ValueError

If any of the requested fields are empty in the extracted user information.

raise_event(message: Any, stream_name: str | None = None) → None#

Enqueue an event that contains the message on the stream_name queue, within a step of an existing project.

Parameters:
messageAny

Message to be enqueued. Can contain Any json-able type of data.

stream_namestr, optional

The name of the stream where the message will be enqueued to. If not set, the name of the transaction method the event is raised from will be used.

Examples

>>> class MyStep(StepModel):
>>>    @transaction(self=StepSpec())
>>>    def trigger_event(self) -> None:
>>>        self.transaction.raise_event(message={"message":"Hello world!"}, stream_name="my-stream")
upload(field_names: list[str]) → None#

Upload step fields to the project to persist their contents. Use this method to update fields during the execution of a method.

Parameters:
field_nameslist of str

List of the fields (identified by name) whose content in the method execution environment is to be uploaded to the project. The names must match the field names of the step.

Notes

the corresponding section describes how to use this method with an example.

property user_info: UserInfo#

Information about the user who executed the transaction method.

Returns:
ansys.saf.glow.solution.UserInfo

User information extracted from the token in the request’s header.

class ansys.saf.glow.solution.UserInfo(*, sub: str = '', name: str = '', given_name: str = '', family_name: str = '', middle_name: str = '', nickname: str = '', preferred_username: str = '', profile: str = '', picture: str = '', website: str = '', email: str = '', email_verified: bool = False, gender: str = '', birthdate: str = '', zoneinfo: str = '', locale: str = '', phone_number: str = '', phone_number_verified: bool = False, address: str = '', updated_at: str = '')#

Bases: BaseModel

OpenID Connect set of standard claims about the profile information of the end-user.

model_config = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

ansys.saf.glow.solution.create_instance(instance_name: str, instance_manager_type: type[ProductInstanceManager[Any, TRecoveryStateInfo]], identifier: str | None = None, max_execution_time: int | None = None)#

Transaction method decorator which ensures that, in the current project, a named shared product instance is created for the step in which the method is declared.

Parameters:
instance_namestr

The name of the product instance.

This string must be unique across the create_instance decorators in the step.

instance_manager_typeclass derived from ProductInstanceManager

Instance manager that is to be used to manage the product instance.

This class determines the type of product instance that is created. It is recommended that a class derived from InstanceManager is used as it would provide a typed (IDE friendly) interface to the product client.

identifierstr, optional

Name of the argument of the annotated method that will be passed the object of instance_manager_type when the method is invoked.

If not given, then instance_name is used instead.

max_execution_timestr, optional

Amount of time (in seconds) after which an instance managed by Ansys HPS will be timed-out by HPS. Useful to avoid leaving instances on a stuck state.

Currently has no effect if ‘GLOW_PRODUCT_INSTANCE_SYSTEM’ is set to ‘PIM’.

If not given, the value is set to 7200 seconds (2 hours).

Notes

For instructions and examples on how to use create_instance to create shared product instances, see the corresponding section in the User Guide.

Examples

>>> @transaction(self=StepSpec(download=["aedt_file"]))
>>> @create_instance("aedt", Maxwell2DManager, max_execution_time=3600)
>>> def initialize_instance(self, aedt: Maxwell2DManager) -> None:
>>>    aedt.initialize(self.aedt_file)
ansys.saf.glow.solution.instance(instance_name: str, identifier: str | None = None)#

A decorator of transaction methods which indicates that the method will use a shared product instance that was created by another method.

A method decorated with the create_instance() decorator indicates that the decorated method will create a named instance.

An InstanceManager object for the shared product instance is passed as an argument to the transaction method.

Parameters:
instance_namestr

Reference to a shared product instance.

This parameter can contain no period (.) characters. If it does, then the parameter refers to the shared product instance with the same name that was created by another method on the same step as the decorated method.

This parameter can contain a single period (.) character separating two names where the first is a step name (see Notes) and the second name refers to a shared product instance created on the named step.

identifierstr, optional

Name of the argument of the decorated method that is passed the InstanceManager object for the shared product instance referenced by instance_name. If this parameter is not supplied, then the name of the referenced instance is used.

Notes

For instructions and examples of how to use instance to access shared product instances, see the corresponding section in the User Guide.

A ‘step’ is a field on a StepsModel derived class. The name of a step is the name of the field. The StepsModel derived class is the type of the steps field which defines the set of steps in a Solution derived class.

ansys.saf.glow.solution.long_running(step_func: Callable[[P], T]) → Callable[[P], LongRunning[T]]#

Decorator for transaction methods which need to be non-blocking in the client or in the REST API. Calls by a client to a long_running decorated transaction method will be non-blocking. The REST POST calls to a long_running decorated transaction method will complete before the transaction method implementation has completed. Typically, methods decorated with long_running potentially have a long execution time.

Notes

For details on using this decorator, see the corresponding section in the User Guide.

ansys.saf.glow.solution.transaction(enable_termination_event: bool = False, **kwargs: StepSpec)#

A method decorator that indicates that the decorated method is a transaction method. A transaction method is accessible to clients of the containing solution. Transaction methods can only be defined on StepModel derived classes. A transaction decorator defines, via its StepSpec arguments, which fields of the solution are transferred to and from the project and the method execution environment.

Parameters:
enable_termination_eventbool, optional

A boolean indicatinf if the transaction method should raise an event through the transaction’s default event stream containing a serialization of its assigned MethodState. If True, the event will always be raised even if the transaction was not successful.

**kwargsdict, optional

A mapping of keyword arguments to StepSpec objects. The argument keywords are the names of steps, the only exception, following python convention, being that self refers to the step on which the transaction method is defined. For each referenced step and keyword argument the argument value is a StepSpec object that defines which fields of the step are transferred to and from the project and the method execution environment.

Notes

A ‘step’ is a field on a StepsModel derived class. The name of a step is the name of the field. The StepsModel derived class is the type of the steps field which defines the set of steps in a Solution derived class.

the corresponding section describes how the transaction decorator is used to define transaction methods.

Examples

>>>        @transaction(self=StepSpec(download=["x"]))
>>>        def my_step_method(self):
>>>            print(self.x)
>>>
>>>        @transaction(self=StepSpec(download=["x"]), enable_termination_event=True)
>>>        def my_step_method_with_termination_event(self):
>>>            print(self.x)