]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
merge of new documentation generation system
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Oct 2006 20:57:10 +0000 (20:57 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Oct 2006 20:57:10 +0000 (20:57 +0000)
28 files changed:
CHANGES
README
doc/build/README [new file with mode: 0644]
doc/build/compile_docstrings.py [deleted file]
doc/build/components/autohandler
doc/build/components/base.myt [new file with mode: 0644]
doc/build/components/content_layout.myt [new file with mode: 0644]
doc/build/components/doclib.myt [deleted file]
doc/build/components/formatting.myt
doc/build/components/index.myt [deleted file]
doc/build/components/nav.myt [new file with mode: 0644]
doc/build/components/printsection.myt [deleted file]
doc/build/components/pydoc.myt
doc/build/components/section_wrapper.myt [deleted file]
doc/build/components/toc.myt [new file with mode: 0644]
doc/build/content/docstrings.myt
doc/build/content/document_base.myt [deleted file]
doc/build/content/index.myt [new file with mode: 0644]
doc/build/content/metadata.txt
doc/build/content/tutorial.txt
doc/build/gen_docstrings.py [new file with mode: 0644]
doc/build/genhtml.py
doc/build/lib/docstring.py
doc/build/lib/documentgen.py [deleted file]
doc/build/lib/toc.py [new file with mode: 0644]
doc/build/read_markdown.py [new file with mode: 0644]
doc/build/runhtml.py
doc/build/txt2myt.py [deleted file]

diff --git a/CHANGES b/CHANGES
index 95bd4bc65dd0595dfe3685390746513fdd2bc596..3cd19c9d18c2a95c6dfcc4ae192017d0370a66cd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -10,6 +10,8 @@
     Test suite includes "--log-info" and "--log-debug" arguments
     which work independently of --verbose/--quiet.  Logging added
     to orm to allow tracking of mapper configurations, row iteration.
+    - the documentation-generation system has been overhauled to be
+    much simpler in design and more integrated with Markdown
 - Specific Databases:
     - SQLite:
     - sqlite boolean datatype converts False/True to 0/1 by default
diff --git a/README b/README
index 8c398b7c44d2be432d662018a79c7e89d5fc359f..f4726e164f09f27a9cd793ce8f5427319a21ff40 100644 (file)
--- a/README
+++ b/README
@@ -11,14 +11,6 @@ an svn-tagged build.
 
 Documentation is available in HTML format in the ./doc/ directory.
 
-The "raw" format of the documentation is Markdown with a few extra syntaxes 
-added in; those files are present in ./doc/build/content/.
-
-To fully generate the documentation into both Myghty and HTML format:
-
-       cd ./doc/build/
-       python genhtml.py
-
 Information running unit tests is in README.unittests. 
 
 good luck !
diff --git a/doc/build/README b/doc/build/README
new file mode 100644 (file)
index 0000000..ce7570f
--- /dev/null
@@ -0,0 +1,10 @@
+Documentation exists in its original format as Markdown files in the ./content directory.
+
+To generate documentation:
+
+       python genhtml.py
+
+This generates the Markdown files into Myghty templates as an interim step and then into HTML.  It also
+creates two pickled datafiles corresponding to the table of contents and all the generated docstrings
+for the SQLAlchemy sourcecode.
+
diff --git a/doc/build/compile_docstrings.py b/doc/build/compile_docstrings.py
deleted file mode 100644 (file)
index 4ddc8cb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import cPickle as pickle
-import sys, os
-
-sys.path = ['../../lib', './lib/'] + sys.path
-
-import docstring
-
-import sqlalchemy.schema as schema
-import sqlalchemy.engine as engine
-import sqlalchemy.engine.strategies as strategies
-import sqlalchemy.sql as sql
-import sqlalchemy.pool as pool
-import sqlalchemy.orm as orm
-import sqlalchemy.exceptions as exceptions
-import sqlalchemy.ext.proxy as proxy
-import sqlalchemy.ext.sessioncontext as sessioncontext
-import sqlalchemy.mods.threadlocal as threadlocal
-import sqlalchemy.ext.selectresults as selectresults
-
-objects = []
-def make_doc(obj, classes=None, functions=None):
-    objects.append(docstring.ObjectDoc(obj, classes=classes, functions=functions))
-
-make_doc(obj=sql)
-make_doc(obj=schema)
-make_doc(obj=engine)
-make_doc(obj=engine.url)
-make_doc(obj=orm, classes=[orm.MapperExtension])
-make_doc(obj=orm.mapperlib, classes=[orm.mapperlib.Mapper])
-make_doc(obj=orm.query, classes=[orm.query.Query, orm.query.OperationContext, orm.query.QueryContext, orm.query.SelectionContext])
-make_doc(obj=orm.session, classes=[orm.session.Session, orm.session.SessionTransaction])
-make_doc(obj=pool, classes=[pool.DBProxy, pool.Pool, pool.QueuePool, pool.SingletonThreadPool])
-make_doc(obj=sessioncontext)
-make_doc(obj=threadlocal)
-make_doc(obj=selectresults)
-make_doc(obj=exceptions)
-make_doc(obj=proxy)
-
-
-output = os.path.join(os.getcwd(), 'content', "compiled_docstrings.pickle")
-pickle.dump(objects, file(output, 'w'))
index 38f964fcb48a3e927cdba85f57b669c6a431d630..223b7ff615945ee00b9174cc63cf29aab2fec2ad 100644 (file)
@@ -2,6 +2,11 @@
 <html>
 <head>
        <title><& REQUEST:title &></title>
+    <link href="style.css" rel="stylesheet" type="text/css"></link>
+    <link href="syntaxhighlight.css" rel="stylesheet" type="text/css"></link>
+
+    <link href="docs.css" rel="stylesheet" type="text/css"></link>
+    <script src="scripts.js"></script>
 </head>
 <body>
 
diff --git a/doc/build/components/base.myt b/doc/build/components/base.myt
new file mode 100644 (file)
index 0000000..7d6e7ba
--- /dev/null
@@ -0,0 +1,38 @@
+<%doc>base.myt - common to all documentation pages. intentionally separate from autohandler, which can be swapped
+out for a different one</%doc>
+<%args>
+    extension="myt"
+</%args>
+<%python scope="init">
+    if m.cache_self(key=m.request_component.file):
+        return
+    # bootstrap TOC structure from request args, or pickled file if not present.
+    import cPickle as pickle
+    import os, time
+    m.log("base.myt generating from table of contents for file %s" % m.request_component.file)
+    toc = m.request_args.get('toc')
+    if toc is None:
+        filename = os.path.join(os.path.dirname(m.request_component.file), 'table_of_contents.pickle')
+        toc = pickle.load(file(filename))
+    version = toc.version
+    last_updated = toc.last_updated
+</%python>
+<%method title>
+    <% m.request_component.attributes.get('title') %>
+</%method>
+
+<div style="position:absolute;left:0px;top:0px;"><a name="top"></a>&nbsp;</div>
+
+<div class="doccontainer">
+
+<div class="docheader">
+
+<h1><% toc.root.doctitle %></h1>
+<div class="">Version: <% version %>   Last Updated: <% time.strftime('%x %X', time.localtime(last_updated)) %></div>
+</div>
+
+% m.call_next(toc=toc, extension=extension)
+
+</div>
+
+
diff --git a/doc/build/components/content_layout.myt b/doc/build/components/content_layout.myt
new file mode 100644 (file)
index 0000000..c44a6f3
--- /dev/null
@@ -0,0 +1,15 @@
+<%doc>defines the default layout for normal documentation pages (not including the index)</%doc>
+<%args>
+    extension="myt"
+    toc
+</%args>
+<%flags>inherit="base.myt"</%flags>
+<%init>
+    current = toc.get_by_file(m.request_component.attributes['filename'])
+</%init>
+
+<A name="<% current.path %>"></a>
+<& nav.myt:topnav, item=current, extension=extension &>
+<div class="sectioncontent">
+% m.call_next(toc=toc, extension=extension)
+</div>
diff --git a/doc/build/components/doclib.myt b/doc/build/components/doclib.myt
deleted file mode 100644 (file)
index 12efa1d..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-
-<%python scope="global">
-import sys, string, re
-
-# datastructure that will store the whole contents of the documentation
-class TOCElement:
-    def __init__(self, filename, name, description, parent = None, ext = None, header = None, last_updated = 0, htmldescription=None, altlink=None):
-        self.filename = filename
-        self.name = name
-        self.parent = parent
-        self.path = self._create_path()
-        self.header = header
-        self.altlink = altlink
-        if self.parent is not None:
-            self.root = parent.root
-            self.root.pathlookup[self.path] = self
-
-            if self.parent.filename != self.filename:
-                self.root.filelookup[self.filename] = self
-                self.isTop = True
-        else:
-            self.root = self
-            self.pathlookup = {}
-            self.pathlookup[''] = self
-            self.filelookup = {}
-            self.filelookup[filename] = self
-
-        if ext is not None:
-            self.ext = ext
-        else:
-            self.ext = self.root.ext
-
-        self.last_updated = last_updated    
-        self.description = description
-        self.htmldescription = htmldescription
-        self.content = None
-        self.previous = None
-        self.next = None
-        self.children = []
-        if parent:
-            if len(parent.children):
-                self.previous = parent.children[-1]
-                parent.children[-1].next = self
-            parent.children.append(self)
-            if last_updated > parent.last_updated:
-                parent.last_updated = self.last_updated
-
-    def get_file(self, name):
-        name = re.sub("\.\w+$", "", name)
-        return self.root.filelookup[name]
-
-    def lookup(self, path):
-        return self.root.pathlookup[path]
-
-    def get_link(self, includefile = True, anchor = True):
-        if includefile:
-            if anchor:
-                return "%s%s#%s" % (self.filename, self.ext, self.path) 
-            else:
-                return "%s%s" % (self.filename, self.ext)
-        else:
-            if anchor:
-                return "#" + self.path  
-            else:
-                return ""
-
-        
-    def _create_path(self):
-        elem = self
-        tokens = []
-        while elem.parent is not None:
-            tokens.insert(0, elem.name)
-            elem = elem.parent
-        path = string.join(tokens, '_')
-        return path
-
-
-
-</%python>
-
-<%python scope="request">
-    current = Value()
-    filename = Value()
-</%python>
-
-
-<%args scope="request">
-    paged = 'yes'
-</%args>
-
-<%python scope="init">
-
-    try:
-        a = r
-        isdynamic = True
-        ext = ".myt"
-    except:
-        isdynamic = False
-        ext = ".html"
-        
-    request_comp = m.request_comp()
-
-    if isdynamic and not m.interpreter.attributes.get('docs_static_cache', False):
-        page_cache = True
-    else:
-        page_cache = False
-
-    # for dynamic page, cache the output of the final page
-    
-    if page_cache:
-        if m.cache_self(key="doc_%s" % paged, component = request_comp):
-            return
-
-    list_comp = m.fetch_next()
-    files = request_comp.attributes['files']
-    title = request_comp.attributes.setdefault('title', "Documentation")
-    version = request_comp.attributes['version']
-    wrapper = request_comp.attributes['wrapper']
-    index = request_comp.attributes['index']
-    onepage = request_comp.attributes['onepage']
-
-
-
-    def buildtoc():
-        root = TOCElement("", "root", "root element", ext = ext)
-        current.assign(root) 
-    
-        for file in files:
-            filename.assign(file)
-            comp = m.fetch_component(file + ".myt")
-        
-            main = m.scomp(comp)
-
-        return root
-
-    if not page_cache:
-        # non-dynamic (i.e. command-line) page, cache the datastructure so successive
-        # pages are fast (disables auto-recompiling)
-        cache = m.get_cache(list_comp)
-
-        toc = cache.get_value('toc', createfunc = buildtoc)
-    
-    else:
-        toc = buildtoc()
-
-    last_updated = toc.last_updated
-    m.comp(wrapper, isdynamic=isdynamic, ext = ext, toc = toc, comp = request_comp, onepage = onepage, paged = paged, title = title, version = version, index=index, last_updated = last_updated)
-
-</%python>
-
-<%method title>
-<% m.request_comp().get_attribute('title', inherit = True) or "Documentation" %>
-</%method>
-
-<%method item>
-    <%doc>stores an item in the table of contents</%doc>
-    <%args>
-        # name should be a URL friendly name used for hyperlinking the section
-        name
-
-        # description is the heading for the item
-        description
-
-        htmldescription = None
-        escapedesc = False
-        
-        header = None
-        altlink=None
-    </%args>
-    <%python scope="init">
-        if escapedesc:
-            description = m.apply_escapes(description, ['h'])
-
-        current(TOCElement(filename(), name, description, current(), header = header, last_updated = m.caller.component_source.last_modified, htmldescription=htmldescription, altlink=altlink))
-        current().content = m.content()
-        current(current().parent)
- </%python></%method>
-
-
-<%method current>
-<%init>return current()</%init>
-</%method>
-
-
-
-
-
index ee9fb3958da6d535ae7195d7beece6e3d41ca545..da1c81df05b265432fc2c485a99c4acf7d32b7a2 100644 (file)
-<%doc>formatting.myt - library of HTML formatting functions to operate on a TOCElement tree</%doc>
+<%doc>formatting.myt - Provides section formatting elements, syntax-highlighted code blocks, and other special filters.</%doc>
 
 <%global>
     import string, re
     import highlight
 </%global>
 
-
-<%method printtoc>
-<%args> 
-    root
-    includefile
-    current = None
-    full = False
-    children = True
-</%args>
-
-% header = False
-<ul class="toc_list">
-% for i in root.children:
-
-%   if i.header:
-%       if header:
-    </ul>
-%
-%   header = True
-    <h3><% i.header %></h3>
-    <ul class="toc_list">
-%
-    <& printtocelement, item=i, includefile = includefile, bold = (i == current and includefile), full = full, children=children &>
-%
-
-</ul>
-</%method>
-
-<%def printtocelement>
-<%doc>prints a TOCElement as a table of contents item and prints its immediate child items</%doc>
-    <%args>
-        item
-        includefile
-        bold = False
-        full = False
-        children = True
-    </%args>
-
-        <li><A style="<% bold and "font-weight:bold;" or "" %>" href="<% item.get_link(includefile, anchor = (not includefile)) %>"><% item.description %></a></li>
-    
-% if children:  
-    <ul class="small_toc_list">
-%   for i in item.children:
-        <& printsmtocelem, item=i, includefile = includefile, children=full &>
-%
-    </ul>
-%
-</%def>
-
-<%def printsmtocelem>
-    <%args>
-        item
-        includefile
-        children = False
-    </%args>    
-    <li><A href="<% item.get_link(includefile) %>"><% item.description %></a></li>
-
-% if children:
-    <ul class="small_toc_list">
-%   for i in item.children:
-        <& printsmtocelem, item = i, includefile = includefile &>
-%
-    </ul>
-%
-
-</%def>
-
-
-
-<%method printitem>
-<%doc>prints the description and contents of a TOC element and recursively prints its child items</%doc>
-
+<%method section>
+<%doc>Main section formatting element.</%doc>
 <%args>
-    item
-    indentlevel = 0
-    includefile
-    omitheader = False
-    root = None
+    toc
+    path
+    description=None
 </%args>
+<%init>
+    item = toc.get_by_path(path)
+    if item is None:
+        raise "path: " + path
+</%init>
 
-% if root is None: root = item
-
-% if not omitheader:
 <A name="<% item.path %>"></a>
-% if item.altlink:
-<A name="<% item.altlink %>"></a>
-%
-%
-
-<div class="subsection" style="margin-left:<% repr(10 + indentlevel * 10) %>px;">
 
+<div class="subsection" style="margin-left:<% repr(item.depth * 10) %>px;">
 
 <%python>
-    regexp = re.compile(r"__FORMAT:LINK{(?:\@path=(.+?))?(?:\@xtra=(.+?))?(?:\@text=(.+?))?(?:\@href=(.+?))?(?:\@class=(.+?))?}")
-    def link(matchobj):
-        path = matchobj.group(1)
-        xtra = matchobj.group(2)
-        text = matchobj.group(3)
-        href = matchobj.group(4)
-        class_ = matchobj.group(5)
-        
-        if class_ is not None:
-            class_ = 'class="%s"' % class_
-        else:
-            class_ = ''        
-            
-        if href:
-            return '<a href="%s" %s>%s</a>' % (href, class_, text or href)
-        else:
-            try:
-                element = item.lookup(path)
-                if xtra is not None:
-                    return '<a href="%s_%s" %s>%s</a>' % (element.get_link(includefile), xtra, class_, text or xtra)
-                else:
-                    return '<a href="%s" %s>%s</a>' % (element.get_link(includefile), class_, text or element.description)
-            except KeyError:
-                if xtra is not None:
-                    return '<b>%s</b>' % (text or xtra)
-                else:
-                    return '<b>%s</b>' % text or path
-
+    content = m.content()
     re2 = re.compile(r"'''PYESC(.+?)PYESC'''", re.S)
-    content = regexp.sub(link, item.content)
     content = re2.sub(lambda m: m.group(1), content)
-    description = regexp.sub(link, item.htmldescription or item.description)
 </%python>
 
-% if not omitheader:
-    <h3><% description %></h3>
+% if item.depth > 1:
+<h3><% description or item.description %></h3>
 %
-    <div class="sectiontext">
-
-<%python>
-    #m.write(item.content)
-    m.write(content)
-</%python>
 
+    <div class="sectiontext">
+    <% content %>
     </div>
 
-%   for i in item.children:
-        <& printitem, item=i, indentlevel=indentlevel + 1, includefile = includefile, root=root &>
-%
-
-% if root is not None and len(item.children) == 0:
-    <a href="#<% root.path %>" class="toclink">back to section top</a>
+% if item.depth > 1:
+%   if (item.next and item.next.depth >= item.depth):
+    <a href="#<% item.get_page_root().path %>" class="toclink">back to section top</a>
 %
-
-% if indentlevel == 0:
-%   if includefile:
-    <& SELF:pagenav, item=item, includefile=includefile &>
-%   else:
-    <hr width="400px" align="left" />
-% #
+% else:
+    <a href="#<% item.get_page_root().path %>" class="toclink">back to section top</a>
+    <& nav.myt:pagenav, item=item &>
 % 
-
 </div>
 
 </%method>
 
-<%method pagenav>
-<%args>
-    item
-    includefile
-</%args>
-<div class="sectionnavblock">
-<div class="sectionnav">
-
-% if not includefile:
-    <a href="#top">Top</a> |
-%
-
-%       if item.previous is not None:
-        Previous: <& SELF:itemlink, item=item.previous, includefile = includefile &>
-%       # end if
-
-%       if item.next is not None:
-%               if item.previous is not None:
-                |
-%               # end if
-
-        Next: <& SELF:itemlink, item=item.next, includefile = includefile &>
-%       # end if
-
-</div>
-</div>
-</%method>
 
 <%method formatplain>
     <%filter>
 <% m.content() | h%>
 </%method>
 
-<%method itemlink trim="both">
-    <%args>
-    item
-    includefile
-    </%args>
-    <a href="<% item.get_link(includefile, anchor = (not includefile)) %>"><% item.description %></a>
-</%method>
-
 
 
-<%method paramtable>
-    <table cellspacing="0" cellpadding="0" width="100%">
-    <% m.content() %>
-    </table>
-</%method>
-
-<%method member_doc>
-       <%args>
-               name = ""
-               link = ""
-               type = None
-       </%args>
-       <tr>
-       <td>
-           <div class="darkcell">
-           <A name="<% m.comp('doclib.myt:current').path %>_<% link %>"></a>
-           <b><% name %></b>
-           <div class="docstring"><% m.content() %></div>
-           </div>
-       </td>
-       </tr>
-</%method>
-
-
-<%method function_doc>
-    <%args>
-        name = ""
-        link = ""
-        alt = None
-        arglist = []
-        rettype = None
-    </%args>
-    <tr>
-    <td>
-        <div class="darkcell">
-        <A name="<% m.comp('doclib.myt:current').path %>_<% link %>"></a>
-        <b><% name %>(<% string.join(map(lambda k: "<i>%s</i>" % k, arglist), ", ")%>)</b>
-        <div class="docstring"><% m.content() %></div>
-        </div>
-    </td>
-    </tr>
-</%method>
 
 <%method codeline trim="both">
 <span class="codeline"><% m.content() %></span>
 <% content %></div>
 </%method>
 
-<%method link trim="both">
-    <%args>
-        path = None
-        param = None
-        method = None
-        member = None
-        text = None
-        href = None
-        class_ = None
-    </%args>
-    <%init>
-        if href is None and path is None:
-            path = m.comp('doclib.myt:current').path
-            
-        extra = (param or method or member)
-    </%init>
-__FORMAT:LINK{<% path and "@path=" + path or "" %><% extra and "@xtra=" + extra or "" %><% text and "@text=" + text or "" %><% href and "@href=" + href or "" %><% class_ and "@class=" + class_ or "" %>}
-</%method>
+
+
 
 <%method popboxlink trim="both"> 
     <%args>
@@ -354,7 +145,7 @@ javascript:togglePopbox('<% name %>', '<% show %>', '<% hide %>')
     <%init>
         href = m.scomp('SELF:popboxlink')
     </%init>
-    '''PYESC<& SELF:link, href=href, text=link, class_="codepoplink" &>PYESC'''
+    '''PYESC<& nav.myt:link, href=href, text=link, class_="codepoplink" &>PYESC'''
 </%method>
 
 <%method codepopper trim="both">
diff --git a/doc/build/components/index.myt b/doc/build/components/index.myt
deleted file mode 100644 (file)
index c55dfc2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<%flags>inherit="document_base.myt"</%flags>
-
diff --git a/doc/build/components/nav.myt b/doc/build/components/nav.myt
new file mode 100644 (file)
index 0000000..a045df8
--- /dev/null
@@ -0,0 +1,106 @@
+<%doc>nav.myt - Provides page navigation elements that are derived from toc.TOCElement structures, including
+individual hyperlinks as well as navigational toolbars and table-of-content listings.</%doc>
+
+<%method itemlink trim="both">
+    <%args>
+    item
+    anchor=True
+    </%args>
+    <%args scope="request">
+        extension='myt'
+    </%args>
+    <a href="<% item.get_link(extension=extension, anchor=anchor) %>"><% item.description %></a>
+</%method>
+
+<%method toclink trim="both">
+    <%args>
+        toc 
+        path
+        description=None
+        extension
+    </%args>
+    <%init>
+        item = toc.get_by_path(path)
+        if description is None:
+            if item:
+                description = item.description
+            else:
+                description = path
+    </%init>
+% if item:
+    <a href="<% item.get_link(extension=extension) %>"><% description %></a>
+% else:
+    <b><% description %></b>
+%
+</%method>
+
+
+<%method link trim="both">
+    <%args>
+        href
+        text
+        class_
+    </%args>
+    <a href="<% href %>" <% class_ and (('class=\"%s\"' % class_) or '')%>><% text %></a>
+</%method>
+
+<%method topnav>
+       <%args>
+               item
+               extension
+       </%args>
+<div class="topnav">
+
+<div class="topnavsectionlink">
+
+<a href="index.<% extension %>">Table of Contents</a>
+
+<div class="prevnext">
+% if item.previous is not None:
+Previous: <& itemlink, item=item.previous, anchor=False &>
+%
+
+% if item.previous is not None and item.next is not None:
+&nbsp; | &nbsp;
+%
+
+% if item.next is not None:
+
+Next: <& itemlink, item=item.next, anchor=False &>
+%
+
+</div>
+</div>
+
+<div class="topnavmain">
+       <div class="topnavheader"><% item.description %></div>
+       <div class="topnavitems">
+       <& toc.myt:printtoc, root=item, current=None, full=True, extension=extension, anchor_toplevel=True &>
+       </div>
+</div>
+
+</div>
+</%method>
+
+<%method pagenav>
+<%args>
+    item
+</%args>
+<div class="sectionnavblock">
+<div class="sectionnav">
+
+%       if item.previous is not None:
+        Previous: <& itemlink, item=item.previous &>
+%       # end if
+
+%       if item.next is not None:
+%               if item.previous is not None:
+                |
+%               # end if
+
+        Next: <& itemlink, item=item.next &>
+%       # end if
+
+</div>
+</div>
+</%method>
diff --git a/doc/build/components/printsection.myt b/doc/build/components/printsection.myt
deleted file mode 100644 (file)
index cd5a26f..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-<%args>
-       toc
-       paged
-       comp
-       isdynamic
-       index
-       ext
-       onepage
-</%args>
-
-<%python scope="init">
-       # get the item being requested by this embedded component from the documentation tree
-       try:
-               current = toc.get_file(comp.get_name())
-       except KeyError:
-               current = None
-</%python>
-
-% if paged == 'yes':
-%      if current is None:
-               <& toc, includefile = True, **ARGS &>
-%      else:
-               <A name="<% current.path %>"></a>
-               <& topnav, item=current, **ARGS &>
-               <div class="sectioncontent">
-                       <& formatting.myt:printitem, item=current, includefile = True, omitheader = True &>
-               </div>
-%      # if/else
-% else:
-       <& toc, includefile = False, **ARGS &>
-       <div class="onepagecontent">
-%      for i in toc.children:
-               <div class="section">
-                                       
-                       <A name="<% i.path %>"></a>
-                       <div class="topnavmargin">
-                       <& topnav, item=i, **ARGS &>
-                       </div>
-
-                       <& formatting.myt:printitem, item=i, includefile = False, omitheader = True &>
-               </div>
-%      # for i
-       </div>
-       
-% # if/else
-
-
-<%method topnav>
-       <%args>
-               isdynamic
-               paged
-               item
-               index
-               ext
-               onepage
-       </%args>
-% ispaged = (paged =='yes')
-
-<div class="topnav">
-
-<& topnavcontrol, **ARGS &>
-
-<div class="topnavsectionlink">
-
-<a href="<% ispaged and 'index' + ext or '#top' %>">Table of Contents</a>
-
-<div class="prevnext">
-% if item.previous is not None:
-Previous: <& formatting.myt:itemlink, item=item.previous, includefile=ispaged &>
-%
-
-% if item.previous is not None and item.next is not None:
-&nbsp; | &nbsp;
-%
-
-% if item.next is not None:
-
-Next: <& formatting.myt:itemlink, item=item.next, includefile=ispaged &>
-%
-
-</div>
-</div>
-
-
-<div class="topnavmain">
-       <div class="topnavheader"><% item.description %></div>
-       <div class="topnavitems">
-       <& formatting.myt:printtoc, root = item, includefile = False, current = None, full = True &>
-       </div>
-</div>
-
-</div>
-</%method>
-
-<%method topnavcontrol>
-       <%args>
-               isdynamic
-               paged
-               index
-               ext
-               onepage
-       </%args>
-% ispaged = (paged =='yes')
-
-       <div class="topnavcontrol">
-% if ispaged:
-       View: <b>Paged</b> &nbsp;|&nbsp; <a href="<% isdynamic and index + ext + '?paged=no' or onepage + ext %>">One Page</a>
-% else:
-       View: <a href="<% index + ext %>">Paged</a> &nbsp;|&nbsp; <b>One Page</b>
-%
-       </div>
-
-</%method>
-
-<%method toc>
-       <%args>
-               toc
-               includefile = True
-               isdynamic
-               paged
-               index
-               ext
-               onepage
-       </%args>
-       
-       
-       <div class="maintoc">
-       <& topnavcontrol, **ARGS &>
-
-       <a name="table_of_contents"></a>
-       <h2>Table of Contents</h2>
-       &nbsp;&nbsp;
-       <a href="#full_index">(view full table)</a>
-       <br/><br/>
-       
-       <div style="margin-left:50px;">
-       <& formatting.myt:printtoc, root = toc, includefile = includefile, current = None, full = False, children=False &>
-       </div>
-
-       </div>
-
-
-       <div class="maintoc">
-       <a name="full_index"></a>
-       <h2>Table of Contents: Full</h2>
-       &nbsp;&nbsp;
-       <a href="#table_of_contents">(view brief table)</a>
-       <br/><br/>
-
-       <div style="margin-left:50px;">
-       <& formatting.myt:printtoc, root = toc, includefile = includefile, current = None, full = True, children=True &>
-       </div>
-
-       </div>
-</%method>
index bf7a6952a0c9a4631c819878ae1029dd08b2a32f..b787ae74f84e486855ae6b6edb3952605994d2f6 100644 (file)
@@ -1,44 +1,42 @@
+<%doc>pydoc.myt - provides formatting functions for printing docstring.AbstractDoc generated python documentation objects.</%doc>
+
 <%global>
-    import docstring, string, sys
+import docstring
 </%global>
 
 <%method obj_doc>
     <%args>
         obj
+        toc
+        extension
     </%args>
-
-<%python>
+<%init>
 if obj.isclass:
-    s = []
     links = []
     for elem in obj.inherits:
         if isinstance(elem, docstring.ObjectDoc):
-            links.append("<a href=\"#%s\">%s</a>" % (str(elem.id), elem.name))
-            s.append(elem.name)
+            links.append(m.scomp("nav.myt:toclink", toc=toc, path=elem.toc_path, extension=extension, description=elem.name))
         else:
             links.append(str(elem))
-            s.append(str(elem))
-    description = "class " + obj.classname + "(%s)" % (','.join(s))
     htmldescription = "class " + obj.classname + "(%s)" % (','.join(links))
 else:
-    description = obj.description
     htmldescription = obj.description
-    
-</%python>
-<&|doclib.myt:item, name=obj.name, description=description, htmldescription=htmldescription, altlink=str(obj.id) &>
+
+</%init>
+
+<&|formatting.myt:section, toc=toc, path=obj.toc_path, description=htmldescription &>
+
 <&|formatting.myt:formatplain&><% obj.doc %></&>
 
 % if not obj.isclass and obj.functions:
-<&|doclib.myt:item, name="modfunc", description="Module Functions" &>
-<&|formatting.myt:paramtable&>
+
 %   for func in obj.functions:
     <& SELF:function_doc, func=func &>
 %
-</&>
-</&>
+
 % else:
+
 % if obj.functions:
-<&|formatting.myt:paramtable&>
 %   for func in obj.functions:
 %   if isinstance(func, docstring.FunctionDoc):
     <& SELF:function_doc, func=func &>
@@ -46,26 +44,26 @@ else:
     <& SELF:property_doc, prop=func &>
 %
 %
-</&>
 %
 %
 
 % if obj.classes:
-<&|formatting.myt:paramtable&>
 %   for class_ in obj.classes:
-      <& SELF:obj_doc, obj=class_ &>
+      <& SELF:obj_doc, obj=class_, toc=toc, extension=extension &>
 %   
-</&>
 %    
 </&>
-
 </%method>
 
 <%method function_doc>
     <%args>func</%args>
-    <&|formatting.myt:function_doc, name=func.name, link=func.link, arglist=func.arglist &>
-    <&|formatting.myt:formatplain&><% func.doc %></&>
-    </&>
+        <div class="darkcell">
+        <A name=""></a>
+        <b><% func.name %>(<% ", ".join(map(lambda k: "<i>%s</i>" % k, func.arglist))%>)</b>
+        <div class="docstring">
+        <&|formatting.myt:formatplain&><% func.doc %></&>
+        </div>
+        </div>
 </%method>
 
 
@@ -73,7 +71,13 @@ else:
     <%args>
         prop
     </%args>
-    <&|formatting.myt:member_doc, name=prop.name, link=prop.link &>
-    <&|formatting.myt:formatplain&><% prop.doc %></&>
-    </&>    
+         <div class="darkcell">
+         <A name=""></a>
+         <b><% prop.name %></b>
+         <div class="docstring">
+         <&|formatting.myt:formatplain&><% prop.doc %></&>
+         </div> 
+         </div>
 </%method>
+
+
diff --git a/doc/build/components/section_wrapper.myt b/doc/build/components/section_wrapper.myt
deleted file mode 100644 (file)
index b4e7c52..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<%python scope="global">
-    import string, re, time
-
-</%python>
-
-<%args>
-    comp
-    toc
-    title
-    version = None
-    last_updated = None
-    index
-    paged
-    onepage
-    isdynamic
-    ext
-</%args>
-
-<link href="style.css" rel="stylesheet" type="text/css"></link>
-<link href="syntaxhighlight.css" rel="stylesheet" type="text/css"></link>
-
-<link href="docs.css" rel="stylesheet" type="text/css"></link>
-<script src="scripts.js"></script>
-
-
-<div style="position:absolute;left:0px;top:0px;"><a name="top"></a>&nbsp;</div>
-
-<div class="doccontainer">
-
-<div class="docheader">
-
-<h1><% title %></h1>
-% if version is not None:
-<div class="">Version: <% version %>   Last Updated: <% time.strftime('%x %X', time.localtime(last_updated)) %></div>
-%
-</div>
-
-<& printsection.myt, paged = paged, toc = toc, comp = comp, isdynamic=isdynamic, index=index, ext=ext,onepage=onepage &>
-
-</div>
-
-
diff --git a/doc/build/components/toc.myt b/doc/build/components/toc.myt
new file mode 100644 (file)
index 0000000..6580a39
--- /dev/null
@@ -0,0 +1,95 @@
+<%doc>toc.myt - prints full table of contents listings given toc.TOCElement strucures</%doc>
+
+<%method toc>
+       <%args>
+               toc
+               extension
+       </%args>
+       
+       
+       <div class="maintoc">
+
+       <a name="table_of_contents"></a>
+       <h2>Table of Contents</h2>
+       &nbsp;&nbsp;
+       <a href="#full_index">(view full table)</a>
+       <br/><br/>
+       
+       <div style="margin-left:50px;">
+       <& printtoc, root = toc, current = None, full = False, children=False, extension=extension, anchor_toplevel=False &>
+       </div>
+
+       </div>
+
+
+       <div class="maintoc">
+       <a name="full_index"></a>
+       <h2>Table of Contents: Full</h2>
+       &nbsp;&nbsp;
+       <a href="#table_of_contents">(view brief table)</a>
+       <br/><br/>
+
+       <div style="margin-left:50px;">
+       <& printtoc, root = toc, current = None, full = True, children=True, extension=extension, anchor_toplevel=False &>
+       </div>
+
+       </div>
+</%method>
+
+
+<%method printtoc>
+<%args> 
+    root
+    current = None
+    full = False
+    children = True
+    extension
+    anchor_toplevel=False
+</%args>
+
+<ul class="toc_list">
+% for i in root.children:
+    <& printtocelement, item=i, bold = (i == current), full = full, children=children, extension=extension, anchor_toplevel=anchor_toplevel &>
+%
+</ul>
+</%method>
+
+<%def printtocelement>
+<%doc>prints a TOCElement as a table of contents item and prints its immediate child items</%doc>
+    <%args>
+        item
+        bold = False
+        full = False
+        children = True
+        extension
+        anchor_toplevel
+    </%args>
+    
+        <li><A style="<% bold and "font-weight:bold;" or "" %>" href="<% item.get_link(extension=extension, anchor=anchor_toplevel) %>"><% item.description %></a></li>
+    
+% if children:  
+    <ul class="small_toc_list">
+%   for i in item.children:
+        <& printsmtocelem, item=i, children=full, extension=extension &>
+%
+    </ul>
+%
+</%def>
+
+<%def printsmtocelem>
+    <%args>
+        item
+        children = False
+        extension
+    </%args>    
+    <li><A href="<% item.get_link(extension=extension) %>"><% item.description %></a></li>
+
+% if children:
+    <ul class="small_toc_list">
+%   for i in item.children:
+        <& printsmtocelem, item = i, extension=extension &>
+%
+    </ul>
+%
+
+</%def>
index a30a5fb636d49dd8f47e6a390bf0236fff2a47e2..685c0314fa596264f3b7f621764ddc2cbd7e118c 100644 (file)
@@ -1,6 +1,12 @@
-<%flags>inherit='document_base.myt'</%flags>
-<%attr>title='Modules and Classes'</%attr>
-<&|doclib.myt:item, name="docstrings", description="Modules and Classes" &>
+<%flags>inherit='content_layout.myt'</%flags>
+<%attr>
+    title='Modules and Classes'
+    filename='docstrings'
+</%attr>
+<%args>
+    toc
+    extension
+</%args>
 <%init>
     import cPickle as pickle
     import os
@@ -9,7 +15,5 @@
 </%init>
 
 % for obj in data:
-<& pydoc.myt:obj_doc, obj=obj &>
+<& pydoc.myt:obj_doc, obj=obj, toc=toc, extension=extension &>
 %
-
-</&>
\ No newline at end of file
diff --git a/doc/build/content/document_base.myt b/doc/build/content/document_base.myt
deleted file mode 100644 (file)
index e4750c7..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<%flags>inherit="doclib.myt"</%flags>
-
-<%python scope="global">
-
-    files = [
-        'tutorial',
-        'dbengine',
-        'metadata',
-        'sqlconstruction',
-        'datamapping',
-        'unitofwork',
-        'adv_datamapping',
-        'types',
-        'pooling',
-        'plugins',
-        'docstrings',
-        ]
-
-</%python>
-
-<%attr>
-    files=files
-    wrapper='section_wrapper.myt'
-    onepage='documentation'
-    index='index'
-    title='SQLAlchemy 0.3 Documentation'
-    version = '0.3.0'
-</%attr>
-
-<%method title>
-% try:
-#  avoid inheritance via attr instead of attributes
-    <% m.base_component.attr['title'] %> - <% self.owner.attr['title'] %>
-% except KeyError:
-    <% self.owner.attr['title'] %>
-%
-</%method>
-
-
-
-
-
diff --git a/doc/build/content/index.myt b/doc/build/content/index.myt
new file mode 100644 (file)
index 0000000..524a43b
--- /dev/null
@@ -0,0 +1,7 @@
+<%flags>inherit='base.myt'</%flags>
+<%args>
+    extension
+    toc
+</%args>
+
+<& toc.myt:toc, toc=toc, extension=extension &>
index 4cae58cb4b21bf4396eacb82478b7d592e333b6a..cc677cd89ad2bc74f96f3e72e0dffb664cfa19c0 100644 (file)
@@ -463,13 +463,13 @@ A table with a sequence looks like:
         Column("description", String(40)),
         Column("createdate", DateTime())
     )
