Using a CSV to push values to elements with Dynamo/Python

I am working on a code to be able to utilize Dynamo/Python to push a value to an element that contains a parameter value from a CSV, I have it working for some elements, but I have a set of elements that are nested that end up causing the last section of the code to fail due to them being mapped to the host, so it changes the first element, then it flops for the remainder instead of continuing onto the next item that it can do.

the code in question is lines 145-159

Also I have another section that I dont think is a good workflow but I cannot seem to get to work without doing it this way otherwise it messes up my list numbering. basically I am opening the CSV getting a count of the columns to a variable, then deleting out that parameter and closing the CSV, then opening it again so I can read the content…
image

Here is the entire code:

#portion of script covering find element containing parameter value taken from MEPover FilterStringEquals node.

import clr
import sys
pyPath = r"C:\Program Files (x86)\IronPython 2.7\Lib"
sys.path.append(pyPath)
import os
import System 
import System.Collections
#Access to Revit Document
clr.AddReference("RevitServices")
import RevitServices
#To Get Doc, UI and Application Objects
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIDocument
app = DocumentManager.Instance.CurrentUIApplication.Application
#Needed to make any changes in Revit
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitNodes")
import StringIO
from System.IO import FileInfo
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *;
clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI import *
from System.Collections.Generic import List
import csv
from System.IO import FileInfo

#Get CSV Path, Param Row Letter, ParamVal Column Number 
filePath = IN[0]
paramName = IN[1].lower()
pNToInt = ord(paramName)-97#lowecase a starts at 97 in ASCII
paramValCell = int(IN[2])-1#subtract 1 to normalize numbers (Revit lists start with 0 not 1)

#get CSV Info
with open(filePath) as csvCountFile:
	delReader = csv.reader(csvCountFile, delimiter=',')
	columns = len(next(delReader))-1
	del delReader
	csvCountFile.close()

csvData = []
with open(filePath) as csvFile:
	csvReader = csv.reader(csvFile, delimiter=',')
	for row in csvReader:
		csvData.append(row)

#find Elements with Value from CSV
search = csvData[pNToInt][0]
string = csvData[paramValCell][pNToInt]
case = IN[3]
bips = System.Enum.GetValues(BuiltInParameter)

bm = doc.ParameterBindings
bmlist = bm.ForwardIterator()
paramId = None
testout = []
while bmlist.MoveNext():
	binddef = bmlist.Key
	testout.append(binddef.Name)
	if binddef.Name == search:
		paramId = binddef.Id
		break

param = None
if paramId == None:
	biplist = []
	for bip in bips:
		try:
			name = LabelUtils.GetLabelFor(bip)
		except:
			continue
		if name == search:
			biplist.append(bip)


sharedparamrule = SharedParameterApplicableRule(search)
evaluator = FilterStringEquals()

parameter = None
if paramId == None and len(biplist) == 0:
	coll = FilteredElementCollector(doc)
	sharedparams = coll.OfClass(ParameterElement)
	
	for param in sharedparams:
		name = param.GetDefinition().Name
		if name == search:
			parameter = param
	
	if parameter != None:
		ruleslist = List[FilterRule]()
		provider = ParameterValueProvider(parameter.Id)
		filterrule = FilterStringRule(provider, evaluator, string, case)
		ruleslist.Add(filterrule)
		ruleslist.Add(sharedparamrule)
		paramFilter = ElementParameterFilter(ruleslist)
		collector = FilteredElementCollector(doc)
		collector.OfClass(FamilyInstance).WherePasses(paramFilter)
		
		collector2 = FilteredElementCollector(doc)
		collector2.OfClass(HostObject).WherePasses(paramFilter)
		collector2.UnionWith(collector)

elif paramId == None:
	filterList = List[ElementFilter]()
	for param in biplist:
		provider = ParameterValueProvider(ElementId(param))
		filterrule = FilterStringRule(provider, evaluator, string, case)
		paramFilter = ElementParameterFilter(filterrule)
		filterList.Add(paramFilter)
			
	orFilter = LogicalOrFilter(filterList)
	collector = FilteredElementCollector(doc)
	collector.OfClass(FamilyInstance).WherePasses(orFilter)
	
	collector2 = FilteredElementCollector(doc)
	collector2.OfClass(HostObject).WherePasses(orFilter)
	collector2.UnionWith(collector)
else:
	ruleslist = List[FilterRule]()
	provider = ParameterValueProvider(paramId)
	filterrule = FilterStringRule(provider, evaluator, string, case)
	ruleslist.Add(filterrule)
	ruleslist.Add(sharedparamrule)
	paramFilter = ElementParameterFilter(ruleslist)
	collector = FilteredElementCollector(doc)
	collector.OfClass(FamilyInstance).WherePasses(paramFilter)
	
	collector2 = FilteredElementCollector(doc)
	collector2.OfClass(HostObject).WherePasses(paramFilter)
	collector2.UnionWith(collector)


if parameter == None and paramId == None and len(biplist) == 0:
	OUT = "Does not work with non-shared family parameters"
else:
	elements = collector2.ToElements()

elemsChanged = []
TransactionManager.Instance.EnsureInTransaction(doc)	
try:	
	for e in elements:
		i = 0
		while i < columns:
			param = csvData[0][i]
			val = csvData[paramValCell][i]
			e.LookupParameter(param).Set(val)
			i += 1
		elemsChanged.Add(e)
		
except:
	OUT = "Try Again"
TransactionManager.Instance.TransactionTaskDone()


OUT = paramValCell, param, val, search, string, elemsChanged, elements

MM - Python - WIP Set Parameters if value contained in CSV.dyn (13.4 KB)

1 Like

Not certain, but I think that this is the issue:

try:	
	for e in elements:
		i = 0
		while i < columns:
			param = csvData[0][i]
			val = csvData[paramValCell][i]
			e.LookupParameter(param).Set(val)
			i += 1
		elemsChanged.Add(e)
		
except:
	OUT = "Try Again"

This is asking Revit to try to set all the element’s parameters and if one fails, just set OUT to "Try again".

You want to take each element and try to set the parameter, and if it fails move onto the next element (ideally letting the user know which failed.

something like this perhaps:

results = [] #sets a new variable to append some useful info into
import traceback #imports the traceback module so we can find out why each item fails
for e in elements: #starts a loop to work over the elements
  try: #starts the list of stuff to try
    i = 0  #resets i to zero
    while i < columns: #while i is less than the column count perform the offset items below
      param = csvData[0][i] #gets the parameter in question from the CSV data
      val = csvData[paramValCell][i] #gets the value from the csvData
      e.LookupParameter(param).Set(val) #attempts to set the element's parameter to the given value
      i+=1 #increments i by one
    elemsChanged.Add(e) #appends the element to the elemsChanged list
    results.append("All set") #appends an informative message to the results list
  except: #if the 'try' statement above failed, perform the offset items below
    message = traceback.format_exc() #gets the failure message from the memory
    elemsChanged.Add(none) #adds an empty item (null in Dynamo) to the elemsChanged list (keeping your list structure in tact)
    results.append(message) #appends the traceback message to the results list

Be sure to add the “results” variable to your output so your users will know why this has failed.

4 Likes

That worked like a champ! (beside the very minor none needing to be capitalized) I had been staring at it for a while without any ideas beyond food sounds good about now, so my brain quit functioning…

Thank you so much for the help!

Here is the finalized script if anyone wants.
MM - Python - Set Parameters if value contained in CSV.dyn (14.2 KB)

1 Like

This is what I get for typing code on my phone. :laughing:

Glad you’re all set. :slight_smile:

1 Like

Thats pretty damn impressive coming from your phone!

MM - Python - Set Parameters if value contained in CSV.dyn (12.3 KB)

Revised version of the script, now iterates through all rows in the CSV

1 Like