Script to Load and Insert Detail Family

Hi, all.
I’m new to pyRevit toolbar creation (just saw my first couple of videos on the topic recently), but am very excited for the opportunities ahead!
Could someone help me write a script for a pushbutton that will insert a detail family (or load one if it’s not already loaded)? The pseudo-code is as follows:

  1. click button to start script (already have this and the button already works - but the script itself does nothing yet).
  2. script will check if a specific detail family, say “symbol.rfa”, is loaded into current project model.
  3. if it is loaded, the script gets it ready to be inserted into the working view (similar to how the “Detail Component” in the Annotate tab already works).
  4. if is not loaded, the script will then load that detail family from a specific folder, say C:\pyRevit\MyTools.
  5. after loading it into the current project model, the script gets it ready to be inserted into the working view.

Any help would be greatly appreciated :slight_smile:

Hi @EBSoares
Check out this: GitHub - jmcouffin/pyRevit-BILT_NA_2022

That will get you there.
In the handout i talk about content bundles or content button.

This is a bundle type that lets you attach 1 or 2 families to a push button.

You can also install this demo toolbar nad figure out how it works and how it is structured clicking on the button + alt.

Hi, @Jean-Marc - thanks for the reply :+1:

It looks like the code there would require the Revit family to be actually located in the folder for the pushbutton itself. And I’m not sure if the program would even check if the family is already loaded in the project model before attempting to load the family.

Is there a way to write a script that will do that? Just like the pseudo-code above? That way we can keep all of our families in their usual folder (so it’s easy to make updates), write down the actual file path in the script, and go from there.

Thanks in advance

Check this: The Building Coder: Family API Add-in Load Family and Place Instances
The scenario 1 is what you are after.
It is c# but the logic is there.

You are right - after reading, it is exactly what I need :grinning:
I forgot to mention on the OP, but I am also new to Python (never wrote a thing in this language) and do not know how to convert C# to it in order to place it in the scipt.py file - could you give me a hand on that by any chance?

Got the code from Jeremy Tammik converted to Python (thanks Jeremy and Jean-Mark!).

Issue now is that it doesn’t seem to compile. I wish I knew enough about Python to fix it, but alas I can’t… Could someone help me figure this one out?

import clr
import os.path
import System
import Autodesk.Revit.DB as DB
import Autodesk.Revit.UI as UI


clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")


class CmdTableLoadPlace(UI.IExternalCommand):
	FamilyName = "family_api_table"
	_family_folder = os.path.dirname(System.Reflection.Assembly.GetExecutingAssembly().Location)
	_family_ext = "rfa"
	_family_path = os.path.join(_family_folder, FamilyName)
	_family_path = os.path.splitext(_family_path)[0] + "." + _family_ext


	_added_element_ids = []


	def Execute(self, commandData):
		uiapp = commandData.Application
		uidoc = uiapp.ActiveUIDocument
		app = uiapp.Application
		doc = uidoc.Document


		# Retrieve the family if it is already present:
		family = DB.FilteredElementCollector(doc).OfClass(DB.Family).FirstOrDefault(lambda f: f.Name == self.FamilyName)


	if not family:
		# It is not present, so check for the file to load it from:
		if not os.path.exists(self._family_path):
			TaskDialog.Show("Error", "Please ensure that the sample table family file '{0}' exists in '{1}'.".format(self.FamilyName, self._family_folder))
			return UI.Result.Failed


			# Load family from file:
			with DB.Transaction(doc, "Load Family") as tx:
				family = doc.LoadFamily(self._family_path)


		# Determine the family symbol
		symbol = None
		for s in family.Symbols:
			symbol = s
			# Our family only contains one symbol, so pick it and leave
			break


		# Place the family symbol:
		# Subscribe to document changed event to retrieve family instance elements added by the PromptForFamilyInstancePlacement operation:
		app.DocumentChanged += self.OnDocumentChanged
		self._added_element_ids.clear()


		# PromptForFamilyInstancePlacement cannot be called inside transaction.
		uidoc.PromptForFamilyInstancePlacement(symbol)


		app.DocumentChanged -= self.OnDocumentChanged


		# Access the newly placed family instances:
		n = len(self._added_element_ids)
		msg = "Placed {0} {1} family instance{2}{3}".format(n, family.Name, self.PluralSuffix(n), self.DotOrColon(n))
		ids = ", ".join(str(id.IntegerValue) for id in self._added_element_ids)
		TaskDialog.Show("Information", "{0}\n{1}".format(msg, ids))


		return UI.Result.Succeeded


	def OnDocumentChanged(self, sender, args):
		self._added_element_ids.extend(args.GetAddedElementIds())


	def PluralSuffix(self, n):
		return "" if n == 1 else "s"


	def DotOrColon(self, n):
		return ":" if n == 0 else "."