Dynamo/Python script for document transmittal

Hi all,

I have been attempting to get this dynamo/python script to work but I am coming up with a generic error that I cant seem to work out.

Its from this tutorial

https://www.youtube.com/watch?v=hWxblEJ0EkU&lc=Ugwa0Qkc6hsP45mmG614AaABAg.9xZi1STbqW79xZnu9rZAYk

And rather than badgering the creator with questions I thought id ask here. When running the script I get this error

PythonEvaluator.Evaluate operation failed.
Traceback (most recent call last):
File "<string>", line 44 in <module> 
AtrributeError: 'NoneType' object has no attribute 'Name'

I have tested this on the project file which the creator uses and it works fine, but on my project file the error keeps occurring. Ill post the entire script at the bottom for your information.

The only trouble shooting ive done myself is check that every drawing has at least 1 revision. Which they do.

Any help will be greatly appreciated.

# Made by Gavin Crump
# Free for use
# BIM Guru, www.bimguru.com.au

# Boilerplate text
import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 

clr.AddReference("RevitAPI")
import Autodesk 
from Autodesk.Revit.DB import *

# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument

# Define list/unwrap list functions
def uwlist(input):
    result = input if isinstance(input, list) else [input]
    return UnwrapElement(result)

# Preparing input from dynamo to revit
sheets = uwlist(IN[0])

# Get revision sequences and revisions
revSeqs = FilteredElementCollector(doc).OfClass(RevisionNumberingSequence).ToElements()
revIds  = Revision.GetAllRevisionIds(doc)
revs    = [doc.GetElement(i) for i in revIds]

# Get sequence name per revision


# Empty variable lists to store to
revSeqNames, revCharSeqs = [],[]

# Get sequence names and characters
for r in revs:
	# Get sequence
	rsId = r.RevisionNumberingSequenceId
	rs   = doc.GetElement(rsId)
	# Append the name and start a sequence
	revSeqNames.append(rs.Name)
	charSequence = []
	# Get sequence characters for numeric...
	if rs.NumberType == RevisionNumberType.Numeric:
		settings  = rs.GetNumericRevisionSettings()
		minDigits = settings.MinimumDigits
		prefix    = settings.Prefix
		suffix    = settings.Suffix
		for n in range(settings.StartNumber,99,1):
			char_str = str(n)
			pad_str  = char_str.rjust(minDigits,"0")
			char_seq = prefix + pad_str + suffix
			charSequence.append(char_seq)
	# ... or Alphanumeric
	else:
		settings = rs.GetAlphanumericRevisionSettings()
		prefix    = settings.Prefix
		suffix    = settings.Suffix
		for a in settings.GetSequence():
			char_seq = prefix + a + suffix
			charSequence.append(char_seq)
	# Append the character sequence
	revCharSeqs.append(charSequence)

# Get revision sequences per sheet
rowsOut = []
sep = "\t"

for s in sheets:
	trackRevs = []
	sheetRevs = s.GetAllRevisionIds()
	rowOut = ""
	rowOut += s.SheetNumber + sep + s.Name + sep
	# For each revision in the document
	for i in revIds:
		# Check if the sheet has it
		if i in sheetRevs:
			# Get the sequence Id name and get its name
			r    = doc.GetElement(i)
			rsId = r.RevisionNumberingSequenceId
			rs   = doc.GetElement(rsId)
			rsn  = rs.Name
			# Find the index of the sequence name
			i_sq = revSeqNames.index(rsn)
			# Find out how many times the sequence occured so far
			i_ch = trackRevs.count(rsn)
			# Get the sequence character, then track the sequence
			d = revCharSeqs[i_sq][i_ch] + sep
			trackRevs.append(rsn)
		else:
			d = "" + sep
		rowOut += d
	# Add the value to the end
	rowsOut.append(rowOut)


# Make the top header
header = "Number" + sep + "Name" + sep + sep.join([r.RevisionDate for r in revs]) + sep
rowsOut.insert(0,header)

# Preparing output to Dynamo
OUT = rowsOut
type or paste code here

You’re welcome to badger me a bit.

The warning indicates that there is no name for a revision sequence that was not found. From what I can tell on line 41 it’s triggering an error so my guess is maybe one of your revisions has no sequence associated to it (None). Some firms use this to make a ‘title’ revision at the top of their table, in which case you should drop any of those revisions from the ones being collected first.

Maybe try catching it in try/except and using continue to get it to skip that iteration:

	# Append the name and start a sequence
	try:
		revSeqNames.append(rs.Name)
	except:
		continue
1 Like

Instead of that I would go like that:

if rs:
	revSeqNames.append(rs.Name)
	# Rest of Code
