pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

Python pastebin - collaborative debugging tool View Help


Posted by dw on Wed 1 Oct 16:23
report abuse | download | new post

  1. #!/usr/bin/env python2.5
  2.  
  3. import os, re, cgi, datetime, time, sys, urllib
  4.  
  5. import cgitb
  6.  
  7. from xml.etree.ElementTree import Element, SubElement, ElementTree,\
  8.     ProcessingInstruction
  9. import xml.etree.ElementTree as ElementTreex
  10.  
  11.  
  12. NEW_GUID_DATE = datetime.datetime(2005,  7,  6)
  13. PUBLISHED_FLAG_DATE = datetime.datetime(2007, 7, 12)
  14.  
  15.  
  16. class ParsedArgs:
  17.     def __init__(self, argStr):
  18.         for pair in (argStr or '').split('&'):
  19.             if '=' in pair:
  20.                 key, value = pair.split('=', 1)
  21.                 value = urllib.unquote(value)
  22.             else:
  23.                 key = pair
  24.                 value = True
  25.  
  26.             setattr(self, urllib.unquote(key), value)
  27.  
  28.  
  29.     def __getattr__(self, key):
  30.         return False
  31.  
  32.  
  33.  
  34.  
  35. def myfilter(filter_func, sequence):
  36.     '''
  37.    As with the filter() built-in, except return a list of
  38.    (fn_result, <object>) tuples rather than simply a list of <object>s.
  39.    '''
  40.  
  41.     output = []
  42.  
  43.     for item in sequence:
  44.         result = filter_func(item)
  45.         if result:
  46.             output.append((result, item))
  47.  
  48.     return output
  49.  
  50.  
  51.  
  52.  
  53. class Entry:
  54.     XMLNS = 'http://www.w3.org/2005/Atom'
  55.  
  56.     def __init__(self, create_date):
  57.         self.create_date = create_date
  58.         self.title = None
  59.         self.html = False
  60.         self.tags = []
  61.  
  62.         if create_date < NEW_GUID_DATE:
  63.             s = create_date.strftime('%Y-%m-%d-%H:%M:%S')
  64.             self.guid = cgi.escape(s.replace(' ', '_'))
  65.         else:
  66.             self.guid = 'entry_' + str(int(time.mktime(create_date.timetuple())))
  67.  
  68.         if create_date < PUBLISHED_FLAG_DATE:
  69.             self.hidden = False
  70.         else:
  71.             self.hidden = True
  72.  
  73.         self.filename = create_date.strftime('%Y-%m-%d-%H:%M:%S')
  74.         pathname = os.path.join(entries_dir, self.filename)
  75.         self.fp = fp = file(pathname)
  76.  
  77.         ts = os.fstat(fp.fileno()).st_mtime
  78.         self.edit_date = create_date
  79.         #self.edit_date = datetime.datetime.fromtimestamp(ts)
  80.  
  81.         fileIter = iter(file(pathname))
  82.  
  83.         for line in fileIter:
  84.             line = line.rstrip()
  85.  
  86.             if ': ' in line:
  87.                 key, value = line.split(': ', 1)
  88.                 key = key.lower()
  89.  
  90.                 if key in ('category', 'tags'):
  91.                     self.tags = value.split(', ')
  92.                 elif key == 'title':
  93.                     self.title = value
  94.             elif not line:
  95.                 break
  96.             elif not self.title:
  97.                 self.title = line.rstrip()
  98.             else:
  99.                 if line == 'hidden':
  100.                     self.hidden = True
  101.                 elif line == 'published':
  102.                     self.hidden = False
  103.                 elif line == 'html':
  104.                     self.html = True
  105.  
  106.         self.body = ''.join([ x for x in fileIter ])
  107.  
  108.  
  109.     def format_body(self, bodyOnly = False):
  110.         if bodyOnly:
  111.             if self.html:
  112.                 return self.body
  113.             else:
  114.                 return self.format_quicktext()
  115.  
  116.         cdate = self.create_date.strftime('%a %d %B %Y, %H:%M')
  117.         mdate = self.edit_date.strftime('%a %d %B %Y, %H:%M')
  118.  
  119.         bits = [
  120.             '<a name="%s"></a>' % self.guid,
  121.             '<div class="entry">',
  122.             '<h2>%s</h2>\n' % cgi.escape(self.title),
  123.             '<p class="date">',
  124.             #'<em>Modified:</em> %s<br />' % mdate,
  125.             '<em>Created:</em> %s' % cdate,
  126.             '</p>\n',
  127.             '<div class="paras">'
  128.         ]
  129.  
  130.         if self.html:
  131.             bits.append(self.body)
  132.         else:
  133.             bits.append(self.format_quicktext())
  134.  
  135.         bits.append('</div>')
  136.         bits.append('''<div id="disqus_thread"></div><script type="text/javascript" src="http://disqus.com/forums/dmw/embed.js"></script><noscript><a href="http://dmw.disqus.com/?url=ref">View the discussion thread.</a></noscript><a class="dsq-brlink"><span class="logo-disqus"></span></a>''')
  137.         bits.append('</div>')
  138.  
  139.         return '\n'.join(bits)
  140.  
  141.  
  142.     def format_quicktext(self):
  143.         paras = map(htmlise, map(cgi.escape, self.body.split('\n\n')))
  144.  
  145.         data = []
  146.         for para in paras:
  147.             if para.startswith('<'):
  148.                 data.append(para)
  149.             elif para:
  150.                 data.append("<p>\n" + para + "</p>\n")
  151.  
  152.         return '\n'.join(data)
  153.  
  154.  
  155.     def get_dates(cls, substr = None):
  156.         dateRe = re.compile(
  157.             r'^(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d):(\d\d):(\d\d)'
  158.             '(?:.html)?$')
  159.         entries = []
  160.  
  161.         for match, item in myfilter(dateRe.match, os.listdir(entries_dir)):
  162.             if substr is not None and substr not in item:
  163.                 continue
  164.             entries.append(datetime.datetime(*map(int, match.groups())))
  165.  
  166.         entries.sort()
  167.         return entries
  168.  
  169.     get_dates = classmethod(get_dates)
  170.  
  171.  
  172.  
  173. def format_entry_rss(entry, chan, idx):
  174.     cdate = entry.create_date.strftime('%a %d %B %Y, %H:%M')
  175.     link = 'http://dmw.me.uk/weblog#' + entry.guid
  176.  
  177.     item = SubElement(chan, 'item')
  178.     SubElement(item, 'title').text = entry.title
  179.     SubElement(item, 'description').text = entry.format_body(bodyOnly = True)
  180.     SubElement(item, 'link').text = link
  181.     SubElement(item, 'guid').text = link
  182.  
  183.     SubElement(item, 'pubDate').text =\
  184.         entry.create_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
  185.  
  186.  
  187.  
  188.  
  189. def format_blog(id = None, hidden = False):
  190.     entries = Entry.get_dates(substr = id)
  191.     entries.reverse() # newest first.
  192.     entries = entries[:10]
  193.  
  194.     output = ''
  195.  
  196.     for date in entries:
  197.         entry = Entry(date)
  198.         if (not entry.hidden) or hidden or 1:
  199.             output += entry.format_body()
  200.  
  201.     return output
  202.  
  203.  
  204. def format_index():
  205.     title_links = []
  206.  
  207.     for dt in Entry.get_dates():
  208.         entry = Entry(dt)
  209.         title_links.append(
  210.                             '%s: '
  211.                             '<code>%s%s</code> '
  212.                             '<a href="%s">%s</a><br />' %
  213.             (entry.create_date,
  214.              ['.', 'P'][int('private' in entry.tags)],
  215.              ['.', 'H'][int(entry.hidden)],
  216.              "/weblog/%s" % entry.filename,
  217.              cgi.escape(str(entry.title))))
  218.  
  219.     return '\n'.join(title_links)
  220.  
  221.  
  222. def format_rss(hidden):
  223.     entries = Entry.get_dates()
  224.     entries.reverse() # newest first.
  225.     entries = entries[:1]
  226.  
  227.     strip = str.strip
  228.  
  229.     # RSS header.
  230.     doc = Element('rss', version = '2.0')
  231.     chan = SubElement(doc, 'channel')
  232.  
  233.     SubElement(chan, 'title').text = 'David Wilson\'s Weblog'
  234.  
  235.     SubElement(chan, 'link').text = 'http://dmw.me.uk/weblog/rss'
  236.  
  237.     SubElement(chan, 'description').text = strip('''
  238.        Random musings and thoughts from David Wilson, a programmer/geek of
  239.        sorts from Belfast, Northern Ireland.
  240.    ''')
  241.  
  242.     SubElement(chan, 'copyright').text = strip('''
  243.        Copyright 2004-2007, David Wilson.
  244.    ''')
  245.  
  246.     SubElement(chan, 'lastBuildDate').text =\
  247.         time.strftime('%a, %d %b %Y %H:%M:%S GMT')
  248.  
  249.     SubElement(chan, 'generator').text =\
  250.         'Python%s; ElementTree %s; blog.py 0.3' %\
  251.         (str(sys.version_info), ElementTreex.VERSION)
  252.  
  253.     SubElement(chan, 'docs').text =\
  254.         'http://blogs.law.harvard.edu/tech/rss'
  255.  
  256.  
  257.     for idx, date in enumerate(entries):
  258.         entry = Entry(date)
  259.         if (not entry.hidden) or hidden:
  260.             format_entry_rss(entry, chan, idx)
  261.  
  262.     return ElementTreex.tostring(doc)
  263.  
  264.  
  265.  
  266. def htmlise(text):
  267.     if text == '--':
  268.         return '<div class="divider">&nbsp;</div>'
  269.  
  270.     lines = text.split("\n")
  271.     list_re = re.compile(r'^    - (.+)')
  272.     bleh = myfilter(list_re.match, lines)
  273.  
  274.     if len(bleh) == len(lines):
  275.         out = [ '<ul>\n' ]
  276.         out += [ '<li>' + htmlise(match.groups()[0]) + '</li>' for match,line in bleh ]
  277.         out.append('</ul>\n\n')
  278.  
  279.         return '\n'.join(out)
  280.  
  281.  
  282.     R0 = re.compile(r'^&gt;&gt;(.+)&lt;&lt;$')
  283.     bleh = R0.match(text)
  284.  
  285.     if bleh:
  286.         return '<h3>' + bleh.groups()[0] + '</h3>\n'
  287.  
  288.     Rimg = re.compile(r'&lt;img (http[^&]+)&gt;')
  289.     text = Rimg.sub(r'<img src="\1" alt="" />', text)
  290.  
  291.     Rimg = re.compile(r'&lt;img ([^&]+)&gt;')
  292.     text = Rimg.sub(r'<img src="\1" alt="" />', text)
  293.  
  294.     R1 = re.compile(r'&lt;(http://[^&]+)&gt;([^\n]+?)&lt;/a&gt;', re.M)
  295.     text = R1.sub(r'<a href="\1">\2</a>', text)
  296.  
  297.     R2 = re.compile(r'&lt;(http://[^&]+)&gt;', re.M)
  298.     return R2.sub(r'<a href="\1">\1</a>', text)
  299.  
  300.  
  301.  
  302.  
  303. def get_header():
  304.     return file(os.path.join(blog_dir, 'header.html')).read()
  305.  
  306.  
  307.  
  308.  
  309. def get_footer():
  310.     return file(os.path.join(blog_dir, 'footer.html')).read()
  311.  
  312.  
  313.  
  314. def RunCGI():
  315.     global blog_dir, entries_dir
  316.  
  317.     cgitb.enable(display=1, logdir="/tmp")
  318.  
  319.     # Directory where blog.py is stored.
  320.     blog_dir = os.path.dirname(os.environ['SCRIPT_FILENAME'])
  321.     entries_dir = os.path.join(blog_dir, 'entries')
  322.     args = ParsedArgs(os.environ['QUERY_STRING'])
  323.  
  324.     print 'Content-type: text/html'
  325.     print
  326.  
  327.     if args.id:
  328.         sys.stdout.write(format_blog(id = args.id))
  329.     elif args.index:
  330.         sys.stdout.write(format_index())
  331.     elif args.body_only:
  332.         sys.stdout.write(format_blog(hidden = args.hidden != False))
  333.     elif args.rss:
  334.         sys.stdout.write(format_rss(hidden = args.hidden != False))
  335.     else:
  336.         sys.stdout.write(get_header())
  337.         sys.stdout.write(format_blog())
  338.         sys.stdout.write(get_footer())
  339.  
  340.  
  341. if __name__ == '__main__':
  342.     RunCGI()

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post