-        
-The Sequence is used with Postgres or Oracle to indicate the name of a database sequence that will be used to create default values for a column.  When a table with a Sequence on a column is created in the database by SQLAlchemy, the database sequence object is also created.   Similarly, the database sequence is dropped when the table is dropped.  Sequences are typically used with primary key columns.  When using Postgres, if an integer primary key column defines no explicit Sequence or other default method, SQLAlchemy will create the column with the SERIAL keyword, and will pre-execute a sequence named "tablename_columnname_seq" in order to retrieve new primary key values, if they were not otherwise explicitly stated.   Oracle, which has no "auto-increment" keyword, requires that a Sequence be created for a table if automatic primary key generation is desired.  
-    
+
+The Sequence is used with Postgres or Oracle to indicate the name of a database sequence that will be used to create default values for a column.  When a table with a Sequence on a column is created in the database by SQLAlchemy, the database sequence object is also created.   Similarly, the database sequence is dropped when the table is dropped.  Sequences are typically used with primary key columns.  When using Postgres, if an integer primary key column defines no explicit Sequence or other default method, SQLAlchemy will create the column with the SERIAL keyword, and will pre-execute a sequence named "tablename_columnname_seq" in order to retrieve new primary key values, if they were not otherwise explicitly stated.   Oracle, which has no "auto-increment" keyword, requires that a Sequence be created for a table if automatic primary key generation is desired.
+
 A Sequence object can be defined on a Table that is then used for a non-sequence-supporting database.  In that case, the Sequence object is simply ignored.  Note that a Sequence object is **entirely optional for all databases except Oracle**, as other databases offer options for auto-creating primary key values, such as AUTOINCREMENT, SERIAL, etc.  SQLAlchemy will use these default methods for creating primary key values if no Sequence is present on the table metadata.
