Move ElementSupply to own file and document it
This commit is contained in:
parent
7c89ada5f0
commit
b71e3e15d6
4 changed files with 156 additions and 97 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from .element import *
|
from .element import *
|
||||||
|
from .element_supply import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .markup import *
|
from .markup import *
|
||||||
from .tree_display import *
|
from .tree_display import *
|
||||||
|
|
@ -8,6 +9,7 @@ from .tree_list import *
|
||||||
|
|
||||||
__all__: List[str] = []
|
__all__: List[str] = []
|
||||||
__all__ += element.__all__
|
__all__ += element.__all__
|
||||||
|
__all__ += element_supply.__all__
|
||||||
__all__ += exceptions.__all__
|
__all__ += exceptions.__all__
|
||||||
__all__ += markup.__all__
|
__all__ += markup.__all__
|
||||||
__all__ += tree_display.__all__
|
__all__ += tree_display.__all__
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from typing import Hashable, List, Optional
|
||||||
from .exceptions import ElementException, TreeException
|
from .exceptions import ElementException, TreeException
|
||||||
from .markup import AttributedText
|
from .markup import AttributedText
|
||||||
|
|
||||||
__all__ = ["Id", "Element", "ElementSupply", "RenderedElement"]
|
__all__ = ["Id", "Element", "RenderedElement"]
|
||||||
|
|
||||||
Id = Hashable
|
Id = Hashable
|
||||||
|
|
||||||
|
|
@ -47,101 +47,6 @@ class Element(abc.ABC):
|
||||||
) -> RenderedElement:
|
) -> RenderedElement:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ElementSupply(abc.ABC):
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get(self, element_id: Id) -> Element:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_parent_id(self, element_id: Id) -> Optional[Id]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_parent(self, element_id: Id) -> Optional[Element]:
|
|
||||||
parent_id = self.get_parent_id(element_id)
|
|
||||||
|
|
||||||
if parent_id is not None:
|
|
||||||
return self.get(parent_id)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_children_ids(self, element_id: Id) -> List[Id]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_children(self, element_id: Id) -> List[Element]:
|
|
||||||
children_ids = self.get_children_ids(element_id)
|
|
||||||
|
|
||||||
children: List[Element] = []
|
|
||||||
for child_id in children_ids:
|
|
||||||
children.append(self.get(child_id))
|
|
||||||
|
|
||||||
return children
|
|
||||||
|
|
||||||
# There is not a clear-cut way to get the previous or next "sibling" of an
|
|
||||||
# element that is itself a child of the implicit root (None), since
|
|
||||||
# get_children() doesn't accept None in its element_id argument.
|
|
||||||
#
|
|
||||||
# Because of this, the get_previous_id() and get_next_id() functions are
|
|
||||||
# abstract (until I decide to change the signature of get_children(), that
|
|
||||||
# is :P).
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_previous_id(self, element_id: Id) -> Optional[Id]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_previous(self, element_id: Id) -> Optional[Element]:
|
|
||||||
previous_id = self.get_previous_id(element_id)
|
|
||||||
|
|
||||||
if previous_id is not None:
|
|
||||||
return self.get(previous_id)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_next_id(self, element_id: Id) -> Optional[Id]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_next(self, element_id: Id) -> Optional[Element]:
|
|
||||||
next_id = self.get_next_id(element_id)
|
|
||||||
|
|
||||||
if next_id is not None:
|
|
||||||
return self.get(next_id)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_furthest_ancestor_id(self,
|
|
||||||
element_id: Id,
|
|
||||||
root_id: Optional[Id] = None,
|
|
||||||
) -> Id:
|
|
||||||
current_id = element_id
|
|
||||||
|
|
||||||
while True:
|
|
||||||
parent_id = self.get_parent_id(current_id)
|
|
||||||
|
|
||||||
if parent_id == root_id:
|
|
||||||
return current_id
|
|
||||||
elif parent_id is None:
|
|
||||||
raise TreeException("Reached implicit root before hitting specified root")
|
|
||||||
|
|
||||||
current_id = parent_id
|
|
||||||
|
|
||||||
def get_furthest_ancestor(self,
|
|
||||||
element_id: Id,
|
|
||||||
root_id: Optional[Id] = None,
|
|
||||||
) -> Element:
|
|
||||||
return self.get(self.get_furthest_ancestor_id(element_id,
|
|
||||||
root_id=root_id))
|
|
||||||
|
|
||||||
def get_tree(self, tree_id: Id) -> Element:
|
|
||||||
tree = self.get(tree_id)
|
|
||||||
|
|
||||||
children: List[Element] = []
|
|
||||||
for child_id in self.get_children_ids(tree_id):
|
|
||||||
children.append(self.get_tree(child_id))
|
|
||||||
|
|
||||||
tree.children = children
|
|
||||||
return tree
|
|
||||||
|
|
||||||
class RenderedElement:
|
class RenderedElement:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
element: Element,
|
element: Element,
|
||||||
|
|
|
||||||
151
cheuph/element_supply.py
Normal file
151
cheuph/element_supply.py
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
import abc
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from .element import Element, Id
|
||||||
|
from .exceptions import TreeException
|
||||||
|
|
||||||
|
__all__ = ["ElementSupply", "MemoryElementSupply"]
|
||||||
|
|
||||||
|
class ElementSupply(abc.ABC):
|
||||||
|
"""
|
||||||
|
An ElementSupply is an interface to query some resource containing
|
||||||
|
Elements. The elements could for example be kept in memory, in a database
|
||||||
|
or somewhere else.
|
||||||
|
|
||||||
|
The element ids must be unique, and the elements and their parents must
|
||||||
|
form one or more trees (i. e. must not contain any cycles).
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get(self, element_id: Id) -> Element:
|
||||||
|
"""
|
||||||
|
Get a single element by its id.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_parent_id(self, element_id: Id) -> Optional[Id]:
|
||||||
|
"""
|
||||||
|
Get the id of the parent's element.
|
||||||
|
|
||||||
|
This function is redundant, since you can just use element.parent_id.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.get(element_id).parent_id
|
||||||
|
|
||||||
|
def get_parent(self, element_id: Id) -> Optional[Element]:
|
||||||
|
"""
|
||||||
|
Like get_parent_id, but returns the Element instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
parent_id = self.get_parent_id(element_id)
|
||||||
|
|
||||||
|
if parent_id is not None:
|
||||||
|
return self.get(parent_id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_children_ids(self, element_id: Optional[Id]) -> List[Id]:
|
||||||
|
"""
|
||||||
|
Get a list of the ids of all the element's children.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_children(self, element_id: Optional[Id]) -> List[Element]:
|
||||||
|
"""
|
||||||
|
Get a list of all children of an element.
|
||||||
|
|
||||||
|
If the id passed is None, return a list of all top-level elements
|
||||||
|
instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
children_ids = self.get_children_ids(element_id)
|
||||||
|
|
||||||
|
children: List[Element] = []
|
||||||
|
for child_id in children_ids:
|
||||||
|
children.append(self.get(child_id))
|
||||||
|
|
||||||
|
return children
|
||||||
|
|
||||||
|
# There is not a clear-cut way to get the previous or next "sibling" of an
|
||||||
|
# element that is itself a child of the implicit root (None), since
|
||||||
|
# get_children() doesn't accept None in its element_id argument.
|
||||||
|
#
|
||||||
|
# Because of this, the get_previous_id() and get_next_id() functions are
|
||||||
|
# abstract (until I decide to change the signature of get_children(), that
|
||||||
|
# is :P).
|
||||||
|
|
||||||
|
def get_previous_id(self, element_id: Id) -> Optional[Id]:
|
||||||
|
"""
|
||||||
|
Get the id of an element's previous sibling (i. e. the sibling just
|
||||||
|
above it).
|
||||||
|
|
||||||
|
Returns None if there is no previous sibling.
|
||||||
|
|
||||||
|
Depending on the amount of elements in your ElementSupply, the default
|
||||||
|
implementation might get very slow.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass # TODO
|
||||||
|
|
||||||
|
def get_previous(self, element_id: Id) -> Optional[Element]:
|
||||||
|
"""
|
||||||
|
Like get_previous_id(), but returns the Element instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
previous_id = self.get_previous_id(element_id)
|
||||||
|
|
||||||
|
if previous_id is not None:
|
||||||
|
return self.get(previous_id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_next_id(self, element_id: Id) -> Optional[Id]:
|
||||||
|
"""
|
||||||
|
Get the id of an element's next sibling (i. e. the sibling just below
|
||||||
|
it).
|
||||||
|
|
||||||
|
Returns None if there is no next sibling.
|
||||||
|
|
||||||
|
Depending on the amount of elements in your ElementSupply, the default
|
||||||
|
implementation might get very slow.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pass # TODO
|
||||||
|
|
||||||
|
def get_next(self, element_id: Id) -> Optional[Element]:
|
||||||
|
"""
|
||||||
|
Like get_next_id(), but returns the Element instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
next_id = self.get_next_id(element_id)
|
||||||
|
|
||||||
|
if next_id is not None:
|
||||||
|
return self.get(next_id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# def get_furthest_ancestor_id(self,
|
||||||
|
# element_id: Id,
|
||||||
|
# root_id: Optional[Id] = None,
|
||||||
|
# ) -> Id:
|
||||||
|
# current_id = element_id
|
||||||
|
#
|
||||||
|
# while True:
|
||||||
|
# parent_id = self.get_parent_id(current_id)
|
||||||
|
#
|
||||||
|
# if parent_id == root_id:
|
||||||
|
# return current_id
|
||||||
|
# elif parent_id is None:
|
||||||
|
# raise TreeException("Reached implicit root before hitting specified root")
|
||||||
|
#
|
||||||
|
# current_id = parent_id
|
||||||
|
#
|
||||||
|
# def get_furthest_ancestor(self,
|
||||||
|
# element_id: Id,
|
||||||
|
# root_id: Optional[Id] = None,
|
||||||
|
# ) -> Element:
|
||||||
|
# return self.get(self.get_furthest_ancestor_id(element_id,
|
||||||
|
# root_id=root_id))
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import collections
|
import collections
|
||||||
from typing import Any, List, Optional, Set
|
from typing import Any, List, Optional, Set
|
||||||
|
|
||||||
from .element import Element, ElementSupply, Id, RenderedElement
|
from .element import Element, Id, RenderedElement
|
||||||
|
from .element_supply import ElementSupply
|
||||||
from .exceptions import TreeException
|
from .exceptions import TreeException
|
||||||
from .markup import AttributedText
|
from .markup import AttributedText
|
||||||
from .tree_list import TreeList
|
from .tree_list import TreeList
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue