PYTHON   15

wiki py

Guest on 28th June 2022 09:48:55 AM

  1. """
  2. The Wiki module primarily exports the `WikiPage` class:
  3. """
  4.  
  5. import os, re, time
  6. from docutils import core, io
  7. from docutils import readers
  8.  
  9. __all__ = ['WikiPage', 'allPages', 'recentPages',
  10.            'searchTitles', 'search', 'css']
  11.  
  12. ## All the Wiki pages will be kept in this directory:
  13. pageDir = '/usr/home/ianb/w/pypaper/pages/'
  14.  
  15. class WikiPage(object):
  16.     """
  17.    WikiPage is a class to represent one page in a WikiWikiWeb [#]_.
  18.    The page may or may not yet exist -- that is, it may not yet
  19.    have content.
  20.  
  21.    .. [#] http://c2.com/cgi-bin/wiki
  22.  
  23.    It has the following properties and methods:
  24.  
  25.        `html`:
  26.            A read-only property giving the HTML for the page.
  27.            If the page does not yet have content the text
  28.            ``"This page has not yet been created"`` is returned.
  29.        `text`:
  30.            The text for the page.  To save new text, simply
  31.            assign to this property.
  32.        `title`:
  33.            The title of the page.
  34.        `name`:
  35.            The name of the page -- a canonical identifier.
  36.            Related to the title, but not necessarily the
  37.            same.
  38.        .. ignore: html
  39.        .. ignore: text
  40.        .. ignore: setText
  41.        .. ignore: title
  42.  
  43.    """
  44.  
  45.     def __init__(self, pageName):
  46.         """
  47.        Each page has a name, which is a unique identifier, for example
  48.        ``"FrontPage"``, which identifies the page in the URL and
  49.        for linking.
  50.        """
  51.         self.name = pageName
  52.  
  53.     def basePath(self):
  54.         """
  55.        :Ignore: yes
  56.        Returns the base path (sans extension) for this page
  57.        """
  58.         return _basePath(self.name)
  59.  
  60.     basePath = property(basePath)
  61.  
  62.     def exists(self):
  63.         """Does this page have content yet?"""
  64.         return _exists(self.name)
  65.  
  66.     def html(self):
  67.         """Returns text of HTML for page (HTML fragment only)"""
  68.         if self.exists():
  69.             html = open(self.basePath + ".html").read()
  70.             html = self._subWikiLinks(html)
  71.             return html
  72.         else:
  73.             return 'This page has not yet been created.'
  74.  
  75.     html = property(html)
  76.  
  77.     def preview(self, text):
  78.         """Returns an HTML preview of the text"""
  79.         return self._subWikiLinks(self._convertText(text))
  80.  
  81.     _wikiLinkRE = re.compile(r'(<a [^>]* href=")!(.*?)("[^>]*>)(.*?)(</a>)',
  82.                              re.I+re.S)
  83.    
  84.     def _subWikiLinks(self, text):
  85.         return self._wikiLinkRE.sub(self._subLink, ' %s ' % text)
  86.  
  87.     def _subLink(self, match):
  88.         if _exists(match.group(2)):
  89.             return match.group(1) + match.group(2) + match.group(3) + match.group(4) + match.group(5)
  90.         else:
  91.             return '<span class="nowiki">%s%s%s%s?%s</span>' \
  92.                    % (match.group(4), match.group(1), match.group(2),
  93.                       match.group(3), match.group(5))
  94.  
  95.     def text(self):
  96.         """
  97.        The text of the page.  ReStructuredText is used, though the
  98.        parsing is internal to the module.  You can assign to this
  99.        property to save new text for the page.
  100.        """
  101.         if self.exists():
  102.             return open(self.basePath + ".txt").read()
  103.         else:
  104.             return ''
  105.  
  106.     def setText(self, text):
  107.         """Sets the text for the page (and updates cached HTML at the
  108.        same time)"""
  109.         f = open(self.basePath + ".txt", 'w')
  110.         f.write(text)
  111.         f.close()
  112.         f = open(self.basePath + ".html", 'w')
  113.         f.write(self._convertText(text))
  114.         f.close()
  115.  
  116.     def _convertText(self, text):
  117.         return self._cleanHTML(core.publish_string(
  118.             source=text,
  119.             reader=Reader(),
  120.             parser_name='restructuredtext',
  121.             writer_name='html'))
  122.  
  123.     def _cleanHTML(self, html):
  124.         return html[html.find('<body>'):html.find('</body>')]
  125.  
  126.     text = property(text, setText)
  127.  
  128.     def searchMatches(self, text):
  129.         """
  130.        :Ignore: yes
  131.        """
  132.         return self.searchTitleMatches(text) \
  133.                or self.text().lower().find(text.lower()) != -1
  134.  
  135.     def searchTitleMatches(self, text):
  136.         """
  137.        :Ignore: yes
  138.        """
  139.         return self.title().lower().find(text.lower()) != -1
  140.  
  141.     def modifiedDate(self):
  142.         """Date modified (integer timestamp)"""
  143.         return os.stat(self.basePath + ".txt").st_mtime
  144.  
  145.     modifiedDate = property(modifiedDate)
  146.  
  147.     def modifiedDateText(self):
  148.         """Text representation of modified date"""
  149.         return time.strftime("%a %m/%d/%y", time.gmtime(self.modifiedDate()))
  150.  
  151.     modifiedDateText = property(modifiedDateText)
  152.  
  153.     def title(self):
  154.         """Page title"""
  155.         return self.name
  156.        
  157.     title = property(title)
  158.  
  159. """
  160. Methods for searching the wiki pages:
  161. """
  162.  
  163. def allPages():
  164.     """All pages with content in the system"""
  165.     return [WikiPage(page[:-4])
  166.             for page in os.listdir(pageDir)
  167.             if page.endswith('.txt')]
  168.    
  169. def recentPages():
  170.     """All pages, sorted by date modified, most recent first"""
  171.     pages = allPages()
  172.     pages.sort(lambda a, b: cmp(b.modifiedDate(), a.modifiedDate()))
  173.     return pages
  174.  
  175. def searchTitles(text):
  176.     """Search page titles for ``text``, returning list of pages"""
  177.     return [page for page in allPages()
  178.             if page.searchTitleMatches(text)]
  179.  
  180. def search(text):
  181.     """Search titles and bodies of pages for ``text``, returning list
  182.    of pages"""
  183.     return [page for page in allPages()
  184.             if page.searchMatches(text)]
  185.  
  186.  
  187. def _basePath(name):
  188.     return os.path.join(pageDir, name)
  189.  
  190. def _exists(name):
  191.     return os.path.exists(_basePath(name) + ".html")
  192.  
  193. """
  194. There is one module global to be printed at the top of
  195. every Wiki page:
  196.  
  197.    `css`:
  198.        The HTML to put the proper CSS at the top of the page.  This
  199.        should be put in the ``<head>`` section of the page.
  200. """
  201.  
  202. try:
  203.     f = open('default.css')
  204. except IOError:
  205.     css = ""
  206. else:
  207.     css = '<style type="text/css">\n%s</style>\n' % f.read()
  208.     f.close()
  209.  
  210. ########################################
  211. ## reST-specific stuff
  212. ########################################
  213.  
  214.  
  215. from docutils import nodes
  216. from docutils.readers import standalone
  217. from docutils.transforms import Transform
  218.  
  219. class WikiLinkResolver(nodes.SparseNodeVisitor):
  220.     ":Ignore: yes"
  221.  
  222.     def visit_reference(self, node):
  223.         if node.resolved or not node.hasattr('refname'):
  224.             return
  225.         refname = node['refname']
  226.         node.resolved = 1
  227.         node['class'] = 'wiki'
  228.         # I put a ! here to distinguish Wiki links from other
  229.         # links -- Wiki links have to be fixed up at view time,
  230.         # to distinguish between dangling and resolved Wiki
  231.         # links.
  232.         node['refuri'] = '!' + refname
  233.         del node['refname']
  234.  
  235. class WikiLink(Transform):
  236.     ":Ignore: yes"
  237.  
  238.     default_priority = 800
  239.  
  240.     def apply(self):
  241.         visitor = WikiLinkResolver(self.document)
  242.         self.document.walk(visitor)
  243.        
  244. class Reader(standalone.Reader):
  245.     ":Ignore: yes"
  246.  
  247.     supported = standalone.Reader.supported + ('wiki',)
  248.  
  249.     def get_transforms(self):
  250.         return standalone.Reader.get_transforms(self) + [WikiLink]

Raw Paste


Login or Register to edit or fork this paste. It's free.