-    
+
 A sequence can also be specified with `optional=True` which indicates the Sequence should only be used on a database that requires an explicit sequence, and not those that supply some other method of providing integer values.  At the moment, it essentially means "use this sequence only with Oracle and not Postgres".
-    
+
 ### Defining Constraints and Indexes {@name=constraints}
 
 #### UNIQUE Constraint
index d17c82db6048b512c95bb58c2ae2dd44b02016bb..2cce781ea6d5a1a306e14ce7ef0eee4e336b48f7 100644 (file)
@@ -3,7 +3,7 @@ Tutorial
 This tutorial provides a relatively simple walking tour through the basic concepts of SQLAlchemy.  You may wish to skip it and dive into the [main manual][manual] which is more reference-oriented.  The examples in this tutorial comprise a fully working interactive Python session, and are guaranteed to be functioning courtesy of [doctest][].
 
 [doctest]: http://www.python.org/doc/lib/module-doctest.html
-[manual]: rel:howtoread
+[manual]: rel:metadata
 
 Installation
 ------------
diff --git a/doc/build/gen_docstrings.py b/doc/build/gen_docstrings.py
new file mode 100644 (file)
index 0000000..67b60cd
--- /dev/null
@@ -0,0 +1,74 @@
+from toc import TOCElement
+import docstring
+
+import sqlalchemy.schema as schema
+import sqlalchemy.engine as engine
+import sqlalchemy.engine.strategies as strategies
+import sqlalchemy.sql as sql
+import sqlalchemy.pool as pool
+import sqlalchemy.orm as orm
+import sqlalchemy.exceptions as exceptions
+import sqlalchemy.ext.proxy as proxy
+import sqlalchemy.ext.sessioncontext as sessioncontext
+import sqlalchemy.mods.threadlocal as threadlocal
+import sqlalchemy.ext.selectresults as selectresults
+
+def make_doc(obj, classes=None, functions=None):
+    """generate a docstring.ObjectDoc structure for an individual module, list of classes, and list of functions."""
+    return docstring.ObjectDoc(obj, classes=classes, functions=functions)
+
+def make_all_docs():
+    """generate a docstring.AbstractDoc structure."""
+    objects = [
+        make_doc(obj=sql),
+        make_doc(obj=schema),
+        make_doc(obj=engine),
+        make_doc(obj=engine.url),
+        make_doc(obj=orm, classes=[orm.MapperExtension]),
+        make_doc(obj=orm.mapperlib, classes=[orm.mapperlib.Mapper]),
+        make_doc(obj=orm.query, classes=[orm.query.Query, orm.query.QueryContext, orm.query.SelectionContext]),
+        make_doc(obj=orm.session, classes=[orm.session.Session, orm.session.SessionTransaction]),
+        make_doc(obj=pool, classes=[pool.DBProxy, pool.Pool, pool.QueuePool, pool.SingletonThreadPool]),
+        make_doc(obj=sessioncontext),
+        make_doc(obj=threadlocal),
+        make_doc(obj=selectresults),
+        make_doc(obj=exceptions),
+        make_doc(obj=proxy),
+    ]
+    return objects
+    
+def create_docstring_toc(data, root):
+    """given a docstring.AbstractDoc structure, create new TOCElement nodes corresponding
+    to the elements and cross-reference them back to the doc structure."""
+    root = TOCElement("docstrings", name="docstrings", description="Generated Documentation", parent=root)
+    def create_obj_toc(obj, toc):
+        if obj.isclass:
+            s = []
+            links = []
+            for elem in obj.inherits:
+                if isinstance(elem, docstring.ObjectDoc):
+                    links.append("<a href=\"#%s\">%s</a>" % (str(elem.id), elem.name))
+                    s.append(elem.name)
+                else:
+                    links.append(str(elem))
+                    s.append(str(elem))
+            description = "class " + obj.classname + "(%s)" % (','.join(s))
+            htmldescription = "class " + obj.classname + "(%s)" % (','.join(links))
+        else:
+            description = obj.description
+            htmldescription = obj.description
+
+        toc = TOCElement("docstrings", obj.name, description, parent=toc)
+        obj.toc_path = toc.path
+
+        if not obj.isclass and obj.functions:
+            TOCElement("docstrings", name="modfunc", description="Module Functions", parent=toc)
+
+        if obj.classes:
+            for class_ in obj.classes:
+                create_obj_toc(class_, toc)
+                
+    for obj in data:
+        create_obj_toc(obj, root)
+    return data
+
index 2a274b03aba484476c1d5ea5a6417673521a11d1..015f65bdf0485d07168b7675a50cf4be7de86add 100644 (file)
@@ -1,24 +1,65 @@
 #!/usr/bin/env python
