<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Python Error with GenerateLayoutBookfromExcel.py in Archicad Python API</title>
    <link>https://community.graphisoft.com/t5/Archicad-Python-API/Python-Error-with-GenerateLayoutBookfromExcel-py/m-p/272205#M582</link>
    <description>&lt;DIV class="actalk-migrated-content"&gt;Does anyone know why when I run the GenerateLayoutBookFromExcel.py script with the Python plug-in I get this error: &lt;BR /&gt;Bad Name: A1 Landscape&lt;BR /&gt;&lt;U&gt;&lt;/U&gt;&lt;S&gt;&lt;U&gt;&lt;U&gt;&lt;/U&gt;&lt;/U&gt;&lt;/S&gt;&lt;I&gt;&lt;/I&gt;&lt;S&gt;&lt;I&gt;&lt;I&gt;&lt;/I&gt;&lt;/I&gt;&lt;/S&gt;GenerateLayoutBookFromExcel.py(108): AttributeError: 'NoneType' object has no attribute 'db'&lt;BR /&gt;&lt;BR /&gt;Below is the Python script:
&lt;PRE&gt;import os
import sys
import re
import xlrd

excelFileName = "LayoutBook.xls"
excelFilePath = os.path.join (os.path.dirname (sys.argv[0]), excelFileName)

if os.path.isfile (excelFilePath) is False:
	sys.exit ("File does not exists: {}".format (excelFilePath))

xl_workbook = xlrd.open_workbook(excelFilePath)
xl_sheet = xl_workbook.sheet_by_index(0)

layoutTree = GetNavigatorTree (API_LayoutMap)
subSetTree = [(list(layoutTree)[0], 0)]

def GetItemsFromTree (tree, typeSet = None):
	l = []
	for k in tree.keys():
		if typeSet is None or k.itemType in typeSet:
			l.append (k)
		l.extend (GetItemsFromTree (tree, typeSet))
	return l

masters = GetItemsFromTree (layoutTree, {API_MasterLayoutNavItem})

def GetChildrenFromTree (tree, subSetTree):
	if not subSetTree:
		return list(tree.keys())
	for k in tree.keys():
		if k.name == subSetTree[0][0].name and k.uiId == subSetTree[0][0].uiId:
			return GetChildrenFromTree (tree, subSetTree[1:])
	return []

def FindItemByName (items, name):
	for item in items:
		if item.name == name:
			return item
	PrintError('Bad Name: {}'.format(name))
	return None

def FindItemByIDName (items, ID, name):
	for item in items:
		if item.name == name and item.uiId == ID:
			return item
	return None

def CreateSubSetItem (ID, name, parent):
	newSubSet = APIObject ()
	newSubSet.uiId = ID
	newSubSet.customUiId = True
	newSubSet.name = name
	newSubSet.customName = True
	newSubSet.itemType = API_SubSetNavItem
	newSubSet.mapId = API_LayoutMap
	CreateNavigatorItem (newSubSet, parent)
	return newSubSet

def CreateOrChangeLayoutItem (ID, name, masterName, parent, oldItem = None):
	newLayout = APIObject () if oldItem is None else oldItem
	newLayout.uiId = ID
	newLayout.customUiId = True
	newLayout.name = name
	newLayout.customName = True
	newLayout.itemType = API_LayoutNavItem
	newLayout.mapId = API_LayoutMap
	newLayout.db = APIObject ()
	newLayout.db.typeID = APIWind_LayoutID
	masterLayoutItem = FindItemByName (masters, masterName)
	newLayout.db.masterLayoutUnId = masterLayoutItem.db.databaseUnId
	if oldItem is None:
		parentChildren = GetChildrenFromTree (layoutTree, subSetTree)
		if not parentChildren:
			CreateNavigatorItem (newLayout, parent)
		else:
			CreateNavigatorItem (newLayout, parent, parentChildren[-1])
	else:
		ChangeNavigatorItem (newLayout)
	return newLayout

def GetParent (actIndex):
	global subSetTree
	for i in reversed(range(1,len(subSetTree))):
		if subSetTree&lt;I&gt;[1] &amp;gt;= actIndex:
			del subSetTree&lt;I&gt;
	return subSetTree[-1][0]

