Reload Family from Folder

Hi everyone, I have a family that is already in a project and i want a dynamo script that will reload the same family into the project. Im unfamiliar with the file and directory nodes. Could someone please give me some help on this topic?

What have you tried so far? Have you searched the forum for similar topics? There should be more than a few that deal with loading families. I believe Orchid has nodes for loading you could try.

Crumple package has one.

2 Likes

Hi @GavinCrump. Im a big fan of your youtube channel, it has helped me learn dynamo!

Im still learning dynamo, can you show me an example graph of how to use the FamilyDoc.LoadPath node?

1 Like

Yep there is a graph here:

Thank you for your help!

1 Like

Hi Gavin, Whether this code for reload is python 3 Compatible?

Yes, I have updated all but the nodes under the IronPython section of my package to CPython3.

Thanks for the information.
I tried to use the familydoc load node in cpython3 engine but it is not working as Familyloadoptions throws error in cPython3, i think it needed to be fixed to work in cpython3 thanks

Ah yes unfortunately that uses an interface which is not supported in CP3… my mistake. PythonNet will be needed or the IronPython2.7 package for now until the team builds it in.

1 Like

Have you seen this? PythonNet3: A New Python to Fix Everything - Dynamo BIM

1 Like

If I’m reading that right, pythonnet’s improvements come in the form of another dependency package - oof if so.

I feel like 50% of my troubleshooting for packages these days is ā€˜install ironpython package’ (even after i put my own package in cp3 - most other packages didn’t…).

PythonNet3 will become the default engine

I think It is a good idea that it be as a package (temporarily) to report issues in the different host software (Revit, Civil, etc.) and correct them

1 Like

Ah that makes more sense, try it as a package, integrate it later. Thanks!

That sounds very promising in that case. I miss interfaces… and easy enums…

1 Like

As @c.poupin indicated, this is the intended state for today, but in the future this will be the default. Previous python updates have suffered from:

  • No one can use it until the team ships it - which resulted in issues as they can’t test what users do with it.
  • There was no chance at backwards compatibility - which resulted in package authors having to issue a different code base between builds. A package can be updated as possible in the future giving you (and others) the option of writing it once and using it again.
  • Users and authors had to live with what is in the initial deployment - the only way things got fixed is when Dynamo was updated, which means we have to live with things until the team had time to fork, update, build, test, and ship the fix, which is a minimum of 6 months for some integrations
  • Beta testing doesn’t require a beta machine - by allowing some use in the wild we can get real project feedback (usually where the issues that have the most impact are found as the base datasets are shall we say imperfect) rather than what can be gained from interaction with a sample project

The alternatives to a package are ā€˜do it as we did it before’ (remember CPython was introduced in July of 2020 and many still haven’t updated so I’m not a huge fan of that), or provide it under a feature flag… and if you think downloading a package for end users is difficult imagine getting IT to sign off on ā€œenabling a feature flag for an experimental code execution environmentā€. This truly was the ā€˜best path’ in my opinion.

2 Likes

It’s not that it’s difficult for me, but it appears to be too difficult for the average Dynamo user to know to download a package, and before that actually read the instructions to ensure they don’t overshoot the version for their respective Revit build. This difficulty in turn leads on to repetitive lines of questioning/troubleshooting. Just feels like things are getting a bit… messy.

To clarify I think the team has done about as much as can be done in the UX to ensure users are aware of this dependency in the dependency manager interface. It’s just the nature of where we’re at I guess.

I honestly don’t mind the tabula rasa idea, the packages list needs a serious nuke, and a reset to PythonNet and beyond might be a good way to do it - albeit painful/confusing for users and package managers straddling whichever Revit build that could happen for. And potentially punishing for people who stuck with zero touch throughout the whole fiasco depending how a line in the sand could work.

Having moved on from pyRevit and running out of time to manage my own Python package, my skin in the game is limited, but the vast majority of depended upon packages utilize IP2 at this point it seems.

Personally I think we passed messy and moved into ā€˜forgot to put the lid on the blender before starting it right underneath the high power ceiling fan’ about 5 years ago. It’s been a ā€˜clean up’ effort ever since.

Bit of a minority stance here, but I really appreciate the thought behind it and in some ways would take a similar perspective if starting at a firm tomorrow. Sadly as soon as you say ā€œwe are starting over without any upgrade pathā€ the people who buy the software (executives at the firm) get quite mad… If you were to tell your boss tomorrow that all of your current automations are going in the bin and you’re starting over in 2026 how do you think they’d react?