-import sys,re,os
+import sys,re,os,shutil
+import myghty.interp
+import myghty.exception as exception
+import cPickle as pickle
 
-print "Running txt2myt.py..."
-execfile("txt2myt.py")
+sys.path = ['../../lib', './lib/'] + sys.path
 
-print "Generating docstring data"
-execfile("compile_docstrings.py")
+import gen_docstrings, read_markdown, toc
+
+files = [
+    'index',
+    'tutorial',
+    'dbengine',
+    'metadata',
+    'sqlconstruction',
+    'datamapping',
+    'unitofwork',
+    'adv_datamapping',
+    'types',
+    'pooling',
+    'plugins',
+    'docstrings'
+    ]
+
+title='SQLAlchemy 0.3 Documentation'
+version = '0.3.0'
+
+root = toc.TOCElement('', 'root', '', version=version, doctitle=title)
+
+shutil.copy('./content/index.myt', './output/index.myt')
+shutil.copy('./content/docstrings.myt', './output/docstrings.myt')
+
+read_markdown.parse_markdown_files(root, files)
+docstrings = gen_docstrings.make_all_docs()
+gen_docstrings.create_docstring_toc(docstrings, root)
+
+pickle.dump(docstrings, file('./output/compiled_docstrings.pickle', 'w'))
+pickle.dump(root, file('./output/table_of_contents.pickle', 'w'))
 
 component_root = [
     {'components': './components'},
-    {'content' : './content'}
+    {'output' :'./output'}
 ]
