Hallo community, I have a conceptual issue about breaking down a dynamo script into smaller steps.
I regularly implement a series of control checkpoints in my scripts, for example to make sure all geometry is read without errors (no empty lists or nulls results out of an element.geometry node) or that parameters are correctly mapped (string is equal to value, count.false is zero). The output of any control checkpoint restitutes either (1) a string of IDs separated by a semicolon, which represents the objets to check as I copy paste from the player into the āsearch IDā Revit command (and manually emend), or (2) a success message such as āOK, all items are fineā.
I wish to run the rest of the script ONLY when the latter condition happens. I am trying to grasp the transactions & passthrough nodes funtioning, so far without luck.Atm the rest of the script runs with wrong inputs, causing a lot of time losses and script crash.
Also I see videos of older versions of dynamo player when the user clicks on one subtask, then on another, and so on - but i am not being able to replicate the process.
Easiest way will be to wrap each section into a custom node that gets packaged and distributed. Then add an extra inout to toggle execution only if the previous section returned ok, otherwise only processing null data.
You could also fight the ScopeIf nodes, or set up the graph to have a UI to approve execution or only pass null data if something other than the ok message is received.
Specific help will require a specific graph situation though, so upload something illustrating the current issue if you need more than this.
Honestly once you get to advanced control flow itās likely time to move on from passthroughs and branch-offs, and look into Python or Zero touch. You will have the ability to execute, bypass and catch errors more easily in this environment.
It can be a big step at first, but over time youāll find that even in Dynamo youāll gain much more UX flexibility for your users by mixing Python in with your code.
Iāve been in the same position before trying to achieve partial script runs and the time it takes to set up a script to cleanly work this way would be just as much as dabbling in some Python fundamentals and mixing it in step by step. Maybe begin by looking into basic iteration of numbers (not Revit elements, just for loops), then if/then/else, then mix that into a loop body and finally try/except which allows you to encounter and deal with potential errors (e.g. nulls).
@Draxl_Andreas Attached the code. The WHITE groups are my checkpoints and restitute as an output either an empty list (all is fine) or a list of items that I shall check (plots the item to check as text strings).
The desired script behaviour would consist in not running the PINK block if either of the WHITE block restitute a list which is not empty. I am aware that an IF block could parse empty or null into the PINK block, but I wish to actually stop the code from running further (otherwise I may break script further down the line and/or let revit crash). Is this possible at all? Maybe can the Revit API stop a script from running, or is there any node that does this already?
I would favour a Python solution like the one that @GavinCrump is pointing, yet IĀ“m not aware of any way to use Trasition.Start() Trasition.End() methods in a costum python node that would abort the script from running, or if this is the right method at all. @jacob.small I do not know Scopeself yet, while IĀ“m not super keen on processing null for the reason above; also I am worried that the wrap section method would pose problems in the script maintenance.
A great approach would probably be a python node that reads the checklist and stop the code from running further, if the list is NOT empty, and plots the IDs of the item (IĀ“ve already coded this part in python in the WHITE block below using the join method), otherwise process the data further down the line.
Handled properly the null will just throw a warning; nothing will be processed as the data will be a single invalid entry. This is how the Data.Gate node prevents many a Revit model from going bad.
That said, what you are describing certainly sounds like the desire for a custom node with a ārunā input that passes nothing though the contained functions (a single null or empty list) or the full dataset. This can be done with a simple .dyf node which you manage and deploy. Python can do the trick too, but itās a bigger bar for entry into the space as you have to pick up the expertise in Python (from the context and typical āpaceā for education, Iād say you are month of education away from being able to execute in that manor).
This is the Python code to undertake a transaction, everything between start/end is going to be in that transaction:
# Boilerplate text
import clr
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument
# Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
# your actions
TransactionManager.Instance.TransactionTaskDone()
Big shoutout to @jacob.small : IĀ“ve tested and tested and now I get what you say. Parsing a null down the line is the closest IĀ“ve got to abort the script from running. Thanks!
IĀ“m trying to close my educational gap asap and working towards having everything āunder one roofā in a nice coded way as @GavinCrump suggests. Your contents are legendary btw.
FYI : the IĀ“m including this combination of nodes as an AUDIT mechanism in all of my scripts. The AUDITOR script takes a list of IDs that undertook a check up the line and throws a string of text (as an output for the player) that can be copy-pasted into the search per ID of the Manage tab, so that the model can be cleaned. Should the list be empty, then the output message āOKā triggers to passthrough the original list - otherwise a null is sent down the line to block the script and give time to the operatot to check the model.
def list_to_string_semicolon(numbers):
# Remove None values and convert numbers to strings
string_list = [str(num) for num in numbers if num is not None]
# Check if the resulting list is empty
if not string_list:
return "OK"
# Join the string representations into a single string, separated by a semicolon
result = ";".join(string_list)
return result
flagged = IN[0]
audit = list_to_string_semicolon(flagged)
OUT = audit
I am aware that I could code anything in one Pyhton node, especially the IF mechanism, but donĀ“t know how to generate more OUT entries in a Python node(a list with two lists, then a codeblock to call OUT[0] and OUT[1], could be a solution) - as it is possible to do in Grasshopper, for instance.
Also, it seems logical to convert the standardized AUDITOR into a custom node, as @jacob.small poited out, but I have issues in mantaining and will do this to a later stage.