newSubSetNumber, newLayoutNumber = 0, 0
for row_idx in range(1, xl_sheet.nrows):
	for column_idx in range(1, xl_sheet.ncols):
		idCell = xl_sheet.cell(row_idx, column_idx)
		if idCell.value != '':
			ID = idCell.value.strip()
			NAME = xl_sheet.cell(row_idx, column_idx + 1).value.strip()
			MASTER_NAME = xl_sheet.cell(row_idx, column_idx + 3).value.strip()

			PARENT = GetParent(column_idx)
			oldItem = FindItemByIDName (GetChildrenFromTree (layoutTree, subSetTree), ID, NAME)
			if MASTER_NAME == '':
				newSubSetNumber += 1
				if oldItem is None:
					subSetTree.append((CreateSubSetItem (ID, NAME, PARENT), column_idx))
				else:
					subSetTree.append((oldItem, column_idx))
			else:
				newLayoutNumber += 1
				CreateOrChangeLayoutItem (ID, NAME, MASTER_NAME, PARENT, oldItem)

			layoutTree = GetNavigatorTree (API_LayoutMap)
			break
print("Created {} subsets and {} layouts based on {}".format(newSubSetNumber, newLayoutNumber, excelFileName))&lt;/I&gt;&lt;/I&gt;&lt;/PRE&gt;
&lt;/DIV&gt;</description>
    <pubDate>Thu, 29 Sep 2022 07:58:46 GMT</pubDate>
    <dc:creator>ares997</dc:creator>
    <dc:date>2022-09-29T07:58:46Z</dc:date>
    <item>
      <title>Python Error with GenerateLayoutBookfromExcel.py</title>
      <link>https://community.graphisoft.com/t5/Archicad-Python-API/Python-Error-with-GenerateLayoutBookfromExcel-py/m-p/272205#M582</link>
      <description>&lt;DIV class="actalk-migrated-content"&gt;Does anyone know why when I run the GenerateLayoutBookFromExcel.py script with the Python plug-in I get this error: &lt;BR /&gt;Bad Name: A1 Landscape&lt;BR /&gt;&lt;U&gt;&lt;/U&gt;&lt;S&gt;&lt;U&gt;&lt;U&gt;&lt;/U&gt;&lt;/U&gt;&lt;/S&gt;&lt;I&gt;&lt;/I&gt;&lt;S&gt;&lt;I&gt;&lt;I&gt;&lt;/I&gt;&lt;/I&gt;&lt;/S&gt;GenerateLayoutBookFromExcel.py(108): AttributeError: 'NoneType' object has no attribute 'db'&lt;BR /&gt;&lt;BR /&gt;Below is the Python script:
&lt;PRE&gt;import os
import sys
import re
import xlrd

excelFileName = "LayoutBook.xls"
excelFilePath = os.path.join (os.path.dirname (sys.argv[0]), excelFileName)

if os.path.isfile (excelFilePath) is False:
	sys.exit ("File does not exists: {}".format (excelFilePath))

xl_workbook = xlrd.open_workbook(excelFilePath)
xl_sheet = xl_workbook.sheet_by_index(0)

layoutTree = GetNavigatorTree (API_LayoutMap)
subSetTree = [(list(layoutTree)[0], 0)]

def GetItemsFromTree (tree, typeSet = None):
	l = []
	for k in tree.keys():
		if typeSet is None or k.itemType in typeSet:
			l.append (k)
		l.extend (GetItemsFromTree (tree, typeSet))
	return l

masters = GetItemsFromTree (layoutTree, {API_MasterLayoutNavItem})

def GetChildrenFromTree (tree, subSetTree):
	if not subSetTree:
		return list(tree.keys())
	for k in tree.keys():
		if k.name == subSetTree[0][0].name and k.uiId == subSetTree[0][0].uiId:
			return GetChildrenFromTree (tree, subSetTree[1:])
	return []

def FindItemByName (items, name):
	for item in items:
		if item.name == name:
			return item
	PrintError('Bad Name: {}'.format(name))
	return None

def FindItemByIDName (items, ID, name):
	for item in items:
		if item.name == name and item.uiId == ID:
			return item
	return None