-doccomp = ['document_base.myt']
 output = os.path.dirname(os.getcwd())
 
-sys.path = ['./lib/'] + sys.path
+interp = myghty.interp.Interpreter(component_root = component_root, output_encoding='utf-8')
 
-import documentgen
+def genfile(name, toc):
+    infile = name + ".myt"
+    outname = os.path.join(os.getcwd(), '../', name + ".html")
+    outfile = file(outname, 'w')
+    print infile, '->', outname
+    interp.execute(infile, out_buffer=outfile, request_args={'toc':toc,'extension':'html'}, raise_error=True)
+    
+try:
+    for filename in files:
+        genfile(filename, root)
+except exception.Error, e:
+    sys.stderr.write(e.textformat())
 
-documentgen.genall(doccomp, component_root, output)
 
+        
 
 
index b6879c7ade93de3024a293f7421f6d36f9e9c401..b4ddcff4ef3fc5a59189002dfad77356d78ecafb 100644 (file)
@@ -1,6 +1,8 @@
-import re, types, string, inspect
+"""
+defines a pickleable, recursive "generated python documentation" datastructure.
+"""
 
-"""sucks a module and its contents into a simple documentation object, suitable for pickling"""
+import re, types, string, inspect
 
 allobjects = {}
 
@@ -9,6 +11,7 @@ class AbstractDoc(object):
         allobjects[id(obj)] = self
         self.id = id(obj)
         self.allobjects = allobjects
