Simplify the class variables of the tree class

This commit is contained in:
Veronica Berglyd Olsen
2023-08-20 21:36:33 +02:00
parent 0b4cfd0037
commit ed3e4bca6c
8 changed files with 81 additions and 88 deletions
+54 -61
View File
@@ -65,13 +65,12 @@ class NWTree:
self._project = project
self._projTree: dict[str, NWItem] = {} # Holds all the items of the project
self._treeOrder: list[str] = [] # The order of the tree items in the tree view
self._treeRoots: dict[str, NWItem] = {} # The root items of the tree
self._tree: dict[str, NWItem] = {} # Holds all the items of the project
self._order: list[str] = [] # The order of the tree items in the tree view
self._roots: dict[str, NWItem] = {} # The root items of the tree
self._trashRoot = None # The handle of the trash root folder
self._archRoot = None # The handle of the archive root folder
self._treeChanged = False # True if tree structure has changed
self._trash = None # The handle of the trash root folder
self._changed = False # True if tree structure has changed
return
@@ -81,17 +80,16 @@ class NWTree:
def clear(self) -> None:
"""Clear the item tree entirely."""
self._projTree = {}
self._treeOrder = []
self._treeRoots = {}
self._trashRoot = None
self._archRoot = None
self._treeChanged = False
self._tree = {}
self._order = []
self._roots = {}
self._trash = None
self._changed = False
return
def handles(self) -> list[str]:
"""Returns a copy of the list of all the active handles."""
return self._treeOrder.copy()
return self._order.copy()
@overload # pragma: no cover
def create(self, label: str, parent: None, itemType: Literal[nwItemType.ROOT],
@@ -109,7 +107,7 @@ class NWTree:
parent, None is returned. For root elements, this cannot occur.
"""
parent = None if itemType == nwItemType.ROOT else parent
if parent is None or parent in self._treeOrder:
if parent is None or parent in self._order:
tHandle = self._makeHandle()
newItem = NWItem(self._project, tHandle)
newItem.setName(label)
@@ -130,7 +128,7 @@ class NWTree:
logger.warning("Invalid item handle '%s' detected, skipping", tHandle)
return False
if tHandle in self._projTree:
if tHandle in self._tree:
logger.warning("Duplicate handle '%s' detected, skipping", tHandle)
return False
@@ -138,20 +136,17 @@ class NWTree:
if nwItem.isRootType():
logger.debug("Item '%s' is a root item", str(tHandle))
self._treeRoots[tHandle] = nwItem
if nwItem.itemClass == nwItemClass.ARCHIVE:
logger.debug("Item '%s' is the archive folder", str(tHandle))
self._archRoot = tHandle
elif nwItem.itemClass == nwItemClass.TRASH:
if self._trashRoot is None:
self._roots[tHandle] = nwItem
if nwItem.itemClass == nwItemClass.TRASH:
if self._trash is None:
logger.debug("Item '%s' is the trash folder", str(tHandle))
self._trashRoot = tHandle
self._trash = tHandle
else:
logger.error("Only one trash folder allowed")
return False
self._projTree[tHandle] = nwItem
self._treeOrder.append(tHandle)
self._tree[tHandle] = nwItem
self._order.append(tHandle)
self._setTreeChanged(True)
return True
@@ -171,7 +166,7 @@ class NWTree:
items. In the order defined by the _treeOrder list.
"""
tree = []
for tHandle in self._treeOrder:
for tHandle in self._order:
tItem = self.__getitem__(tHandle)
if tItem:
tree.append(tItem.pack())
@@ -199,7 +194,7 @@ class NWTree:
"""
storage = self._project.storage
files = set(storage.scanContent())
for tHandle in self._treeOrder:
for tHandle in self._order:
if self.updateItemData(tHandle):
logger.debug("Checking item '%s' ... OK", tHandle)
files.discard(tHandle) # Remove it from the record
@@ -220,7 +215,7 @@ class NWTree:
oName, oParent, oClass, oLayout = aDoc.getMeta()
oName = oName or cHandle
oParent = oParent if oParent in self._treeOrder else None
oParent = oParent if oParent in self._order else None
oClass = oClass or nwItemClass.NOVEL
oLayout = oLayout or nwItemLayout.NOTE
@@ -258,7 +253,7 @@ class NWTree:
tocList = []
tocLen = 0
for tHandle in self._treeOrder:
for tHandle in self._order:
tItem = self.__getitem__(tHandle)
if tItem is None:
continue
@@ -300,7 +295,7 @@ class NWTree:
"""Loop over all entries and add up the word counts."""
noteWords = 0
novelWords = 0
for tHandle in self._treeOrder:
for tHandle in self._order:
tItem = self.__getitem__(tHandle)
if tItem is None:
continue
@@ -376,13 +371,13 @@ class NWTree:
def rootClasses(self) -> set[nwItemClass]:
"""Return a set of all root classes in use by the project."""
rootClasses = set()
for nwItem in self._treeRoots.values():
for nwItem in self._roots.values():
rootClasses.add(nwItem.itemClass)
return rootClasses
def iterRoots(self, itemClass: nwItemClass | None) -> Iterator[tuple[str, NWItem]]:
"""Iterate over all root items of a given class in order."""
for tHandle in self._treeOrder:
for tHandle in self._order:
nwItem = self.__getitem__(tHandle)
if isinstance(nwItem, NWItem) and nwItem.isRootType():
if itemClass is None or nwItem.itemClass == itemClass:
@@ -396,12 +391,12 @@ class NWTree:
return True
if tItem.itemClass == nwItemClass.TRASH:
return True
if self._trashRoot is not None:
if tHandle == self._trashRoot:
if self._trash is not None:
if tHandle == self._trash:
return True
elif tItem.itemParent == self._trashRoot:
elif tItem.itemParent == self._trash:
return True
elif tItem.itemRoot == self._trashRoot:
elif tItem.itemRoot == self._trash:
return True
return False
@@ -409,13 +404,13 @@ class NWTree:
"""Returns the handle of the trash folder, or None if there
isn't one.
"""
if self._trashRoot:
return self._trashRoot
if self._trash:
return self._trash
return None
def findRoot(self, itemClass: nwItemClass | None) -> str | None:
"""Find the first root item for a given class."""
for aRoot in self._treeRoots:
for aRoot in self._roots:
tItem = self.__getitem__(aRoot)
if tItem is None:
continue
@@ -429,18 +424,18 @@ class NWTree:
def setOrder(self, newOrder: list[str]) -> None:
"""Reorders the tree based on a list of items."""
tmpOrder = [tHandle for tHandle in newOrder if tHandle in self._projTree]
if not (len(tmpOrder) == len(newOrder) == len(self._treeOrder)):
tmpOrder = [tHandle for tHandle in newOrder if tHandle in self._tree]
if not (len(tmpOrder) == len(newOrder) == len(self._order)):
# Something is wrong, so let's debug it
for tHandle in newOrder:
if tHandle not in self._projTree:
if tHandle not in self._tree:
logger.error("Handle '%s' in new tree order is not in old order", tHandle)
for tHandle in self._treeOrder:
for tHandle in self._order:
if tHandle not in tmpOrder:
logger.warning("Handle '%s' in old tree order is not in new order", tHandle)
# Save the temp list
self._treeOrder = tmpOrder
self._order = tmpOrder
self._setTreeChanged(True)
logger.debug("Project tree order updated")
@@ -452,36 +447,34 @@ class NWTree:
def __len__(self) -> int:
"""The number of items in the project."""
return len(self._treeOrder)
return len(self._order)
def __bool__(self) -> bool:
"""True if there are any items in the project."""
return bool(self._treeOrder)
return bool(self._order)
def __getitem__(self, tHandle: str | None) -> NWItem | None:
"""Return a project item based on its handle. Returns None if
the handle doesn't exist in the project.
"""
if tHandle and tHandle in self._projTree:
return self._projTree[tHandle]
if tHandle and tHandle in self._tree:
return self._tree[tHandle]
logger.error("No tree item with handle '%s'", str(tHandle))
return None
def __delitem__(self, tHandle: str) -> None:
"""Remove an item from the internal lists and dictionaries."""
if tHandle in self._treeOrder and tHandle in self._projTree:
self._treeOrder.remove(tHandle)
del self._projTree[tHandle]
if tHandle in self._order and tHandle in self._tree:
self._order.remove(tHandle)
del self._tree[tHandle]
else:
logger.warning("Failed to delete item '%s': item not found", tHandle)
return
if tHandle in self._treeRoots:
del self._treeRoots[tHandle]
if tHandle == self._trashRoot:
self._trashRoot = None
if tHandle == self._archRoot:
self._archRoot = None
if tHandle in self._roots:
del self._roots[tHandle]
if tHandle == self._trash:
self._trash = None
self._setTreeChanged(True)
@@ -489,12 +482,12 @@ class NWTree:
def __contains__(self, tHandle: str) -> bool:
"""Checks if a handle exists in the tree."""
return tHandle in self._treeOrder
return tHandle in self._order
def __iter__(self) -> Iterator[NWItem]:
"""Iterate through project items."""
for tHandle in self._treeOrder:
tItem = self._projTree.get(tHandle)
for tHandle in self._order:
tItem = self._tree.get(tHandle)
if isinstance(tItem, NWItem):
yield tItem
return
@@ -507,7 +500,7 @@ class NWTree:
"""Set the changed flag to theState, and if being set to True,
propagate that state change to the parent NWProject class.
"""
self._treeChanged = state
self._changed = state
if state:
self._project.setProjectChanged(True)
return
@@ -518,7 +511,7 @@ class NWTree:
"""
logger.debug("Generating new handle")
handle = f"{random.getrandbits(52):013x}"
if handle in self._projTree:
if handle in self._tree:
logger.warning("Duplicate handle encountered! Retrying ...")
handle = self._makeHandle()
+3 -3
View File
@@ -290,7 +290,7 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
assert list(dup.duplicate([C.hSceneDoc])) == [
("0000000000010", C.hSceneDoc), # The Scene
]
assert theProject.tree._treeOrder == [
assert theProject.tree._order == [
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000010",
@@ -311,7 +311,7 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
("0000000000012", None), # The Chapter
("0000000000013", None), # The Scene
]
assert theProject.tree._treeOrder == [
assert theProject.tree._order == [
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000010",
@@ -342,7 +342,7 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
("0000000000017", None), # The Chapter
("0000000000018", None), # The Scene
]
assert theProject.tree._treeOrder == [
assert theProject.tree._order == [
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000010",
+2 -2
View File
@@ -421,8 +421,8 @@ def testCoreDocBuild_Custom(mockGUI, fncPath: Path):
# Add an invalid item to the project
nHandle = "0123456789def"
project.tree._treeOrder.append(nHandle)
project.tree._projTree[nHandle] = None # type: ignore
project.tree._order.append(nHandle)
project.tree._tree[nHandle] = None # type: ignore
docBuild.queueAll()
assert len(docBuild) == 8
+3 -3
View File
@@ -727,7 +727,7 @@ def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
]
# Add a fake handle to the tree and check that it's ignored
theProject.tree._treeOrder.append("0000000000000")
theProject.tree._order.append("0000000000000")
assert [(h, t) for h, t, _ in theIndex._itemIndex.iterNovelStructure(skipExcl=False)] == [
(C.hTitlePage, "T0001"),
(C.hChapterDoc, "T0001"),
@@ -738,7 +738,7 @@ def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
(sHandle, "T0001"),
(tHandle, "T0001"),
]
theProject.tree._treeOrder.remove("0000000000000")
theProject.tree._order.remove("0000000000000")
# Extract stats
assert theIndex.getNovelWordCount(skipExcl=False) == 43
@@ -1077,7 +1077,7 @@ def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
assert nStruct[0][0] == uHandle
# Inject garbage into tree
theProject.tree._treeOrder.append("stuff")
theProject.tree._order.append("stuff")
nStruct = list(itemIndex.iterNovelStructure())
assert len(nStruct) == 4
assert nStruct[0][0] == nHandle
+1 -1
View File
@@ -328,7 +328,7 @@ def testCoreProject_AccessItems(mockGUI, fncPath, mockRnd):
assert theProject.tree.handles() == newOrder
# Add a non-existing item
theProject.tree._treeOrder.append(C.hInvalid)
theProject.tree._order.append(C.hInvalid)
# Add an item with a non-existent parent
nHandle = theProject.newFile("Test File", C.hChapterDir)
+9 -9
View File
@@ -127,7 +127,7 @@ def testCoreTree_BuildTree(mockGUI, mockItems):
assert theTree.append(nwItem) is True
assert theTree.updateItemData(nwItem.itemHandle) is True
assert theTree._treeChanged is True
assert theTree._changed is True
# Check that tree is not empty (calls __bool__)
assert bool(theTree) is True
@@ -413,9 +413,9 @@ def testCoreTree_Methods(mockGUI, mockItems):
assert roots[3][0] == "a000000000004"
# Add a fake item to root and check that it can handle it
theTree._treeRoots["0000000000000"] = NWItem(theProject, "0000000000000")
theTree._roots["0000000000000"] = NWItem(theProject, "0000000000000")
assert theTree.findRoot(nwItemClass.WORLD) is None
del theTree._treeRoots["0000000000000"]
del theTree._roots["0000000000000"]
# Get item path
assert theTree.getItemPath("stuff") == []
@@ -456,13 +456,13 @@ def testCoreTree_MakeHandles(mockGUI):
random.seed(42)
tHandle = theTree._makeHandle()
assert tHandle == handles[0]
theTree._projTree[handles[0]] = None # type: ignore
theTree._tree[handles[0]] = None # type: ignore
# Add the next in line to the project to force duplicate
theTree._projTree[handles[1]] = None # type: ignore
theTree._tree[handles[1]] = None # type: ignore
tHandle = theTree._makeHandle()
assert tHandle == handles[2]
theTree._projTree[handles[2]] = None # type: ignore
theTree._tree[handles[2]] = None # type: ignore
# Reset the seed to force collissions, which should still end up
# returning the next handle in the sequence
@@ -483,7 +483,7 @@ def testCoreTree_Stats(mockGUI, mockItems):
theTree.append(nwItem)
assert len(theTree) == len(mockItems)
theTree._treeOrder.append("stuff")
theTree._order.append("stuff")
# Count Words
novelWords, noteWords = theTree.sumWords()
@@ -520,7 +520,7 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems):
assert "Handle 'stuff' in new tree order is not in old order" in caplog.text
caplog.clear()
theTree._treeOrder.append("stuff")
theTree._order.append("stuff")
theTree.setOrder(bHandle)
assert theTree.handles() == bHandle
assert "Handle 'stuff' in old tree order is not in new order" in caplog.text
@@ -539,7 +539,7 @@ def testCoreTree_ToCFile(monkeypatch, fncPath, mockGUI, mockItems):
theTree.updateItemData(nwItem.itemHandle)
assert len(theTree) == len(mockItems)
theTree._treeOrder.append("stuff")
theTree._order.append("stuff")
def mockIsFile(fileName):
"""Return True for items that are files in novelWriter and
+4 -4
View File
@@ -203,8 +203,8 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
assert nwGUI.closeProject()
assert len(SHARED.project.tree) == 0
assert len(SHARED.project.tree._treeOrder) == 0
assert len(SHARED.project.tree._treeRoots) == 0
assert len(SHARED.project.tree._order) == 0
assert len(SHARED.project.tree._roots) == 0
assert SHARED.project.tree.trashRoot() is None
assert SHARED.project.data.name == ""
assert SHARED.project.data.title == ""
@@ -223,8 +223,8 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
# Check that we loaded the data
assert len(SHARED.project.tree) == 8
assert len(SHARED.project.tree._treeOrder) == 8
assert len(SHARED.project.tree._treeRoots) == 4
assert len(SHARED.project.tree._order) == 8
assert len(SHARED.project.tree._roots) == 4
assert SHARED.project.tree.trashRoot() is None
assert SHARED.project.data.name == "New Project"
assert SHARED.project.data.title == "New Novel"
+5 -5
View File
@@ -260,19 +260,19 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# ===========
projView.setSelectedHandle(C.hNovelRoot)
assert SHARED.project.tree._treeOrder.index(C.hNovelRoot) == 0
assert SHARED.project.tree._order.index(C.hNovelRoot) == 0
# Move novel folder up
assert projTree.moveTreeItem(-1) is False
assert SHARED.project.tree._treeOrder.index(C.hNovelRoot) == 0
assert SHARED.project.tree._order.index(C.hNovelRoot) == 0
# Move novel folder down
assert projTree.moveTreeItem(1) is True
assert SHARED.project.tree._treeOrder.index(C.hNovelRoot) == 1
assert SHARED.project.tree._order.index(C.hNovelRoot) == 1
# Move novel folder up again
assert projTree.moveTreeItem(-1) is True
assert SHARED.project.tree._treeOrder.index(C.hNovelRoot) == 0
assert SHARED.project.tree._order.index(C.hNovelRoot) == 0
# Clean up
# qtbot.stop()
@@ -881,7 +881,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
assert len(SHARED.project.tree) == 21
# Check tree order that all items are next to eachother
assert SHARED.project.tree._treeOrder == [
assert SHARED.project.tree._order == [
C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015",
"0000000000016", "0000000000017", "0000000000018", "0000000000019", "000000000001a",