Skip to content

Commit

Permalink
exercise 0
Browse files Browse the repository at this point in the history
  • Loading branch information
jsdbroughton committed Nov 12, 2024
1 parent 20ae21a commit ac11eb5
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 93 deletions.
50 changes: 50 additions & 0 deletions Exercises/exercise-0/function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
def automate_function(
automate_context: AutomationContext,
function_inputs: FunctionInputs,
) -> None:
"""This is an example Speckle Automate function.
Args:
automate_context: A context helper object, that carries relevant information
about the runtime context of this function.
It gives access to the Speckle project data, that triggered this run.
It also has convenience methods attach result data to the Speckle model.
function_inputs: An instance object matching the defined schema.
"""

# the context provides a convenient way, to receive the triggering version
version_root_object = automate_context.receive_version()

flat_list_of_objects = flatten_base(version_root_object)

# filter the list to only include objects that are displayable.
# this is a simple example, that checks if the object has a displayValue
displayable_objects = [
speckle_object
for speckle_object in flat_list_of_objects
if (
getattr(speckle_object, "displayValue", None)
or getattr(speckle_object, "@displayValue", None)
)
and getattr(speckle_object, "id", None) is not None
]

if len(displayable_objects) == 0:
automate_context.mark_run_failed(
"Automation failed: No displayable objects found."
)

else:
# select a random object from the list
random_object = random.choice(displayable_objects)

automate_context.attach_info_to_objects(
category="Selected Object",
object_ids=[random_object.id],
message=function_inputs.comment_phrase,
)

automate_context.mark_run_success("Added a comment to a random object.")

# set the automation context view, to the original model / version view
automate_context.set_context_view()
16 changes: 16 additions & 0 deletions Exercises/exercise-0/inputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from pydantic import Field
from speckle_automate import AutomateBase


class FunctionInputs(AutomateBase):
"""These are function author defined values.
Automate will make sure to supply them matching the types specified here.
Please use the pydantic model schema to define your inputs:
https://docs.pydantic.dev/latest/usage/models/
"""

comment_phrase: str = Field(
title="Comment Phrase",
description="This phrase will be added to a random model element.",
)
100 changes: 7 additions & 93 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,103 +1,17 @@
"""This module contains the function's business logic.
Use the automation_context module to wrap your function in an Automate context helper.
"""
This main entry point is the command line interface for the Speckle Automate function.
"""

from pydantic import Field, SecretStr
from speckle_automate import (
AutomateBase,
AutomationContext,
execute_automate_function,
)

from flatten import flatten_base


class FunctionInputs(AutomateBase):
"""These are function author-defined values.
Automate will make sure to supply them matching the types specified here.
Please use the pydantic model schema to define your inputs:
https://docs.pydantic.dev/latest/usage/models/
"""

# An example of how to use secret values.
whisper_message: SecretStr = Field(title="This is a secret message")
forbidden_speckle_type: str = Field(
title="Forbidden speckle type",
description=(
"If a object has the following speckle_type,"
" it will be marked with an error."
),
)


def automate_function(
automate_context: AutomationContext,
function_inputs: FunctionInputs,
) -> None:
"""This is an example Speckle Automate function.
Args:
automate_context: A context-helper object that carries relevant information
about the runtime context of this function.
It gives access to the Speckle project data that triggered this run.
It also has convenient methods for attaching result data to the Speckle model.
function_inputs: An instance object matching the defined schema.
"""
# The context provides a convenient way to receive the triggering version.
version_root_object = automate_context.receive_version()

objects_with_forbidden_speckle_type = [
b
for b in flatten_base(version_root_object)
if b.speckle_type == function_inputs.forbidden_speckle_type
]
count = len(objects_with_forbidden_speckle_type)

if count > 0:
# This is how a run is marked with a failure cause.
automate_context.attach_error_to_objects(
category="Forbidden speckle_type"
f" ({function_inputs.forbidden_speckle_type})",
object_ids=[o.id for o in objects_with_forbidden_speckle_type if o.id],
message="This project should not contain the type: "
f"{function_inputs.forbidden_speckle_type}",
)
automate_context.mark_run_failed(
"Automation failed: "
f"Found {count} object that have one of the forbidden speckle types: "
f"{function_inputs.forbidden_speckle_type}"
)

# Set the automation context view to the original model/version view
# to show the offending objects.
automate_context.set_context_view()

else:
automate_context.mark_run_success("No forbidden types found.")

# If the function generates file results, this is how it can be
# attached to the Speckle project/model
# automate_context.store_file_result("./report.pdf")


def automate_function_without_inputs(automate_context: AutomationContext) -> None:
"""A function example without inputs.
If your function does not need any input variables,
besides what the automation context provides,
the inputs argument can be omitted.
"""
pass

import Exercises.exercise_0.inputs.FunctionInputs as FunctionInputs
import Exercises.exercise_0.function.automate_function as automate_function

# make sure to call the function with the executor
# Pass in the function reference with the inputs schema to the executor.
# If the function has no arguments, the executor can handle it like so
# execute_automate_function(automate_function_without_inputs)
if __name__ == "__main__":
# NOTE: always pass in the automate function by its reference; do not invoke it!

# Pass in the function reference with the inputs schema to the executor.
execute_automate_function(automate_function, FunctionInputs)

# If the function has no arguments, the executor can handle it like so
# execute_automate_function(automate_function_without_inputs)

0 comments on commit ac11eb5

Please sign in to comment.