+        self.toc_path = None
         
 class ObjectDoc(AbstractDoc):
     def __init__(self, obj, functions=None, classes=None):
diff --git a/doc/build/lib/documentgen.py b/doc/build/lib/documentgen.py
deleted file mode 100644 (file)
index 7e1783d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-import sys, re, os
-import myghty.interp
-import myghty.exception as exception
-
-# document generation library
-
-def genall(comps, component_root, output_dir):
-    interp = myghty.interp.Interpreter( component_root = component_root)
-    
-    try:
-        for comp in comps:
-            gendoc(comp, interp, output_dir = output_dir)
-    except exception.Error, e:
-        sys.stderr.write(e.textformat())
-
-
-def gendoc(doccomp, interp, output_dir):
-    component = interp.load(doccomp)
-    files = component.get_attribute('files')
-    index = component.get_attribute('index')
-    onepage = component.get_attribute('onepage')
-
-    genfile(index + ".myt", interp, output_dir)
-
-    for file in files:
-        file += '.myt'
-        genfile(file, interp, output_dir)
-
-    genfile(index + ".myt", interp, output_dir, outfile = onepage + ".html", args = {'paged':'no'})
-
-
-
-def genfile(file, interp, output_dir, outfile = None, args = {}):
-    if outfile is None:
-        outfile = re.sub(r"\..+$", "%s" % '.html', file)
-
-    outfile = os.path.join(output_dir, outfile)
-    print "%s -> %s" % (file, outfile)
-    outbuf = open(outfile, "w")
-
-    interp.execute(file, out_buffer = outbuf, request_args = args, raise_error = True)
-        
-    outbuf.close()
-
diff --git a/doc/build/lib/toc.py b/doc/build/lib/toc.py
new file mode 100644 (file)
index 0000000..ebf7e95
--- /dev/null
@@ -0,0 +1,70 @@
+"""
+defines a pickleable, recursive "table of contents" datastructure.
+
+TOCElements define a name, a description, and also a uniquely-identifying "path" which is
+used to generate hyperlinks between document sections.
+"""
+import time
+
+toc_by_file = {}
+toc_by_path = {}
+
+class TOCElement(object):
+    def __init__(self, filename, name, description, parent=None, version=None, last_updated=None, doctitle=None, **kwargs):
+        self.filename = filename
+        self.name = name
+        self.description = description
+        self.parent = parent
+        self.content = None
+        self.toc_by_path = toc_by_path
+        self.toc_by_file = toc_by_file
+        self.last_updated = time.time()
+        self.version = version
+        self.doctitle = doctitle
+        (self.path, self.depth) = self._create_path()
+        #print "NEW TOC:", self.path
+        for key, value in kwargs.iteritems():
+            setattr(self, key, value)
+
+        toc_by_path[self.path] = self
+            
+        self.is_top = (self.parent is not None and self.parent.filename != self.filename) or self.parent is None
+        if self.is_top:
+            toc_by_file[self.filename] = self
+
+        self.root = self.parent or self
+
+        self.content = None
+        self.previous = None
+        self.next = None
+        self.children = []
+        if parent:
+            if len(parent.children):
+                self.previous = parent.children[-1]
+                parent.children[-1].next = self
+            parent.children.append(self)
+
+    def get_page_root(self):
+        return self.toc_by_file[self.filename]
+        
+    def get_by_path(self, path):
+        return self.toc_by_path.get(path)
+
+    def get_by_file(self, filename):
+        return self.toc_by_file[filename]
+
+    def get_link(self, extension='html', anchor=True):
+        if anchor:
+            return "%s.%s#%s" % (self.filename, extension, self.path) 
+        else:
+            return "%s.%s" % (self.filename, extension)
+
+    def _create_path(self):
+        elem = self
+        tokens = []
+        depth = 0
+        while elem.parent is not None:
+            tokens.insert(0, elem.name)
+            elem = elem.parent
+            depth +=1
+        return ('_'.join(tokens), depth)
diff --git a/doc/build/read_markdown.py b/doc/build/read_markdown.py
new file mode 100644 (file)
index 0000000..fdc6175
--- /dev/null
@@ -0,0 +1,230 @@
+import sys, re, os
+from toc import TOCElement
+
+try:
+    import elementtree.ElementTree as et
+except:
+    raise "This module requires ElementTree to run (http://effbot.org/zone/element-index.htm)"
+
+import markdown
+
+def dump_tree(elem, stream):
+    if elem.tag.startswith('MYGHTY:'):
+        dump_myghty_tag(elem, stream)
+    else:
+        stream.write("<%s %s>" % (elem.tag, " ".join("%s=%s" % (key, repr(val)) for key, val in elem.attrib.iteritems())))
+        if elem.text:
+            stream.write(elem.text)
+        for child in elem:
+            dump_tree(child, stream)
+            if child.tail:
+                stream.write(child.tail)
+        stream.write("</%s>" % elem.tag)
+
+def dump_myghty_tag(elem, stream):
+    tag = elem.tag[7:]
+    params = ', '.join(['%s=%s' % i for i in elem.items()])
+    pipe = ''
+    if elem.text or len(elem):
+        pipe = '|'
+    comma = ''
+    if params:
+        comma = ', '
+    stream.write('<&%s%s%s%s&>' % (pipe, tag, comma, params))
+    if pipe:
+        if elem.text:
+            stream.write(elem.text)
+        for n in elem:
+            dump_tree(n, stream)
+            if n.tail:
+                stream.write(n.tail)
+        stream.write("</&>")
+
+def create_toc(filename, tree, tocroot):
+    title = [None]
+    current = [tocroot]
+    level = [0]
+    def process(tree):
+        while True:
+            i = find_header_index(tree)
+            if i is None:
+                return
+            node = tree[i]
+            taglevel = int(node.tag[1])
+            start, end = i, end_of_header(tree, taglevel, i+1)
+            content = tree[start+1:end]
+            description = node.text.strip()
+            if title[0] is None:
+                title[0] = description
+            name = node.get('name')
+            if name is None:
+                name = description.split()[0].lower()
+            
+            taglevel = node.tag[1]
+            if taglevel > level[0]:
+                current[0] = TOCElement(filename, name, description, current[0])
+            elif taglevel == level[0]:
+                current[0] = TOCElement(filename, name, description, current[0].parent)
+            else:
+                current[0] = TOCElement(filename, name, description, current[0].parent.parent)
+
+            level[0] = taglevel
+
+            tag = et.Element("MYGHTY:formatting.myt:section", path=literal(current[0].path), toc="toc")
+            tag.text = (node.tail or "") + '\n'
+            tag.tail = '\n'
+            tag[:] = content
+            tree[start:end] = [tag]
+
+            process(tag)
+
+    process(tree)
+    return (title[0], tocroot.get_by_file(filename))
+
+def literal(s):
+    return '"%s"' % s
+    
+def index(parent, item):
+    for n, i in enumerate(parent):
+        if i is item:
+            return n
+
+def find_header_index(tree):
+    for i, node in enumerate(tree):
+        if is_header(node):
+            return i
+
+def is_header(node):
+    t = node.tag
+    return (isinstance(t, str) and len(t) == 2 and t[0] == 'h' 
+            and t[1] in '123456789')
+
+def end_of_header(tree, level, start):
+    for i, node in enumerate(tree[start:]):
+        if is_header(node) and int(node.tag[1]) <= level:
+            return start + i
+    return len(tree)
+
+def process_rel_href(tree):
+    parent = get_parent_map(tree)
+    for a in tree.findall('.//a'):
+        m = re.match(r'(bold)?rel\:(.+)', a.get('href'))
+        if m:
+            (bold, path) = m.group(1,2)
+            text = a.text
+            if text == path:
+                tag = et.Element("MYGHTY:nav.myt:toclink", path=literal(path), toc="toc", extension="extension")
+            else:
+                tag = et.Element("MYGHTY:nav.myt:toclink", path=literal(path), description=literal(text), toc="toc", extension="extension")
+            a_parent = parent[a]
+            if bold:
+                bold = et.Element('strong')
+                bold.tail = a.tail
+                bold.append(tag)
+                a_parent[index(a_parent, a)] = bold
+            else:
+                tag.tail = a.tail
+                a_parent[index(a_parent, a)] = tag
+
+def replace_pre_with_myt(tree):
+    def splice_code_tag(pre, text, type=None, title=None):
+        doctest_directives = re.compile(r'#\s*doctest:\s*[+-]\w+(,[+-]\w+)*\s*$', re.M)
+        text = re.sub(doctest_directives, '', text)
+        # process '>>>' to have quotes around it, to work with the myghty python
+        # syntax highlighter which uses the tokenize module
+        text = re.sub(r'>>> ', r'">>>" ', text)
+
+        # indent two spaces.  among other things, this helps comment lines "#  " from being 
+        # consumed as Myghty comments.
+        text = re.compile(r'^(?!<&)', re.M).sub('  ', text)
+
+        sqlre = re.compile(r'{sql}(.*?)((?:SELECT|INSERT|DELETE|UPDATE|CREATE|DROP|PRAGMA|DESCRIBE).*?)\n\s*(\n|$)', re.S)
+        if sqlre.search(text) is not None:
+            use_sliders = False
+        else:
+            use_sliders = True
+        
+        text = sqlre.sub(r"<&formatting.myt:poplink&>\1\n<&|formatting.myt:codepopper, link='sql'&>\2</&>\n\n", text)
+
+        sqlre2 = re.compile(r'{opensql}(.*?)((?:SELECT|INSERT|DELETE|UPDATE|CREATE|DROP).*?)\n\s*(\n|$)', re.S)
+        text = sqlre2.sub(r"<&|formatting.myt:poppedcode &>\1\n\2</&>\n\n", text)
+
+        opts = {}
+        if type == 'python':
+            opts['syntaxtype'] = literal('python')
+        else:
+            opts['syntaxtype'] = None
+
+        if title is not None:
+            opts['title'] = literal(title)
+    
+        if use_sliders:
+            opts['use_sliders'] = True
+    
+        tag = et.Element("MYGHTY:formatting.myt:code", **opts)
+        tag.text = text
+
+        pre_parent = parents[pre]
+        tag.tail = pre.tail
+        pre_parent[reverse_parent(pre_parent, pre)] = tag
+
+    parents = get_parent_map(tree)
+
+    for precode in tree.findall('.//pre/code'):
+        m = re.match(r'\{(python|code)(?: title="(.*?)"){0,1}\}', precode.text.lstrip())
+        if m:
+            code = m.group(1)
+            title = m.group(2)
+            text = precode.text.lstrip()
+            text = re.sub(r'{(python|code).*?}(\n\s*)?', '', text)
+            splice_code_tag(parents[precode], text, type=code, title=title)
+        elif precode.text.lstrip().startswith('>>> '):
+            splice_code_tag(parents[precode], precode.text)
+
+def reverse_parent(parent, item):
+    for n, i in enumerate(parent):
+        if i is item:
+            return n
+
+def get_parent_map(tree):
+    return dict([(c, p) for p in tree.getiterator() for c in p])
+
+def header(toc, title, filename):
+    return """#encoding: utf-8
+<%%flags>
+    inherit='content_layout.myt'
+</%%flags>
+<%%args>
+    toc
+    extension
+</%%args>
+<%%attr>
+    title='%s - %s'
+    filename = '%s'
+</%%attr>
+<%%doc>This file is generated.  Edit the .txt files instead of this one.</%%doc>
+""" % (toc.root.doctitle, title, filename)
+  
+class utf8stream(object):
+    def __init__(self, stream):
+        self.stream = stream
+    def write(self, str):
+        self.stream.write(str.encode('utf8'))
+        
+def parse_markdown_files(toc, files):
+    for inname in files:
+        infile = 'content/%s.txt' % inname
+        if not os.access(infile, os.F_OK):
+            continue
+        html = markdown.markdown(file(infile).read())
+        tree = et.fromstring("<html>" + html + "</html>")
+        (title, toc_element) = create_toc(inname, tree, toc)
+        replace_pre_with_myt(tree)
+        process_rel_href(tree)
+        outname = 'output/%s.myt' % inname
+        print infile, '->', outname
+        outfile = utf8stream(file(outname, 'w'))
+        outfile.write(header(toc, title, inname))
+        dump_tree(tree, outfile)
+    
+    
index 591e3b7f7a143fa7d5835b84855a027c29673098..c5b34e4bf192e7f58de4da27208a045917f325e6 100755 (executable)
@@ -1,15 +1,13 @@
 #!/usr/bin/env python\r
 import sys,re,os\r
 \r
