Alternative: Breadth First Search
As an alternative you could also use a BFS algorithm -- the first part is the same:
def bom_build_bfs(o,p):
# Create a hash keyed by parts, providing their sub parts as list
d = dict()
for [part, subpart] in parts_h:
if part in d:
d[part].append(subpart)
else:
d[part] = [subpart]
# add start elements to bom, which later will be removed
bom = [[serial, None, part, part] for [serial, part] in order]
i = 0
# treat it as a queue, adding to it while looping
while i < len(bom):
[serial, parent, part, path] = bom[i]
i += 1
if part in d:
for subpart in d[part]:
bom.append([serial, part, subpart, path + '/' + subpart])
elif i < len(order): # when there are no sub parts
bom.append([serial, part, None, path])
# return the part without the starter elements
return bom[len(order):]
In my limited tests this ran slower than the DFS solution, but it might depend on how the input data is distributed and how deeply nested it is.