Move ElementSupply to own file and document it

This commit is contained in:
Joscha 2019-05-11 22:50:12 +00:00
parent 7c89ada5f0
commit b71e3e15d6
4 changed files with 156 additions and 97 deletions

View file

@ -1,6 +1,7 @@
from typing import List
from .element import *
from .element_supply import *
from .exceptions import *
from .markup import *
from .tree_display import *
@ -8,6 +9,7 @@ from .tree_list import *
__all__: List[str] = []
__all__ += element.__all__
__all__ += element_supply.__all__
__all__ += exceptions.__all__
__all__ += markup.__all__
__all__ += tree_display.__all__

View file

@ -4,7 +4,7 @@ from typing import Hashable, List, Optional
from .exceptions import ElementException, TreeException
from .markup import AttributedText
__all__ = ["Id", "Element", "ElementSupply", "RenderedElement"]
__all__ = ["Id", "Element", "RenderedElement"]
Id = Hashable
@ -47,101 +47,6 @@ class Element(abc.ABC):
) -> RenderedElement:
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:
def __init__(self,
element: Element,

151
cheuph/element_supply.py Normal file
View 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))

View file

@ -1,7 +1,8 @@
import collections
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 .markup import AttributedText
from .tree_list import TreeList