-print "Running txt2myt.py..."\r
-execfile("txt2myt.py")\r
+"""starts an HTTP server which will serve generated .myt files from the ./components and \r
+./output directories."""\r
 \r
-print "Generating docstring data"\r
-execfile("compile_docstrings.py")\r
 \r
 component_root = [\r
     {'components': './components'},\r
-    {'content' : './content'}\r
+    {'content' : './output'}\r
 ]\r
 doccomp = ['document_base.myt']\r
 output = os.path.dirname(os.getcwd())\r
@@ -18,15 +16,16 @@ sys.path = ['./lib/'] + sys.path
 \r
 import myghty.http.HTTPServerHandler as HTTPServerHandler\r
 \r
+port = 8080\r
 httpd = HTTPServerHandler.HTTPServer(\r
-    port = 8080,\r
-    \r
+    port = port,\r
     handlers = [\r
-        {'.*(?:\.myt|/$)' : HTTPServerHandler.HSHandler(path_translate=[(r'^/$', r'/index.myt')], data_dir = './cache', component_root = component_root)},\r
+        {'.*(?:\.myt|/$)' : HTTPServerHandler.HSHandler(path_translate=[(r'^/$', r'/index.myt')], data_dir = './cache', component_root = component_root, output_encoding='utf-8')},\r
     ],\r
 \r
     docroot = [{'.*' : '../'}],\r
     \r
 )       \r
-        \r
+\r
+print "Listening on %d" % port        \r
 httpd.serve_forever()\r