Not sure the statistics bear that out - could just be that the subset of Dynamo uses you’re after all have ā€˜easy’ solutions which are IP2 based, or it could be that the subset of Dynamo uses I see don’t touch IP2… Most stuff I see now though is C# based for better or worse. Could be worth doing a dig into how much there is in a narrow timeframe across the community (i.e. when looking at all package downloads from a one month span, what % of nodes have IP2 in them)… :thinking:

2 Likes

Yes in this case I should clarify that of the python based packages I deal with most, they tend to be IP2. If I delved back into packages again it would definitely be zero touch as I’m two feet in C# for the last 3 months. Maybe a stronger stance to push in the learning materials/pathway, as the easy entry level of Python can be a temptation to put off ZT/C# (I myself being guilty).

There’s broader scope these days that I see with Civil and other packages, so I’ll try not to paint with too broad of a brush in future…

1 Like

Broad brush is fine - in fact your opinion with any brush is highly welcome in any context. :slight_smile:

Doing so brings meaningful insight and inspiration to the community.

I’m actively looking at building a POC for an analysis tool to parse a user’s Dynamo environment (all loaded packages and definitions) for IronPython2 dependencies and save the result to disc. Looks quite doable and shouldn’t take much (~8 hours) to turn it into a view extension to help people like you make informed decisions on the management of your environment(s).

1 Like

For anyone interested I am pasting my findings below. Note that I haven’t entirely tested this, but it should suffice for something you can build a POC from. Runs fine for me in Dynamo Sandbox 3.4 and Dynamo for Revit 2.12 using the CPython engine.

The Python Code
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Attempts to parse the Dynamo environemnt to pull all custom nodes (*.dyf files) and checks each to confirm if there is (0) an unsupported Python in use, (1) only supported Python engines in use, (2) no Python in use."
__DynamoBuilds__ = "3.4"
__ReleaseNotes__ = "Runs in the CPython3 engine in Dynamo. Not completely tested in all environments and configurations. Test thuroughly before implementing."
__Dependancies__ = "None."
__Copyright__ = "2025, Autodesk Inc."
__License__ = "Apache 2"

########################################
### configure the Python environment ###
########################################
import sys, clr, os, json #import sys, clr, os, and json modules into the Python environment
clr.AddReference("DynamoServices") #add DynamoServices to the CLR
from Dynamo.Events import ExecutionEvents #import the execution events class from the Dynamo.Events namespace
import traceback

########################################
#### get dyf files from environment ####
########################################
packagePaths = list(ExecutionEvents.ActiveSession.GetParameterValue("PackagePaths")) #get the package paths from the current Dynamo environment
userFolder = [i for i in packagePaths if "AppData\\Roaming\\" in i][0] #get the user folder - sequence can vary here, but this should be fairly robust; parsing from the Dynamo engine or a property of the workspace might be better but I don't have time to solve everything today
defsFolder = userFolder.replace("packages","definitions") #replace the user pacage folder with the definitions folder
packagePaths.append(defsFolder) #append the definitions folder to the package paths
dyfs = [] #empty list to hold all DYFs found
walk = [os.walk(path) for path in packagePaths] #walk the packag e paths to get all files and directories recursively
for step in walk: #for each step in the walk
    for root, subdir, files in step: #for the root folder, subdir, and files in each step
        [dyfs.append(os.path.join(root,file)) for file in files if file.endswith(".dyf")] #append any file paths to the dyfs directory if the file ends with .dyf

########################################
###### prepare the output strings ######
########################################
unsupportedFileVersion, unsupportedCustomNodes, supportedCustomNodes, noPythonCustomNodes = [], [], [], []


########################################
###### parse dyf for python nodes ######
########################################
for file in dyfs: #for each file
    with open(file) as dyf: #open the file
        dyfStr = dyf.read() #read the dyf as a string
        if dyfStr[0]=="<": #if the first character is a "<" the dyf is in file version 1 and uncompatible by default
            unsupportedFileVersion.append("\t"+file) #append anything older than dirt to the appropriate list
        else:
            data = json.loads(dyfStr) #read the JSON structure from the string
            nodes = data["Nodes"] #get the nodes
            pythonNodes = [node for node in nodes if "Python" in node["NodeType"]] #filter to only nodes which are Python type
            if not pythonNodes: #if there is no Python node 
                noPythonCustomNodes.append("\t"+file) #append to the appropriate list 
            failing = [] #build a list for failing nodes
            for pythonNode in pythonNodes: #for each python node
                if not "Engine" in pythonNode.keys(): #if there is no engine tag the graph is really old and will try to default to IronPython2
                    failing.append([file, pythonNode["Id"]]) #append to the appropriate list
                elif pythonNode["Engine"] == "IronPython2": #if the engine tag is IronPython2
                    failing.append([file, pythonNode["Id"]]) #append to the appropriate list
            
            if failing: #if there is data in failing
                nodes = "\n".join(["\t\t\t"+i[1] for i in failing]) #get the nodes formatted as a string with tripple indent and new lines between each
                count = "\t\t"+str(len(failing)) + " python nodes with unsupported engine" #count the failing nodes and format as a string
                root = [i for i in packagePaths if i in file][0]
                shortPath = file.replace(root,"")
                result = "\n".join(["\t"+shortPath,count,nodes]) #join the result as a string with line breaks
                unsupportedCustomNodes.append(result) #append to the appropriate list 
            else: #otherwise
                supportedCustomNodes.append("\t"+file) #append the indented title to the appropriate list 

#########################################
##### Return the results to Dynamo ######
#########################################
report = {"Invalid or unsupported file format":unsupportedFileVersion, "Utilized Python Engine in unsupported": unsupportedCustomNodes, "Utilized Python Engine is supported": supportedCustomNodes, "No python in use": noPythonCustomNodes}
OUT = report #return the result to the Dynamo environment```

A quick test of the 8 most installed packages on the package manager in Revit 2022 gave me:

  • 61 invalid files
    • These are still Dynamo 1.0 formatted so they aren’t compatible with the new engine.
    • They were entirely from steam nodes, which hasn’t been updated in over a 7 years so it’s well and truly deprecated at this point.
  • 220 used no Python
    • These are custom nodes which just use OOTB nodes for execution.
    • No worries here - you’ve got bigger fish to fry.
  • 1 using a supported Python version.
    • Clockwork’s CustomNode.Propeorties.dyf node takes the cake here.
  • 834 using an unsupported Python version.
    • 89 in Archi-Lab which are likely not supported based on statements from the package author over the years, where it’s been indicated that there should not be any Python nodes in the package.
    • 293 in Clockwork. There is an effort underway to modernize on a CPython3 engine, but it is as of yet unreleased. Repository is here for anyone interested: ClockworkForDynamo/nodes/3.x at master Ā· andydandy74/ClockworkForDynamo Ā· GitHub
    • 349 in Genius Loci. I am not sure where this stands; last I it was firmly in camp ā€˜not going to upgrade at this time’.
    • 103 in spring nodes, which hasn’t been updated in nearly 5 years now, so also likely deprecated.

So not a very pretty picture for those looking for Revit automation packages at first glimpse. But it’s important to keep that 834 in perspective - as of Dynamo for Revit 3.2 (what I have to test handy at the moment) you’ve got 946 nodes in the core Dynamo library and another 776 in Dynamo for Revit. Add Rhythm (~276 nodes) and Archi-Lab’s C# nodes (499 C# nodes after removing the unsupported Python nodes) and you’re looking at 2586 nodes which don’t run into any issues with users configuration of their Python engine. The net result is a Dynamo environment with 3552 nodes, 3/4 of which work when the correct package version is installed (totaling 2718 nodes), and 1/4 of which require the proper version of the deprecated Python engine being installed (834).

Now that node count omits deprecated packages, and your library might look quite a bit different (i.e. installing Orchid or Sythesize would make more Python independent nodes, while installing Datashapes would increase the IronPython woes). But for a tool where office wide content management usually is best described as ā€œwe alternate between applying duct tape and spraying with WD40 until it worksā€ I’d say that’s pretty good. But for ā€˜better’ results it’s less going to be about the end user education (what you pointed to above @GavinCrump) or the Dynamo team ā€œlocking-inā€ current versioning (the clear slate method) or someone somehow supporting all previous code forever (the ideal state which never existed, but we all were ignorant to the reality of), and firms developing, maintaining, and sharing best practices…

2 Likes