def CreateSubSetItem (ID, name, parent):
	newSubSet = APIObject ()
	newSubSet.uiId = ID
	newSubSet.customUiId = True
	newSubSet.name = name
	newSubSet.customName = True
	newSubSet.itemType = API_SubSetNavItem
	newSubSet.mapId = API_LayoutMap
	CreateNavigatorItem (newSubSet, parent)
	return newSubSet

def CreateOrChangeLayoutItem (ID, name, masterName, parent, oldItem = None):
	newLayout = APIObject () if oldItem is None else oldItem
	newLayout.uiId = ID
	newLayout.customUiId = True
	newLayout.name = name
	newLayout.customName = True
	newLayout.itemType = API_LayoutNavItem
	newLayout.mapId = API_LayoutMap
	newLayout.db = APIObject ()
	newLayout.db.typeID = APIWind_LayoutID
	masterLayoutItem = FindItemByName (masters, masterName)
	newLayout.db.masterLayoutUnId = masterLayoutItem.db.databaseUnId
	if oldItem is None:
		parentChildren = GetChildrenFromTree (layoutTree, subSetTree)
		if not parentChildren:
			CreateNavigatorItem (newLayout, parent)
		else:
			CreateNavigatorItem (newLayout, parent, parentChildren[-1])
	else:
		ChangeNavigatorItem (newLayout)
	return newLayout

def GetParent (actIndex):
	global subSetTree
	for i in reversed(range(1,len(subSetTree))):
		if subSetTree&lt;I&gt;[1] &amp;gt;= actIndex:
			del subSetTree&lt;I&gt;
	return subSetTree[-1][0]

newSubSetNumber, newLayoutNumber = 0, 0
for row_idx in range(1, xl_sheet.nrows):
	for column_idx in range(1, xl_sheet.ncols):
		idCell = xl_sheet.cell(row_idx, column_idx)
		if idCell.value != '':
			ID = idCell.value.strip()
			NAME = xl_sheet.cell(row_idx, column_idx + 1).value.strip()
			MASTER_NAME = xl_sheet.cell(row_idx, column_idx + 3).value.strip()

			PARENT = GetParent(column_idx)
			oldItem = FindItemByIDName (GetChildrenFromTree (layoutTree, subSetTree), ID, NAME)
			if MASTER_NAME == '':
				newSubSetNumber += 1
				if oldItem is None:
					subSetTree.append((CreateSubSetItem (ID, NAME, PARENT), column_idx))
				else:
					subSetTree.append((oldItem, column_idx))
			else:
				newLayoutNumber += 1
				CreateOrChangeLayoutItem (ID, NAME, MASTER_NAME, PARENT, oldItem)

			layoutTree = GetNavigatorTree (API_LayoutMap)
			break
print("Created {} subsets and {} layouts based on {}".format(newSubSetNumber, newLayoutNumber, excelFileName))&lt;/I&gt;&lt;/I&gt;&lt;/PRE&gt;
&lt;/DIV&gt;</description>
      <pubDate>Thu, 29 Sep 2022 07:58:46 GMT</pubDate>
      <guid>https://community.graphisoft.com/t5/Archicad-Python-API/Python-Error-with-GenerateLayoutBookfromExcel-py/m-p/272205#M582</guid>
      <dc:creator>ares997</dc:creator>
      <dc:date>2022-09-29T07:58:46Z</dc:date>
    </item>
    <item>
      <title>Re: Python Error with GenerateLayoutBookfromExcel.py</title>
      <link>https://community.graphisoft.com/t5/Archicad-Python-API/Python-Error-with-GenerateLayoutBookfromExcel-py/m-p/272206#M583</link>
      <description>Figured it out.&lt;BR /&gt;
&lt;BR /&gt;
Just had to have a Master Layout named correctly "A1 Landscape".</description>
      <pubDate>Thu, 14 Nov 2019 19:29:38 GMT</pubDate>
      <guid>https://community.graphisoft.com/t5/Archicad-Python-API/Python-Error-with-GenerateLayoutBookfromExcel-py/m-p/272206#M583</guid>
      <dc:creator>ares997</dc:creator>
      <dc:date>2019-11-14T19:29:38Z</dc:date>
    </item>
  </channel>
</rss>