diff --git a/doc/build/txt2myt.py b/doc/build/txt2myt.py
deleted file mode 100644 (file)
index 3c81137..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-"""txt2myt.py -- translate all .txt files in a `content` directory to\r
-.myt template, assuming .txt conform to Markdown syntax.\r
-"""\r
-\r
-import sys\r
-import string\r
-import re\r
-\r
-try:\r
-    import elementtree.ElementTree as et\r
-except:\r
-    raise "This module requires ElementTree to run (http://effbot.org/zone/element-index.htm)"\r
-\r
-sys.path.insert(0, './lib')\r
-import markdown\r
-\r
-class MyElementTree(et.ElementTree):\r
-    def _write(self, file, node, encoding, namespaces):\r
-        """With support for myghty 'tags'"""\r
-        if node.tag is MyghtyTag:\r
-            params = ', '.join(['%s="%s"' % i for i in node.items()])\r
-            pipe = ''\r
-            if node.text or len(node):\r
-                pipe = '|'\r
-            comma = ''\r
-            if params:\r
-                comma = ', '\r
-            file.write('<&%s%s%s%s&>' % (pipe, node.name, comma, params))\r
-            if pipe:\r
-                if node.text:\r
-                    file.write(node.text)\r
-                for n in node:\r
-                    self._write(file, n, encoding, namespaces)\r
-                file.write("</&>")\r
-            if node.tail:\r
-                file.write(node.tail)\r
-        else:\r
-            et.ElementTree._write(self, file, node, encoding, namespaces)\r
-\r
-# The same as et.dump, but using MyElementTree\r
-def dump(elem):\r
-    # debugging\r
-    if not isinstance(elem, et.ElementTree):\r
-        elem = MyElementTree(elem)\r
-    elem.write(sys.stdout)\r
-    tail = elem.getroot().tail\r
-    if not tail or tail[-1] != "\n":\r
-        sys.stdout.write("\n")\r
-\r
-# The same as et.tostring, but using MyElementTree\r
-def tostring(element, encoding=None):\r
-    class dummy:\r
-        pass\r
-    data = []\r
-    file = dummy()\r
-    file.write = data.append\r
-    MyElementTree(element).write(file, encoding)\r
-    return string.join(data, "")\r
-\r
-def MyghtyTag(name_, attrib_={}, **extra):\r
-    """Can be used with ElementTree in places where Element is required"""\r
-    element = et.Element(MyghtyTag, attrib_, **extra)\r
-    element.name = name_\r
-    return element\r
-\r
-CODE_BLOCK = 'formatting.myt:code'\r
-DOCTEST_DIRECTIVES = re.compile(r'#\s*doctest:\s*[+-]\w+(,[+-]\w+)*\s*$', re.M)\r
-LINK = 'formatting.myt:link'\r
-LINK_REG = re.compile(r'(bold)?rel\:(.+)')\r
-SECTION = 'doclib.myt:item'\r
-\r
-def process_code_blocks(tree):\r
-    """Replace <pre><code>...</code></pre> with Myghty tags, if it contains:\r
-    * '{python}'\r
-    or\r
-    * '>>> '\r
-\r
-    Note: '{python}' will be removed\r
-    Note: also remove all doctest directives\r
-    """\r
-    parent = get_parent_map(tree)\r
-\r
-    def replace_pre_with_myt(pre, text, type=None, title=None):\r
-        text = re.sub(DOCTEST_DIRECTIVES, '', text)\r
-        # process '>>>' to have quotes around it, to work with the myghty python\r
-        # syntax highlighter which uses the tokenize module\r
-        text = re.sub(r'>>> ', r'">>>" ', text)\r
-\r
-        # indent two spaces.  among other things, this helps comment lines "#  " from being \r
-        # consumed as Myghty comments.\r
-        text = re.compile(r'^(?!<&)', re.M).sub('  ', text)\r
-\r
-        sqlre = re.compile(r'{sql}(.*?)((?:SELECT|INSERT|DELETE|UPDATE|CREATE|DROP|PRAGMA|DESCRIBE).*?)\n\s*(\n|$)', re.S)\r
-        if sqlre.search(text) is not None:\r
-            use_sliders = False\r
-        else:\r
-            use_sliders = True\r
-            \r
-        text = sqlre.sub(r"<&formatting.myt:poplink&>\1\n<&|formatting.myt:codepopper, link='sql'&>\2</&>\n\n", text)\r
-\r
-        sqlre2 = re.compile(r'{opensql}(.*?)((?:SELECT|INSERT|DELETE|UPDATE|CREATE|DROP).*?)\n\s*(\n|$)', re.S)\r
-        text = sqlre2.sub(r"<&|formatting.myt:poppedcode &>\1\n\2</&>\n\n", text)\r
-\r
-        pre_parent = parent[pre]\r
-        opts = {}\r
-        if type == 'python':\r
-            opts['syntaxtype'] = 'python'\r
-        else:\r
-            opts['syntaxtype'] = None\r
-\r
-        if title is not None:\r
-            opts['title'] = title\r
-        \r
-        if use_sliders:\r
-            opts['use_sliders'] = True\r
-        \r
-        tag = MyghtyTag(CODE_BLOCK, opts)\r
-        tag.text = text\r
-        tag.tail = pre.tail\r
-        pre_parent[index(pre_parent, pre)] = tag\r
-\r
-    for precode in tree.findall('.//pre/code'):\r
-        m = re.match(r'\{(python|code)(?: title="(.*?)"){0,1}\}', precode.text.lstrip())\r
-        if m:\r
-            code = m.group(1)\r
-            title = m.group(2)\r
-            text = precode.text.lstrip()\r
-            text = re.sub(r'{(python|code).*?}(\n\s*)?', '', text)\r
-            replace_pre_with_myt(parent[precode], text, type=code, title=title)\r
-        elif precode.text.lstrip().startswith('>>> '):\r
-            replace_pre_with_myt(parent[precode], precode.text)\r
-\r
-def process_rel_href(tree):\r
-    """Replace all <a href="rel:XXX">YYY</a> with Myghty tags\r
-\r
-    If XXX is the same as YYY, text attribute for Myghty tag will not be\r
-    provided.\r
-    """\r
-    parent = get_parent_map(tree)\r
-    for a in tree.findall('.//a'):\r
-        m = LINK_REG.match(a.get('href'))\r
-        if m:\r
-            (bold, path) = m.group(1,2)\r
-            text = a.text\r
-            if text == path:\r
-                tag = MyghtyTag(LINK, path=path)\r
-            else:\r
-                tag = MyghtyTag(LINK, path=path, text=text)\r
-            a_parent = parent[a]\r
-            if bold:\r
-                bold = et.Element('strong')\r
-                bold.tail = a.tail\r
-                bold.append(tag)\r
-                a_parent[index(a_parent, a)] = bold\r
-            else:\r
-                tag.tail = a.tail\r
-                a_parent[index(a_parent, a)] = tag\r
-\r
-def process_headers(tree):\r
-    """Replace all <h1>, <h2>... with Mighty tags\r
-    """\r
-    title = [None]\r
-    def process(tree):\r
-        while True:\r
-            i = find_header_index(tree)\r
-            if i is None:\r
-                return\r
-            node = tree[i]\r
-            level = int(node.tag[1])\r
-            start, end = i, end_of_header(tree, level, i+1)\r
-            content = tree[start+1:end]\r
-            description = node.text.strip()\r
-            if title[0] is None:\r
-                title[0] = description\r
-            name = node.get('name')\r
-            if name is None:\r
-                name = description.split()[0].lower()\r
-\r
-            tag = MyghtyTag(SECTION, name=name, description=description)\r
-            tag.text = (node.tail or "") + '\n'\r
-            tag.tail = '\n'\r
-            tag[:] = content\r
-            tree[start:end] = [tag]\r
-\r
-            process(tag)\r
-\r
-    process(tree)\r
-    return title[0]\r
-\r
-def index(parent, item):\r
-    for n, i in enumerate(parent):\r
-        if i is item:\r
-            return n\r
-\r
-def find_header_index(tree):\r
-    for i, node in enumerate(tree):\r
-        if is_header(node):\r
-            return i\r
-\r
-def is_header(node):\r
-    t = node.tag\r
-    return (isinstance(t, str) and len(t) == 2 and t[0] == 'h' \r
-            and t[1] in '123456789')\r
-\r
-def end_of_header(tree, level, start):\r
-    for i, node in enumerate(tree[start:]):\r
-        if is_header(node) and int(node.tag[1]) <= level:\r
-            return start + i\r
-    return len(tree)\r
-\r
-def get_parent_map(tree):\r
-    return dict([(c, p) for p in tree.getiterator() for c in p])\r
\r
-def html2myghtydoc(html):\r
-    """Convert HTML to Myghty template (for SQLAlchemy's doc framework)\r
-\r
-    html -- string containing HTML document, which:\r
-    * should be without surrounding <html> or <body> tags\r
-    * should have only one top-level header (usually <h1>). The text of the\r
-      header will be used as a title of Myghty template.\r
-\r
-    Things converter treats specially:\r
-    * <a href="rel:XXX">YYY</a> will result in:\r
-      <&formatting.myt:link, path="XXX", text="YYY"&>\r
-\r
-      If XXX is the same as YYY, text attribute will be absent. E.g.\r
-      <a href="rel:XXX">XXX</a> will result in:\r
-      <&formatting.myt:link, path="XXX"&>\r
-\r
-    * All header tags (<h1>, <h2>...) will be replaced. E.g. \r
-\r
-      <h2>Great title</h2><p>Section content goes here</p>\r
-\r
-      will turn into:\r
-\r
-      <&|doclib.myt:item, name="great", description="Great title"&>\r
-      <p>Section content goes here</p>\r
-      </&>\r
-\r
-      Note that by default the value of `name` parameter is a lower-case version\r
-      of the first word of the title. If you want to override it, supply\r
-      `name` attribute to header tag, e.g.:\r
-      <h2 name="title">Great title</h2>...\r
-      will turn into\r
-      <&|doclib.myt:item, name="title", description="Great title"&>...</&>\r
-\r
-      (Note that to give this attribute in Markdown, you can\r
-      write: {@name=title}.)\r
-\r
-    * If you have {python} marker inside <code>, which is inside <pre>, it will\r
-      replaced with Myghty tag. E.g.:\r
-\r
-      <pre><code>{python} print 'hello, world!'</code></pre>\r
-\r
-      will turn into\r
-\r
-      <&|formatting.myt:code&>print 'hello, world!'</&>\r
-\r
-      You don't need to write {python} marker if you use examples starting with\r
-      Python prompt: >>>\r
-\r
-      If you use doctest directives, they will be removed from output.\r
-\r
-      (Note that <pre> and <code> is what Markdown outputs for pre-formatted\r
-      code blocks.)\r
-    """\r
-\r
-    tree = et.fromstring("<html>" + html + "</html>")\r
-\r
-    process_code_blocks(tree)\r
-    process_rel_href(tree)\r
-    title = process_headers(tree)\r
-\r
-    header = "<%flags>inherit='document_base.myt'</%flags>\n"\r
-    header += "<%attr>title='" + title + "'</%attr>\n"\r
-    header += "<!-- WARNING! This file was automatically generated.\n" \\r
-              "     Modify .txt file if need you to change the content.-->\n"\r
-\r
-    # discard surrounding <html> tag\r
-    body = ''.join([tostring(e) for e in tree[:]])\r
-\r
-    return header + body\r
-\r
-if __name__ == '__main__':\r
-    import glob\r
-    filenames = sys.argv[1:]\r
-    if len(filenames) == 0:\r
-        filenames = glob.glob('content/*.txt')\r
-    for inname in filenames:\r
-        outname = inname[:-3] + 'myt'\r
-        print inname, '->', outname\r
-        input = file(inname).read()\r
-        html = markdown.markdown(input)\r
-        #file(inname[:-3] + "html", 'w').write(html)\r
-        myt = html2myghtydoc(html)\r
-        file(outname, 'w').write(myt)\r