move lib.filesystem code to sites/www.qmsk.net, part one sites
authorTero Marttila <terom@fixme.fi>
Sat, 07 Feb 2009 17:10:06 +0200
branchsites
changeset 34 09196d5b2a39
parent 33 19ea04f4b0cd
child 35 79ea0e2a6cc2
move lib.filesystem code to sites/www.qmsk.net, part one
lib/filesystem/__init__.py
lib/filesystem/map.py
lib/filesystem/menu.py
lib/filesystem/page.py
lib/filesystem/page_tree.py
sites/www.qmsk.net/__init__.py
sites/www.qmsk.net/map.py
sites/www.qmsk.net/menu.py
sites/www.qmsk.net/page.py
sites/www.qmsk.net/page_tree.py
--- a/lib/filesystem/map.py	Sat Feb 07 17:07:06 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-
-import os, os.path
-
-from lib import http, template, map
-
-import page, page_tree
-
-class FilesystemMapper (map.Mapper) :
-    """
-        Translates requests to handlers based on a filesystem directory containing various kinds of files
-    """
-
-    # list of page handlers, by type
-    PAGE_TYPES = [
-        ('html',                    page.HTMLPage           ),
-        (template.TEMPLATE_EXT,     page.TemplatePage       ),
-    ]
-
-    def __init__ (self, path, template) :
-        """
-            Create, path is where the pages are stored. The list of pages is loaded from $path/list
-        """
-        
-        # store
-        self.path = path 
-        self.template = template
-
-        # load the page tree
-        self.tree = page_tree.PageTree(path + '/list')
-    
-    def _lookup_page_type (self, url, path, filename, basename, extension, tail) :
-        """
-            We found the file that we looked for, now get the correct type
-        """
-
-        # find appropriate handler
-        for handler_ext, type in self.PAGE_TYPES :
-            # match against file extension?
-            if handler_ext == extension :
-                # found handler, return instance
-                return type(self, url, path, basename, tail)
-
-        # no handler found
-        raise PageError("No handler found for page %r of type %r" % (url, extension))
-
-    def _lookup_page (self, name) :
-        """
-            Look up and return a Page object for the given page, or raise an error
-        """
-
-        # inital path
-        path = self.path
-        url_segments = []
-
-        # name segments
-        segments = name.split('/')
-
-        # iterate through the parts of the page segments
-        while True :
-            segment = None
-
-            # pop segment
-            if segments :
-                segment = segments.pop(0)
-
-                url_segments.append(segment)
-
-            # translate empty -> index
-            if not segment :
-                segment = 'index'
-
-            # look for it in the dir
-            for filename in os.listdir(path) :
-                # build full file path
-                file_path = os.path.join(path, filename)
-
-                # stat, recurse into subdirectory?
-                if os.path.isdir(file_path) and filename == segment :
-                    # use new dir
-                    path = file_path
-
-                    # break for-loop to look at next segment
-                    break
-     
-                # split into basename + extension
-                basename, extension = os.path.splitext(filename)
-
-                # ...remove that dot
-                extension = extension.lstrip('.')
-                
-                # match against requested page name?
-                if basename == segment :
-                    # found the file we wanted
-                    return self._lookup_page_type('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments))
-                
-                else :
-                    # inspect next file in dir
-                    continue
-
-            else :
-                # did not find any dir or file, break out of while loop
-                break
-
-        # did not find the filename we were looking for in os.listdir
-        raise PageError("Page not found: %s" % name, status='404 Not Found')
-
-    def handle_request (self, request) :
-        """
-            Looks up the appropriate Page, and then renders it
-        """
-
-        # determine the page name
-        page_name = request.get_page_name()
-
-        # get the page handler
-        page = self._lookup_page(page_name)
-        
-        # pass on
-        return page.handle_request(request)
-
--- a/lib/filesystem/menu.py	Sat Feb 07 17:07:06 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-"""
-    Handling the list of available pages
-"""
-
-class Menu (object) :
-    """
-        Contains info needed to render the menu
-    """
-
-    def __init__ (self, fs, page) :
-        """
-            Gather the menu information for the given page, as part of the given FilesystemMapper
-        """
-
-        # the selected page
-        self.page = fs.tree.get_page(page.url)
-
-        # the selected pagen's inheritance
-        self.ancestry = self.page.get_ancestry() if self.page else []
-        
-        # list of menu items == root children, since we always show the full menu...
-        self.items = fs.tree.root.children
-    
--- a/lib/filesystem/page.py	Sat Feb 07 17:07:06 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-
-"""
-    Handling page requests
-"""
-
-# for filesystem ops
-import os, os.path
-import time
-
-from lib import http, handler, template, config
-
-import menu
-
-class PageError (http.ResponseError) :
-    """
-        Error looking up/handling a page
-    """
-
-    pass
-
-# XXX: should inherit from PageInfo
-class Page (handler.RequestHandler) :
-    """
-        This object represents the information about our attempt to render some specific page
-    """
-
-    def __init__ (self, fs, url, path, basename, url_tail, charset='utf8') :
-        """
-            Initialize the page at the given location
-            
-            @param fs the FilesysteMapper
-            @param url the URL leading to this page
-            @param path the filesystem path to this page's file
-            @param basename the filesystem name of this page's file, without the file extension
-            @param url_trail trailing URL for this page
-            @param charset file charset
-        """
-        
-        # store
-        self.fs = fs
-        self.url = url
-        self.path = path
-        self.basename = basename
-        self.url_tail = url_tail
-        self.charset = charset
-
-        # sub-init
-        self._init()
-
-    def _init (self) :
-        """
-            Do initial data loading, etc
-        """
-        
-        pass
-
-    @property
-    def title (self) :
-        """
-            Return the page's title
-
-            Defaults to the retreiving the page title from page_list, or basename in Titlecase.
-        """
-        
-        # lookup in PageTree
-        page_info = self.fs.tree.get_page(self.url)
-        
-        # fallback to titlecase
-        if page_info :
-            title = page_info.title
-
-        else :
-            title = self.basename.title()
-
-        return title
-    
-    @property
-    def content (self) :
-        """
-            Return the page content as a string
-        """
-
-        abstract
-    
-    @property
-    def modified (self) :
-        """
-            Returns the page modification timestamp
-        """
-        
-        # stat
-        timestamp = os.stat(self.path).st_mtime
-
-        return time.strftime(config.DATETIME_FMT, time.gmtime(timestamp))
-    
-    def handle_request (self, request) :
-        """
-            Renders the fs's layout template with this page + menu
-        """
-
-        # render the template
-        response_data = template.render(self.fs.template,
-            request         = request,
-            site_root_url   = request.get_script_dir(),
-            site_page_url   = request.get_page_prefix(),
-            page            = self,
-            menu            = menu.Menu(self.fs, self),
-        )
-        
-        # return the response
-        return http.Response(response_data)
-
-class HTMLPage (Page) :
-    """
-        A simple .html page that's just passed through directly
-    """
-
-    @property
-    def content (self) :
-        """
-            Opens the .html file, reads and returns contents
-        """
-
-        return open(self.path, 'rb').read().decode(self.charset)
-
-class TemplatePage (Page) :
-    """
-        A template that's rendered using our template library
-    """
-    
-    @property
-    def content (self) :
-        """
-            Loads the .tmpl file, and renders it
-        """
-
-        return template.TemplateLoader.render_file(self.path,
-            page_tree   = self.fs.tree,
-        )
-
--- a/lib/filesystem/page_tree.py	Sat Feb 07 17:07:06 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-"""
-    Implements the tree containing pages and their metadata
-"""
-
-from lib import tree_parse
-
-class PageTreeError (Exception) :
-    """
-        Error parsing/loading the page tree
-    """
-
-    pass
-
-class PageInfo (object) :
-    """
-        Contains metainformation about a page
-    """
-
-    def __init__ (self, parent, name, title, children=None) :
-        """
-            Initialize, children defaults to empty list
-        """
-
-        # store
-        self.parent = parent
-        self.name = name
-        self.title = title
-        self.children = children if children else []
-
-        # no url get
-        self._url = None
-    
-    def set_parent (self, parent) :
-        """
-            Set a parent where non was set before
-        """
-
-        assert self.parent is None
-
-        self.parent = parent
-
-    def add_child (self, child) :
-        """
-            Add a PageInfo child
-        """
-
-        self.children.append(child)
-    
-    def get_child (self, name) :
-        """
-            Look up a child by name, returning None if not found
-        """
-
-        return dict((c.name, c) for c in self.children).get(name)
-
-    def get_ancestry (self) :
-        """
-            Returns a list of this page's parents and the page itself, but not root
-        """
-        
-        # collect in reverse order
-        ancestry = []
-        
-        # starting from self
-        item = self
-        
-        # add all items, but not root
-        while item and item.parent :
-            ancestry.append(item)
-
-            item = item.parent
-
-        # reverse
-        ancestry.reverse()
-        
-        # done
-        return ancestry
-
-    @property
-    def url (self) :
-        """
-            Build this page's URL
-        """
-
-        # cached?
-        if self._url :
-            return self._url
-
-        segments = [item.name for item in self.get_ancestry()]
-        
-        # add empty segment if dir
-        if self.children :
-            segments.append('')
-        
-        # join
-        url = '/'.join(segments)
-        
-        # cache
-        self._url = url
-        
-        # done
-        return url
-
-class PageTree (object) :
-    """
-        The tree of pages, rooted at .root.
-
-        Use load_page_tree to initialize the global page_tree instance, and then use that
-    """
-
-    def __init__ (self, path) :
-        """
-            Loads the PageTree root from the given file
-        """
-        
-        # store
-        self.path = path
-        
-        # load
-        self._load(path)
-
-    def _load (self, path) :
-        """
-            Processes the lines in the given file
-        """
-        
-        # parse tree
-        tree = tree_parse.parse(path, ':')
-
-        if not tree :
-            raise PageTreeError("No root node found")
-
-        def _create_node (parent, item) :
-            """
-                Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
-            """
-
-            # unpack
-            line_number, line, children = item
-            
-            # parse line
-            url = title = None
-            
-            try :
-                url, title = line.split(':')
-
-            except :
-                raise PageTreeError("Invalid line: %s:%d: %r" % (path, line_number, line))
-
-            # remove whitespace
-            url = url.strip()
-            title = title.strip()
-            
-            # create PageInfo
-            node = PageInfo(parent, url, title)
-            
-            # set node children
-            node.children = [
-                _create_node(node, child_item) for child_item in children
-            ]
-
-            # return
-            return node
-        
-        # translate
-        self.root = _create_node(None, tree)
-            
-        # *evil cackle*
-        self.root.children.insert(0, self.root)
-        
-    def get_page (self, url) :
-        """
-            Lookup the given page URL, and return the matching PageInfo object, or None, if not found
-        """
-        
-        # start from root
-        node = self.root
-        
-        # traverse the object tree
-        for segment in url.split('/') :
-            if segment :
-                node = node.get_child(segment)
-
-            if not node :
-                return None
-        
-        # return
-        return node
-    
-    def get_siblings (self, url) :
-        """
-            Get the list of siblings for the given url, including the given page itself
-        """
-        
-        # look up the page itself
-        page = self.get_page(url)
-        
-        # specialcase root/unknown node
-        if page and page.parent :
-            return page.parent.children
-
-        else :
-            return self.root.children
-    
-    def dump (self) :
-        """
-            Returns a string representation of the tree
-        """
-        
-        def _print_node (indent, node) :
-            return '\n'.join('%s%s' % (' '*indent, line) for line in [
-                "%-15s : %s" % (node.name, node.title)
-            ] + [
-                _print_node(indent + 4, child) for child in node.children if child != node
-            ])
-
-        return _print_node(0, self.root)
-
--- a/sites/www.qmsk.net/__init__.py	Sat Feb 07 17:07:06 2009 +0200
+++ b/sites/www.qmsk.net/__init__.py	Sat Feb 07 17:10:06 2009 +0200
@@ -3,8 +3,8 @@
 """
 
 from lib import template
-from lib.filesystem.map import FilesystemMapper as _fstree
+import map
 
 # global mapper attribute
-handler = _fstree("pages", template=template.TemplateLoader.load("sites/www.qmsk.net/templates/layout.tmpl"))
+handler = map.FilesystemMapper("pages", template=template.TemplateLoader.load("sites/www.qmsk.net/templates/layout.tmpl"))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/www.qmsk.net/map.py	Sat Feb 07 17:10:06 2009 +0200
@@ -0,0 +1,120 @@
+
+import os, os.path
+
+from lib import http, template, map
+
+import page, page_tree
+
+class FilesystemMapper (map.Mapper) :
+    """
+        Translates requests to handlers based on a filesystem directory containing various kinds of files
+    """
+
+    # list of page handlers, by type
+    PAGE_TYPES = [
+        ('html',                    page.HTMLPage           ),
+        (template.TEMPLATE_EXT,     page.TemplatePage       ),
+    ]
+
+    def __init__ (self, path, template) :
+        """
+            Create, path is where the pages are stored. The list of pages is loaded from $path/list
+        """
+        
+        # store
+        self.path = path 
+        self.template = template
+
+        # load the page tree
+        self.tree = page_tree.PageTree(path + '/list')
+    
+    def _lookup_page_type (self, url, path, filename, basename, extension, tail) :
+        """
+            We found the file that we looked for, now get the correct type
+        """
+
+        # find appropriate handler
+        for handler_ext, type in self.PAGE_TYPES :
+            # match against file extension?
+            if handler_ext == extension :
+                # found handler, return instance
+                return type(self, url, path, basename, tail)
+
+        # no handler found
+        raise PageError("No handler found for page %r of type %r" % (url, extension))
+
+    def _lookup_page (self, name) :
+        """
+            Look up and return a Page object for the given page, or raise an error
+        """
+
+        # inital path
+        path = self.path
+        url_segments = []
+
+        # name segments
+        segments = name.split('/')
+
+        # iterate through the parts of the page segments
+        while True :
+            segment = None
+
+            # pop segment
+            if segments :
+                segment = segments.pop(0)
+
+                url_segments.append(segment)
+
+            # translate empty -> index
+            if not segment :
+                segment = 'index'
+
+            # look for it in the dir
+            for filename in os.listdir(path) :
+                # build full file path
+                file_path = os.path.join(path, filename)
+
+                # stat, recurse into subdirectory?
+                if os.path.isdir(file_path) and filename == segment :
+                    # use new dir
+                    path = file_path
+
+                    # break for-loop to look at next segment
+                    break
+     
+                # split into basename + extension
+                basename, extension = os.path.splitext(filename)
+
+                # ...remove that dot
+                extension = extension.lstrip('.')
+                
+                # match against requested page name?
+                if basename == segment :
+                    # found the file we wanted
+                    return self._lookup_page_type('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments))
+                
+                else :
+                    # inspect next file in dir
+                    continue
+
+            else :
+                # did not find any dir or file, break out of while loop
+                break
+
+        # did not find the filename we were looking for in os.listdir
+        raise PageError("Page not found: %s" % name, status='404 Not Found')
+
+    def handle_request (self, request) :
+        """
+            Looks up the appropriate Page, and then renders it
+        """
+
+        # determine the page name
+        page_name = request.get_page_name()
+
+        # get the page handler
+        page = self._lookup_page(page_name)
+        
+        # pass on
+        return page.handle_request(request)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/www.qmsk.net/menu.py	Sat Feb 07 17:10:06 2009 +0200
@@ -0,0 +1,23 @@
+"""
+    Handling the list of available pages
+"""
+
+class Menu (object) :
+    """
+        Contains info needed to render the menu
+    """
+
+    def __init__ (self, fs, page) :
+        """
+            Gather the menu information for the given page, as part of the given FilesystemMapper
+        """
+
+        # the selected page
+        self.page = fs.tree.get_page(page.url)
+
+        # the selected pagen's inheritance
+        self.ancestry = self.page.get_ancestry() if self.page else []
+        
+        # list of menu items == root children, since we always show the full menu...
+        self.items = fs.tree.root.children
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/www.qmsk.net/page.py	Sat Feb 07 17:10:06 2009 +0200
@@ -0,0 +1,140 @@
+
+"""
+    Handling page requests
+"""
+
+# for filesystem ops
+import os, os.path
+import time
+
+from lib import http, handler, template, config
+
+import menu
+
+class PageError (http.ResponseError) :
+    """
+        Error looking up/handling a page
+    """
+
+    pass
+
+# XXX: should inherit from PageInfo
+class Page (handler.RequestHandler) :
+    """
+        This object represents the information about our attempt to render some specific page
+    """
+
+    def __init__ (self, fs, url, path, basename, url_tail, charset='utf8') :
+        """
+            Initialize the page at the given location
+            
+            @param fs the FilesysteMapper
+            @param url the URL leading to this page
+            @param path the filesystem path to this page's file
+            @param basename the filesystem name of this page's file, without the file extension
+            @param url_trail trailing URL for this page
+            @param charset file charset
+        """
+        
+        # store
+        self.fs = fs
+        self.url = url
+        self.path = path
+        self.basename = basename
+        self.url_tail = url_tail
+        self.charset = charset
+
+        # sub-init
+        self._init()
+
+    def _init (self) :
+        """
+            Do initial data loading, etc
+        """
+        
+        pass
+
+    @property
+    def title (self) :
+        """
+            Return the page's title
+
+            Defaults to the retreiving the page title from page_list, or basename in Titlecase.
+        """
+        
+        # lookup in PageTree
+        page_info = self.fs.tree.get_page(self.url)
+        
+        # fallback to titlecase
+        if page_info :
+            title = page_info.title
+
+        else :
+            title = self.basename.title()
+
+        return title
+    
+    @property
+    def content (self) :
+        """
+            Return the page content as a string
+        """
+
+        abstract
+    
+    @property
+    def modified (self) :
+        """
+            Returns the page modification timestamp
+        """
+        
+        # stat
+        timestamp = os.stat(self.path).st_mtime
+
+        return time.strftime(config.DATETIME_FMT, time.gmtime(timestamp))
+    
+    def handle_request (self, request) :
+        """
+            Renders the fs's layout template with this page + menu
+        """
+
+        # render the template
+        response_data = template.render(self.fs.template,
+            request         = request,
+            site_root_url   = request.get_script_dir(),
+            site_page_url   = request.get_page_prefix(),
+            page            = self,
+            menu            = menu.Menu(self.fs, self),
+        )
+        
+        # return the response
+        return http.Response(response_data)
+
+class HTMLPage (Page) :
+    """
+        A simple .html page that's just passed through directly
+    """
+
+    @property
+    def content (self) :
+        """
+            Opens the .html file, reads and returns contents
+        """
+
+        return open(self.path, 'rb').read().decode(self.charset)
+
+class TemplatePage (Page) :
+    """
+        A template that's rendered using our template library
+    """
+    
+    @property
+    def content (self) :
+        """
+            Loads the .tmpl file, and renders it
+        """
+
+        return template.TemplateLoader.render_file(self.path,
+            page_tree   = self.fs.tree,
+        )
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/www.qmsk.net/page_tree.py	Sat Feb 07 17:10:06 2009 +0200
@@ -0,0 +1,218 @@
+"""
+    Implements the tree containing pages and their metadata
+"""
+
+from lib import tree_parse
+
+class PageTreeError (Exception) :
+    """
+        Error parsing/loading the page tree
+    """
+
+    pass
+
+class PageInfo (object) :
+    """
+        Contains metainformation about a page
+    """
+
+    def __init__ (self, parent, name, title, children=None) :
+        """
+            Initialize, children defaults to empty list
+        """
+
+        # store
+        self.parent = parent
+        self.name = name
+        self.title = title
+        self.children = children if children else []
+
+        # no url get
+        self._url = None
+    
+    def set_parent (self, parent) :
+        """
+            Set a parent where non was set before
+        """
+
+        assert self.parent is None
+
+        self.parent = parent
+
+    def add_child (self, child) :
+        """
+            Add a PageInfo child
+        """
+
+        self.children.append(child)
+    
+    def get_child (self, name) :
+        """
+            Look up a child by name, returning None if not found
+        """
+
+        return dict((c.name, c) for c in self.children).get(name)
+
+    def get_ancestry (self) :
+        """
+            Returns a list of this page's parents and the page itself, but not root
+        """
+        
+        # collect in reverse order
+        ancestry = []
+        
+        # starting from self
+        item = self
+        
+        # add all items, but not root
+        while item and item.parent :
+            ancestry.append(item)
+
+            item = item.parent
+
+        # reverse
+        ancestry.reverse()
+        
+        # done
+        return ancestry
+
+    @property
+    def url (self) :
+        """
+            Build this page's URL
+        """
+
+        # cached?
+        if self._url :
+            return self._url
+
+        segments = [item.name for item in self.get_ancestry()]
+        
+        # add empty segment if dir
+        if self.children :
+            segments.append('')
+        
+        # join
+        url = '/'.join(segments)
+        
+        # cache
+        self._url = url
+        
+        # done
+        return url
+
+class PageTree (object) :
+    """
+        The tree of pages, rooted at .root.
+
+        Use load_page_tree to initialize the global page_tree instance, and then use that
+    """
+
+    def __init__ (self, path) :
+        """
+            Loads the PageTree root from the given file
+        """
+        
+        # store
+        self.path = path
+        
+        # load
+        self._load(path)
+
+    def _load (self, path) :
+        """
+            Processes the lines in the given file
+        """
+        
+        # parse tree
+        tree = tree_parse.parse(path, ':')
+
+        if not tree :
+            raise PageTreeError("No root node found")
+
+        def _create_node (parent, item) :
+            """
+                Creates and returns a PageInfo from the given parent node and (line_number, line, children) tuple item
+            """
+
+            # unpack
+            line_number, line, children = item
+            
+            # parse line
+            url = title = None
+            
+            try :
+                url, title = line.split(':')
+
+            except :
+                raise PageTreeError("Invalid line: %s:%d: %r" % (path, line_number, line))
+
+            # remove whitespace
+            url = url.strip()
+            title = title.strip()
+            
+            # create PageInfo
+            node = PageInfo(parent, url, title)
+            
+            # set node children
+            node.children = [
+                _create_node(node, child_item) for child_item in children
+            ]
+
+            # return
+            return node
+        
+        # translate
+        self.root = _create_node(None, tree)
+            
+        # *evil cackle*
+        self.root.children.insert(0, self.root)
+        
+    def get_page (self, url) :
+        """
+            Lookup the given page URL, and return the matching PageInfo object, or None, if not found
+        """
+        
+        # start from root
+        node = self.root
+        
+        # traverse the object tree
+        for segment in url.split('/') :
+            if segment :
+                node = node.get_child(segment)
+
+            if not node :
+                return None
+        
+        # return
+        return node
+    
+    def get_siblings (self, url) :
+        """
+            Get the list of siblings for the given url, including the given page itself
+        """
+        
+        # look up the page itself
+        page = self.get_page(url)
+        
+        # specialcase root/unknown node
+        if page and page.parent :
+            return page.parent.children
+
+        else :
+            return self.root.children
+    
+    def dump (self) :
+        """
+            Returns a string representation of the tree
+        """
+        
+        def _print_node (indent, node) :
+            return '\n'.join('%s%s' % (' '*indent, line) for line in [
+                "%-15s : %s" % (node.name, node.title)
+            ] + [
+                _print_node(indent + 4, child) for child in node.children if child != node
+            ])
+
+        return _print_node(0, self.root)
+