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
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 !
--- /dev/null
+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.
+
+++ /dev/null
-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'))
<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>
--- /dev/null
+<%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> </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>
+
+
--- /dev/null
+<%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>
+++ /dev/null
-
-<%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>
-
-
-
-
-
-<%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>
<%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">
+++ /dev/null
-<%flags>inherit="document_base.myt"</%flags>
-
--- /dev/null
+<%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:
+ |
+%
+
+% 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>
+++ /dev/null
-<%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:
- |
-%
-
-% 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> | <a href="<% isdynamic and index + ext + '?paged=no' or onepage + ext %>">One Page</a>
-% else:
- View: <a href="<% index + ext %>">Paged</a> | <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>
-
- <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>
-
- <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>
+<%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 &>
<& 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>
<%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>
+
+
+++ /dev/null
-<%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> </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>
-
-
--- /dev/null
+<%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>
+
+ <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>
+
+ <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>
-<%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
</%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
+++ /dev/null
-<%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>
-
-
-
-
-
--- /dev/null
+<%flags>inherit='base.myt'</%flags>
+<%args>
+ extension
+ toc
+</%args>
+
+<& toc.myt:toc, toc=toc, extension=extension &>
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
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
------------
--- /dev/null
+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
+
#!/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)
+
-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 = {}
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):
+++ /dev/null
-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()
-
--- /dev/null
+"""
+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)
--- /dev/null
+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)
+
+
#!/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
\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
+++ /dev/null
-"""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