lib/page_tree.py
changeset 44 d09cc8b3709c
parent 28 b68145b5ce24
parent 43 fc11c4e86a82
child 45 e94ab812c0c8
equal deleted inserted replaced
28:b68145b5ce24 44:d09cc8b3709c
     1 """
       
     2     Implements the tree containing pages and their metadata
       
     3 """
       
     4 
       
     5 import tree_parse
       
     6 
       
     7 # path to file containing the page metadata tree
       
     8 PAGE_TREE_FILE = "pages/list"
       
     9 
       
    10 class PageTreeError (Exception) :
       
    11     """
       
    12         Error parsing/loading the page tree
       
    13     """
       
    14 
       
    15     pass
       
    16 
       
    17 class PageInfo (object) :
       
    18     """
       
    19         Contains metainformation about a page
       
    20     """
       
    21 
       
    22     def __init__ (self, parent, name, title, children=None) :
       
    23         """
       
    24             Initialize, children defaults to empty list
       
    25         """
       
    26 
       
    27         # store
       
    28         self.parent = parent
       
    29         self.name = name
       
    30         self.title = title
       
    31         self.children = children if children else []
       
    32 
       
    33         # no url get
       
    34         self._url = None
       
    35     
       
    36     def set_parent (self, parent) :
       
    37         """
       
    38             Set a parent where non was set before
       
    39         """
       
    40 
       
    41         assert self.parent is None
       
    42 
       
    43         self.parent = parent
       
    44 
       
    45     def add_child (self, child) :
       
    46         """
       
    47             Add a PageInfo child
       
    48         """
       
    49 
       
    50         self.children.append(child)
       
    51     
       
    52     def get_child (self, name) :
       
    53         """
       
    54             Look up a child by name, returning None if not found
       
    55         """
       
    56 
       
    57         return dict((c.name, c) for c in self.children).get(name)
       
    58 
       
    59     def get_ancestry (self) :
       
    60         """
       
    61             Returns a list of this page's parents and the page itself, but not root
       
    62         """
       
    63         
       
    64         # collect in reverse order
       
    65         ancestry = []
       
    66         
       
    67         # starting from self
       
    68         item = self
       
    69         
       
    70         # add all items, but not root
       
    71         while item and item.parent :
       
    72             ancestry.append(item)
       
    73 
       
    74             item = item.parent
       
    75 
       
    76         # reverse
       
    77         ancestry.reverse()
       
    78         
       
    79         # done
       
    80         return ancestry
       
    81 
       
    82     @property
       
    83     def url (self) :
       
    84         """
       
    85             Build this page's URL
       
    86         """
       
    87 
       
    88         # cached?
       
    89         if self._url :
       
    90             return self._url
       
    91 
       
    92         segments = [item.name for item in self.get_ancestry()]
       
    93         
       
    94         # add empty segment if dir
       
    95         if self.children :
       
    96             segments.append('')
       
    97         
       
    98         # join
       
    99         url = '/'.join(segments)
       
   100         
       
   101         # cache
       
   102         self._url = url
       
   103         
       
   104         # done
       
   105         return url
       
   106 
       
   107 class PageTree (object) :
       
   108     """
       
   109         The tree of pages, rooted at .root.
       
   110 
       
   111         Use load_page_tree to initialize the global page_tree instance, and then use that
       
   112     """
       
   113 
       
   114     def __init__ (self) :
       
   115         """
       
   116             Empty PageList, must call load_page_list to initialize, once
       
   117         """
       
   118 
       
   119     def _load (self, path) :
       
   120         """
       
   121             Processes the lines in the given file
       
   122         """
       
   123         
       
   124         # parse tree
       
   125         tree = tree_parse.parse(path, ':')
       
   126 
       
   127         if not tree :
       
   128             raise PageTreeError("No root node found")
       
   129 
       
   130         def _create_node (parent, item) :
       
   131             """
       
   132                 Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
       
   133             """
       
   134 
       
   135             # unpack
       
   136             line_number, line, children = item
       
   137             
       
   138             # parse line
       
   139             url = title = None
       
   140             
       
   141             try :
       
   142                 url, title = line.split(':')
       
   143 
       
   144             except :
       
   145                 raise PageTreeError("Invalid line: %s:%d: %r" % (path, line_number, line))
       
   146 
       
   147             # remove whitespace
       
   148             url = url.strip()
       
   149             title = title.strip()
       
   150             
       
   151             # create PageInfo
       
   152             node = PageInfo(parent, url, title)
       
   153             
       
   154             # set node children
       
   155             node.children = [
       
   156                 _create_node(node, child_item) for child_item in children
       
   157             ]
       
   158 
       
   159             # return
       
   160             return node
       
   161         
       
   162         # translate
       
   163         self.root = _create_node(None, tree)
       
   164             
       
   165         # *evil cackle*
       
   166         self.root.children.insert(0, self.root)
       
   167         
       
   168     def get_page (self, url) :
       
   169         """
       
   170             Lookup the given page URL, and return the matching PageInfo object, or None, if not found
       
   171         """
       
   172         
       
   173         # start from root
       
   174         node = self.root
       
   175         
       
   176         # traverse the object tree
       
   177         for segment in url.split('/') :
       
   178             if segment :
       
   179                 node = node.get_child(segment)
       
   180 
       
   181             if not node :
       
   182                 return None
       
   183         
       
   184         # return
       
   185         return node
       
   186     
       
   187     def get_siblings (self, url) :
       
   188         """
       
   189             Get the list of siblings for the given url, including the given page itself
       
   190         """
       
   191         
       
   192         # look up the page itself
       
   193         page = self.get_page(url)
       
   194         
       
   195         # specialcase root/unknown node
       
   196         if page and page.parent :
       
   197             return page.parent.children
       
   198 
       
   199         else :
       
   200             return self.root.children
       
   201     
       
   202     def dump (self) :
       
   203         """
       
   204             Returns a string representation of the tree
       
   205         """
       
   206         
       
   207         def _print_node (indent, node) :
       
   208             return '\n'.join('%s%s' % (' '*indent, line) for line in [
       
   209                 "%-15s : %s" % (node.name, node.title)
       
   210             ] + [
       
   211                 _print_node(indent + 4, child) for child in node.children if child != node
       
   212             ])
       
   213 
       
   214         return _print_node(0, self.root)
       
   215 
       
   216 # global singleton PageList instance
       
   217 page_tree = PageTree()
       
   218 
       
   219 def load () :
       
   220     """
       
   221         Load the global singleton PageInfo instance
       
   222     """
       
   223     
       
   224     page_tree._load(PAGE_TREE_FILE)
       
   225