3 Likes

Thanks for your help again. I can confirm that your solution works and I have tested it on a number of different models.

So that solution you provided, is that telling the code to check but if no just ignore it and keep going? If so is it a generic solution I could use elsewhere if I have the same problem?

1 Like

The continue statement tells the code to stop this iteration and then go back to the next object in the iterable being looped through in the for statement you call it in. Other useful ones are pass (keep going) and break (stop the loop).

Deniz is also correct in that an if statement where the second branch doesn’t execute instead is probably more clean, although I sometimes find I prefer continue as it means you can avoid an extra visual level of indentation.

2 Likes

Well thanks to you both for the help/advice. I have started with the basics of Python as I want to understand the code myself to I can correct my own errors.

My next step in my project are to add a filter as an input so I can have the script only use certain plans.
To explain further,

How we set up sheets in a project is our Architectural plans always have an ‘A’ before the plan number, ‘S’ before structural etc although im going to assume thats very standard across the industry haha.

So if I just wanted to create a transmittal for just Architectural I was going to add an input to the script and player that a user can add a character (A, S etc) to create a transmittal of just those plans.

So far ive managed to create a bit of a separate part of the script for the filter but cant get it to plug back into the python script node as of yet.

Once I have this part worked out I plan to watch your video again to see where in the code it starts formatting the code for excel as I want to be able to use our company template which has titles and other parts so ill have to format the data to appear in other cells.

Thanks again

There’s likely a null in there somewhere (non-pointer). Check your lists and follow it back to see where it occurs and why.

We can’t see the python error, but it’s likely as one of the inputs is also null.

I have pasted both errors here. Although I did a small tweak and ended up with a different error.

I went from List Bool Mask straight to List sort by key rather than going to string from object first.

This is the error at the Python node

And here is the whole thing

Ok managed to remove the error from the node. I think what the issue was is that I had the list of sheets and the filtered list of keys, but since the total amount of keys didnt match the total number of sheets, thats what the error was (I think)

Now there is a new error in the python code here

Here is the part of the code with line 77

I assume its a similar problem that occurred with the other node. The code is expecting a longer list of sheets, but as its a filtered list, and therefore less sheets, it returns the error?

Although after typing that, that doesnt really make sense to me, as the input into the code contains the filtered list of sheets and nothing from a node that contains all sheets, so you would think that it wouldnt be an issue because as far as the code knows, the filtered list is the only amount of sheets within the model?

Not sure if thats on the right track or not. Just a thought I had.

You’re sending in sheet numbers. Sort the sheets by the key not the keys by the keys.

Hi there,

I have been working through it and managed to get a different error where there is a miss match with keys and sheets (too many keys not enough sheets) So I know what the problem is, So I have been attempting to insert the filter earlier into the script with no success.

Do you have any suggestions where I should insert the filter and what nodes to use? Screen shot is below to show where its up to now

Sort by the sheets after being filtered.

If you’re following my tutorial I’d suggest looking into this method. I found it after my tutorial and it makes the whole process a lot easier:

Thanks I will look into that.

I just adjusted the script and unfortunately its sent two lists of sheet numbers to the script rather than a list of numbers and a list of sheets.
First image is the result when the script is working without the filter im trying to create

This is after your suggestion

Which then leads to the error in the script

Hi @Dylan.hB2 try this…


Example from previous post added also.

Same error as before. You need to filter the sheets by the keys. Make sure to read errors carefully, that one is pretty clearly stating a string is not correct in python.

It may be worth revisiting python fundamentals also if not familiar with it, following full tutorials has less impact without this.

Hi Kai,

Thankyou! the errors are gone and its working…sort of. Haha there is always a But issnt there?
So the new issue is that the original script had the result in the correct sheet order (ordered by sheet number)

Here is what the original did. As you can see its in sheet number order but it has those sheets not in the A series (the ones I want to filter out) stil there

This is after your correction which has the filter working but they arnt in sheet number order anymore

I have noticed that before the node below had two lists of sheet numbers, now with your change it has two lists of sheet names… So do you think this is what is causing the out of sheet number order issue?

I think I have it working. Probably not the most elegant solution but I effectively have two filters running. One for Sheets one for sheet numbers


Hi @Dylan.hB2 you could use same filter you created earlier just add sheet number into another filterbyBoolMask node to streamline it.

1 Like

In addition to Kai’s suggestion, you can also use Filter in Excel to header sort:

1 Like

Thanks to you both for your help.

I am in the middle of an online Python course so I am beginning to understand the code. It especially helps just knowing the nomenclature and what words mean.

At the moment I am at a point where I am trying to see what I have learned into real code

2 Likes