Mercurial > moin > 1.9
changeset 1048:b7544e3bd478
Merge with main.
author | Alexander Schremmer <alex AT alexanderweb DOT de> |
---|---|
date | Mon, 24 Jul 2006 22:18:49 +0200 |
parents | 51086fe55b58 (current diff) 6488692b1eb8 (diff) |
children | 3b5603bf468d ac85f3b79216 |
files | MoinMoin/config.py MoinMoin/formatter/text_python.py MoinMoin/multiconfig.py MoinMoin/util/diff.py MoinMoin/xmlrpc/__init__.py |
diffstat | 69 files changed, 2188 insertions(+), 2126 deletions(-) [+] |
line wrap: on
line diff
--- a/MoinMoin/_tests/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/_tests/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -94,9 +94,9 @@ Non existing default will raise an AttributeError. """ - from MoinMoin.multiconfig import DefaultConfig + from MoinMoin.config import multiconfig for key in defaults: - self._setattr(key, getattr(DefaultConfig, key)) + self._setattr(key, getattr(multiconfig.DefaultConfig, key)) def setCustom(self, **custom): """ Set custom values """
--- a/MoinMoin/action/AttachFile.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/action/AttachFile.py Mon Jul 24 22:18:49 2006 +0200 @@ -620,11 +620,12 @@ # delete map file if it is empty os.unlink(savepath) else: - file = open(savepath, 'wb') + stream = open(savepath, 'wb') try: - file.write(filecontent) + stream.write(filecontent) finally: - file.close() + stream.close() + os.chmod(savepath, 0666 & config.umask) # touch attachment directory to invalidate cache if new map is saved if ext == '.map':
--- a/MoinMoin/action/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/action/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -303,537 +303,11 @@ pg.send_page(request, msg=savemsg) return None -def do_edit(pagename, request): - """ edit a page """ - _ = request.getText - - if not request.user.may.write(pagename): - Page(request, pagename).send_page(request, - msg=_('You are not allowed to edit this page.')) - return - - valideditors = ['text', 'gui', ] - editor = '' - if request.user.valid: - editor = request.user.editor_default - if editor not in valideditors: - editor = request.cfg.editor_default - - editorparam = request.form.get('editor', [editor])[0] - if editorparam == "guipossible": - lasteditor = editor - elif editorparam == "textonly": - editor = lasteditor = 'text' - else: - editor = lasteditor = editorparam - - if request.cfg.editor_force: - editor = request.cfg.editor_default - - # if it is still nothing valid, we just use the text editor - if editor not in valideditors: - editor = 'text' - - savetext = request.form.get('savetext', [None])[0] - rev = int(request.form.get('rev', ['0'])[0]) - comment = request.form.get('comment', [u''])[0] - category = request.form.get('category', [None])[0] - rstrip = int(request.form.get('rstrip', ['0'])[0]) - trivial = int(request.form.get('trivial', ['0'])[0]) - - if request.form.has_key('button_switch'): - if editor == 'text': - editor = 'gui' - else: # 'gui' - editor = 'text' - - # load right editor class - if editor == 'gui': - from MoinMoin.PageGraphicalEditor import PageGraphicalEditor - pg = PageGraphicalEditor(request, pagename) - else: # 'text' - from MoinMoin.PageEditor import PageEditor - pg = PageEditor(request, pagename) - - # is invoked without savetext start editing - if savetext is None: - pg.sendEditor() - return - - # did user hit cancel button? - cancelled = request.form.has_key('button_cancel') - - # convert input from Graphical editor - from MoinMoin.converter.text_html_text_moin_wiki import convert, ConvertError - try: - if lasteditor == 'gui': - savetext = convert(request, pagename, savetext) - - # IMPORTANT: normalize text from the form. This should be done in - # one place before we manipulate the text. - savetext = pg.normalizeText(savetext, stripspaces=rstrip) - except ConvertError: - # we don't want to throw an exception if user cancelled anyway - if not cancelled: - raise - - if cancelled: - pg.sendCancel(savetext or "", rev) - return - - comment = wikiutil.clean_comment(comment) - - # Add category - - # TODO: this code does not work with extended links, and is doing - # things behind your back, and in general not needed. Either we have - # a full interface for categories (add, delete) or just add them by - # markup. - - if category and category != _('<No addition>', formatted=False): # opera 8.5 needs this - # strip trailing whitespace - savetext = savetext.rstrip() - - # Add category separator if last non-empty line contains - # non-categories. - lines = filter(None, savetext.splitlines()) - if lines: - - #TODO: this code is broken, will not work for extended links - #categories, e.g ["category hebrew"] - categories = lines[-1].split() - - if categories: - confirmed = wikiutil.filterCategoryPages(request, categories) - if len(confirmed) < len(categories): - # This was not a categories line, add separator - savetext += u'\n----\n' - - # Add new category - if savetext and savetext[-1] != u'\n': - savetext += ' ' - savetext += category + u'\n' # Should end with newline! - - # Preview, spellcheck or spellcheck add new words - if (request.form.has_key('button_preview') or - request.form.has_key('button_spellcheck') or - request.form.has_key('button_newwords')): - pg.sendEditor(preview=savetext, comment=comment) - - # Preview with mode switch - elif request.form.has_key('button_switch'): - pg.sendEditor(preview=savetext, comment=comment, staytop=1) - - # Save new text - else: - try: - still_conflict = wikiutil.containsConflictMarker(savetext) - pg.setConflict(still_conflict) - savemsg = pg.saveText(savetext, rev, trivial=trivial, comment=comment) - except pg.EditConflict, e: - msg = e.message - - # Handle conflict and send editor - pg.set_raw_body(savetext, modified=1) - - pg.mergeEditConflict(rev) - # We don't send preview when we do merge conflict - pg.sendEditor(msg=msg, comment=comment) - return - - except pg.SaveError, msg: - # msg contain a unicode string - savemsg = unicode(msg) - - # Send new page after save or after unsuccessful conflict merge. - request.reset() - backto = request.form.get('backto', [None])[0] - if backto: - pg = Page(request, backto) - - pg.send_page(request, msg=savemsg) - def do_goto(pagename, request): """ redirect to another page """ target = request.form.get('target', [''])[0] request.http_redirect(Page(request, target).url(request)) -def do_diff(pagename, request): - """ Handle "action=diff" - checking for either a "rev=formerrevision" parameter - or rev1 and rev2 parameters - """ - if not request.user.may.read(pagename): - Page(request, pagename).send_page(request) - return - - try: - date = request.form['date'][0] - try: - date = long(date) # must be long for py 2.2.x - except StandardError: - date = 0 - except KeyError: - date = 0 - - try: - rev1 = int(request.form.get('rev1', [-1])[0]) - except StandardError: - rev1 = 0 - try: - rev2 = int(request.form.get('rev2', [0])[0]) - except StandardError: - rev1 = 0 - - if rev1 == -1 and rev2 == 0: - try: - rev1 = int(request.form.get('rev', [-1])[0]) - except StandardError: - rev1 = -1 - - # spacing flag? - ignorews = int(request.form.get('ignorews', [0])[0]) - - _ = request.getText - - # get a list of old revisions, and back out if none are available - currentpage = Page(request, pagename) - revisions = currentpage.getRevList() - if len(revisions) < 2: - currentpage.send_page(request, msg=_("No older revisions available!")) - return - - if date: # this is how we get called from RecentChanges - rev1 = 0 - log = editlog.EditLog(request, rootpagename=pagename) - for line in log.reverse(): - if date >= line.ed_time_usecs and int(line.rev) != 99999999: - rev1 = int(line.rev) - break - else: - rev1 = 1 - rev2 = 0 - - # Start output - # This action generate content in the user language - request.setContentLanguage(request.lang) - - request.http_headers() - request.theme.send_title(_('Diff for "%s"') % (pagename,), pagename=pagename, allow_doubleclick=1) - - if rev1 > 0 and rev2 > 0 and rev1 > rev2 or rev1 == 0 and rev2 > 0: - rev1, rev2 = rev2, rev1 - - oldrev1, oldcount1 = None, 0 - oldrev2, oldcount2 = None, 0 - - # get the filename of the version to compare to - edit_count = 0 - for rev in revisions: - edit_count += 1 - if rev <= rev1: - oldrev1, oldcount1 = rev, edit_count - if rev2 and rev >= rev2: - oldrev2, oldcount2 = rev, edit_count - if oldrev1 and oldrev2 or oldrev1 and not rev2: - break - - if rev1 == -1: - oldpage = Page(request, pagename, rev=revisions[1]) - oldcount1 -= 1 - elif rev1 == 0: - oldpage = currentpage - # oldcount1 is still on init value 0 - else: - if oldrev1: - oldpage = Page(request, pagename, rev=oldrev1) - else: - oldpage = Page(request, "$EmptyPage$") # hack - oldpage.set_raw_body("") # avoid loading from disk - oldrev1 = 0 # XXX - - if rev2 == 0: - newpage = currentpage - # oldcount2 is still on init value 0 - else: - if oldrev2: - newpage = Page(request, pagename, rev=oldrev2) - else: - newpage = Page(request, "$EmptyPage$") # hack - newpage.set_raw_body("") # avoid loading from disk - oldrev2 = 0 # XXX - - edit_count = abs(oldcount1 - oldcount2) - - # this should use the formatter, but there is none? - request.write('<div id="content">\n') # start content div - request.write('<p class="diff-header">') - request.write(_('Differences between revisions %d and %d') % (oldpage.get_real_rev(), newpage.get_real_rev())) - if edit_count > 1: - request.write(' ' + _('(spanning %d versions)') % (edit_count,)) - request.write('</p>') - - if request.user.show_fancy_diff: - from MoinMoin.util.diff import diff - request.write(diff(request, oldpage.get_raw_body(), newpage.get_raw_body())) - newpage.send_page(request, count_hit=0, content_only=1, content_id="content-below-diff") - else: - lines = wikiutil.linediff(oldpage.getlines(), newpage.getlines()) - if not lines: - msg = _("No differences found!") - if edit_count > 1: - msg = msg + '<p>' + _('The page was saved %(count)d times, though!') % { - 'count': edit_count} - request.write(msg) - else: - if ignorews: - request.write(_('(ignoring whitespace)') + '<br>') - else: - qstr = 'action=diff&ignorews=1' - if rev1: qstr = '%s&rev1=%s' % (qstr, rev1) - if rev2: qstr = '%s&rev2=%s' % (qstr, rev2) - request.write(Page(request, pagename).link_to(request, - text=_('Ignore changes in the amount of whitespace'), - querystr=qstr, rel='nofollow') + '<p>') - - request.write('<pre>') - for line in lines: - if line[0] == "@": - request.write('<hr>') - request.write(wikiutil.escape(line)+'\n') - request.write('</pre>') - - request.write('</div>\n') # end content div - request.theme.send_footer(pagename) - request.theme.send_closing_html() - -def do_info(pagename, request): - """ show misc. infos about a page """ - if not request.user.may.read(pagename): - Page(request, pagename).send_page(request) - return - - def general(page, pagename, request): - _ = request.getText - - request.write('<h2>%s</h2>\n' % _('General Information')) - - # show page size - request.write(("<p>%s</p>" % _("Page size: %d")) % page.size()) - - # show SHA digest fingerprint - import sha - digest = sha.new(page.get_raw_body().encode(config.charset)).hexdigest().upper() - request.write('<p>%(label)s <tt>%(value)s</tt></p>' % { - 'label': _("SHA digest of this page's content is:"), - 'value': digest, - }) - - # show attachments (if allowed) - attachment_info = getHandler(request, 'AttachFile', 'info') - if attachment_info: - request.write(attachment_info(pagename, request)) - - # show subscribers - subscribers = page.getSubscribers(request, include_self=1, return_users=1) - if subscribers: - request.write('<p>', _('The following users subscribed to this page:')) - for lang in subscribers.keys(): - request.write('<br>[%s] ' % lang) - for user in subscribers[lang]: - # do NOT disclose email addr, only WikiName - userhomepage = Page(request, user.name) - if userhomepage.exists(): - request.write(userhomepage.link_to(request) + ' ') - else: - request.write(user.name + ' ') - request.write('</p>') - - # show links - links = page.getPageLinks(request) - if links: - request.write('<p>', _('This page links to the following pages:'), '<br>') - for linkedpage in links: - request.write("%s%s " % (Page(request, linkedpage).link_to(request), ",."[linkedpage == links[-1]])) - request.write("</p>") - - def history(page, pagename, request): - # show history as default - _ = request.getText - - # open log for this page - from MoinMoin.util.dataset import TupleDataset, Column - - history = TupleDataset() - history.columns = [ - Column('rev', label='#', align='right'), - Column('mtime', label=_('Date'), align='right'), - Column('size', label=_('Size'), align='right'), - Column('diff', label='<input type="submit" value="%s">' % (_("Diff"))), - Column('editor', label=_('Editor'), hidden=not request.cfg.show_names), - Column('comment', label=_('Comment')), - Column('action', label=_('Action')), - ] - - # generate history list - revisions = page.getRevList() - versions = len(revisions) - - may_revert = request.user.may.revert(pagename) - - # read in the complete log of this page - log = editlog.EditLog(request, rootpagename=pagename) - count = 0 - for line in log.reverse(): - rev = int(line.rev) - actions = "" - if line.action in ['SAVE', 'SAVENEW', 'SAVE/REVERT', ]: - size = page.size(rev=rev) - if count == 0: # latest page - actions = '%s %s' % (actions, page.link_to(request, - text=_('view'), - querystr='')) - actions = '%s %s' % (actions, page.link_to(request, - text=_('raw'), - querystr='action=raw', rel='nofollow')) - actions = '%s %s' % (actions, page.link_to(request, - text=_('print'), - querystr='action=print', rel='nofollow')) - else: - actions = '%s %s' % (actions, page.link_to(request, - text=_('view'), - querystr='action=recall&rev=%d' % rev, rel='nofollow')) - actions = '%s %s' % (actions, page.link_to(request, - text=_('raw'), - querystr='action=raw&rev=%d' % rev, rel='nofollow')) - actions = '%s %s' % (actions, page.link_to(request, - text=_('print'), - querystr='action=print&rev=%d' % rev, rel='nofollow')) - if may_revert and size: # you can only revert to nonempty revisions - actions = '%s %s' % (actions, page.link_to(request, - text=_('revert'), - querystr='action=revert&rev=%d' % rev, rel='nofollow')) - if count == 0: - rchecked = ' checked="checked"' - lchecked = '' - elif count == 1: - lchecked = ' checked="checked"' - rchecked = '' - else: - lchecked = rchecked = '' - diff = '<input type="radio" name="rev1" value="%d"%s><input type="radio" name="rev2" value="%d"%s>' % (rev, lchecked, rev, rchecked) - comment = line.comment - if not comment and '/REVERT' in line.action: - comment = _("Revert to revision %(rev)d.") % {'rev': int(line.extra)} - else: # ATT* - rev = '-' - diff = '-' - - filename = wikiutil.url_unquote(line.extra) - comment = "%s: %s %s" % (line.action, filename, line.comment) - size = 0 - if line.action != 'ATTDEL': - from MoinMoin.action import AttachFile - page_dir = AttachFile.getAttachDir(request, pagename) - filepath = os.path.join(page_dir, filename) - try: - # FIXME, wrong path on non-std names - size = os.path.getsize(filepath) - except: - pass - if line.action == 'ATTNEW': - actions = '%s %s' % (actions, page.link_to(request, - text=_('view'), - querystr='action=AttachFile&do=view&target=%s' % filename, rel='nofollow')) - elif line.action == 'ATTDRW': - actions = '%s %s' % (actions, page.link_to(request, - text=_('edit'), - querystr='action=AttachFile&drawing=%s' % filename.replace(".draw", ""), rel='nofollow')) - - actions = '%s %s' % (actions, page.link_to(request, - text=_('get'), - querystr='action=AttachFile&do=get&target=%s' % filename, rel='nofollow')) - actions = '%s %s' % (actions, page.link_to(request, - text=_('del'), - querystr='action=AttachFile&do=del&target=%s' % filename, rel='nofollow')) - # XXX use?: wikiutil.escape(filename) - - history.addRow(( - rev, - request.user.getFormattedDateTime(wikiutil.version2timestamp(line.ed_time_usecs)), - str(size), - diff, - line.getEditor(request) or _("N/A"), - wikiutil.escape(comment) or ' ', - actions, - )) - count += 1 - if count >= 100: - break - - # print version history - from MoinMoin.widget.browser import DataBrowserWidget - - request.write('<h2>%s</h2>\n' % _('Revision History')) - - if not count: # there was no entry in logfile - request.write(_('No log entries found.')) - return - - # TODO: this form activates revert, which should use POST, but - # other actions should use get. Maybe we should put the revert - # into the page view itself, and not in this form. - request.write('<form method="GET" action="">\n') - request.write('<div id="page-history">\n') - request.write('<input type="hidden" name="action" value="diff">\n') - - history_table = DataBrowserWidget(request) - history_table.setData(history) - history_table.render() - request.write('</div>\n') - request.write('</form>\n') - - # main function - _ = request.getText - page = Page(request, pagename) - qpagename = wikiutil.quoteWikinameURL(pagename) - title = page.split_title(request) - - request.http_headers() - - # This action uses page or wiki language TODO: currently - # page.language is broken and not available now, when we fix it, - # this will be automatically fixed. - lang = page.language or request.cfg.language_default - request.setContentLanguage(lang) - - request.theme.send_title(_('Info for "%s"') % (title,), pagename=pagename) - - historylink = wikiutil.link_tag(request, '%s?action=info' % qpagename, - _('Show "%(title)s"') % {'title': _('Revision History')}, request.formatter, rel='nofollow') - generallink = wikiutil.link_tag(request, '%s?action=info&general=1' % qpagename, - _('Show "%(title)s"') % {'title': _('General Page Infos')}, request.formatter, rel='nofollow') - hitcountlink = wikiutil.link_tag(request, '%s?action=info&hitcounts=1' % qpagename, - _('Show chart "%(title)s"') % {'title': _('Page hits and edits')}, request.formatter, rel='nofollow') - - request.write('<div id="content">\n') # start content div - request.write("<p>[%s] [%s] [%s]</p>" % (historylink, generallink, hitcountlink)) - - show_hitcounts = int(request.form.get('hitcounts', [0])[0]) != 0 - show_general = int(request.form.get('general', [0])[0]) != 0 - - if show_hitcounts: - from MoinMoin.stats import hitcounts - request.write(hitcounts.linkto(pagename, request, 'page=' + wikiutil.url_quote_plus(pagename))) - elif show_general: - general(page, pagename, request) - else: - history(page, pagename, request) - - request.write('</div>\n') # end content div - request.theme.send_footer(pagename) - request.theme.send_closing_html() - def do_quicklink(pagename, request): """ Add the current wiki page to the user quicklinks
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/action/diff.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,163 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - show diff between 2 page revisions + + @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>, + 2006 by MoinMoin:ThomasWaldmann + @license: GNU GPL, see COPYING for details. +""" + +from MoinMoin import wikiutil +from MoinMoin.logfile import editlog +from MoinMoin.Page import Page + +def execute(pagename, request): + """ Handle "action=diff" + checking for either a "rev=formerrevision" parameter + or rev1 and rev2 parameters + """ + if not request.user.may.read(pagename): + Page(request, pagename).send_page(request) + return + + try: + date = request.form['date'][0] + try: + date = long(date) # must be long for py 2.2.x + except StandardError: + date = 0 + except KeyError: + date = 0 + + try: + rev1 = int(request.form.get('rev1', [-1])[0]) + except StandardError: + rev1 = 0 + try: + rev2 = int(request.form.get('rev2', [0])[0]) + except StandardError: + rev1 = 0 + + if rev1 == -1 and rev2 == 0: + try: + rev1 = int(request.form.get('rev', [-1])[0]) + except StandardError: + rev1 = -1 + + # spacing flag? + ignorews = int(request.form.get('ignorews', [0])[0]) + + _ = request.getText + + # get a list of old revisions, and back out if none are available + currentpage = Page(request, pagename) + revisions = currentpage.getRevList() + if len(revisions) < 2: + currentpage.send_page(request, msg=_("No older revisions available!")) + return + + if date: # this is how we get called from RecentChanges + rev1 = 0 + log = editlog.EditLog(request, rootpagename=pagename) + for line in log.reverse(): + if date >= line.ed_time_usecs and int(line.rev) != 99999999: + rev1 = int(line.rev) + break + else: + rev1 = 1 + rev2 = 0 + + # Start output + # This action generate content in the user language + request.setContentLanguage(request.lang) + + request.http_headers() + request.theme.send_title(_('Diff for "%s"') % (pagename,), pagename=pagename, allow_doubleclick=1) + + if rev1 > 0 and rev2 > 0 and rev1 > rev2 or rev1 == 0 and rev2 > 0: + rev1, rev2 = rev2, rev1 + + oldrev1, oldcount1 = None, 0 + oldrev2, oldcount2 = None, 0 + + # get the filename of the version to compare to + edit_count = 0 + for rev in revisions: + edit_count += 1 + if rev <= rev1: + oldrev1, oldcount1 = rev, edit_count + if rev2 and rev >= rev2: + oldrev2, oldcount2 = rev, edit_count + if oldrev1 and oldrev2 or oldrev1 and not rev2: + break + + if rev1 == -1: + oldpage = Page(request, pagename, rev=revisions[1]) + oldcount1 -= 1 + elif rev1 == 0: + oldpage = currentpage + # oldcount1 is still on init value 0 + else: + if oldrev1: + oldpage = Page(request, pagename, rev=oldrev1) + else: + oldpage = Page(request, "$EmptyPage$") # hack + oldpage.set_raw_body("") # avoid loading from disk + oldrev1 = 0 # XXX + + if rev2 == 0: + newpage = currentpage + # oldcount2 is still on init value 0 + else: + if oldrev2: + newpage = Page(request, pagename, rev=oldrev2) + else: + newpage = Page(request, "$EmptyPage$") # hack + newpage.set_raw_body("") # avoid loading from disk + oldrev2 = 0 # XXX + + edit_count = abs(oldcount1 - oldcount2) + + # this should use the formatter, but there is none? + request.write('<div id="content">\n') # start content div + request.write('<p class="diff-header">') + request.write(_('Differences between revisions %d and %d') % (oldpage.get_real_rev(), newpage.get_real_rev())) + if edit_count > 1: + request.write(' ' + _('(spanning %d versions)') % (edit_count,)) + request.write('</p>') + + if request.user.show_fancy_diff: + from MoinMoin.util import diff_html + request.write(diff_html.diff(request, oldpage.get_raw_body(), newpage.get_raw_body())) + newpage.send_page(request, count_hit=0, content_only=1, content_id="content-below-diff") + else: + from MoinMoin.util import diff_text + lines = diff_text.diff(oldpage.getlines(), newpage.getlines()) + if not lines: + msg = _("No differences found!") + if edit_count > 1: + msg = msg + '<p>' + _('The page was saved %(count)d times, though!') % { + 'count': edit_count} + request.write(msg) + else: + if ignorews: + request.write(_('(ignoring whitespace)') + '<br>') + else: + qstr = 'action=diff&ignorews=1' + if rev1: qstr = '%s&rev1=%s' % (qstr, rev1) + if rev2: qstr = '%s&rev2=%s' % (qstr, rev2) + request.write(Page(request, pagename).link_to(request, + text=_('Ignore changes in the amount of whitespace'), + querystr=qstr, rel='nofollow') + '<p>') + + request.write('<pre>') + for line in lines: + if line[0] == "@": + request.write('<hr>') + request.write(wikiutil.escape(line)+'\n') + request.write('</pre>') + + request.write('</div>\n') # end content div + request.theme.send_footer(pagename) + request.theme.send_closing_html() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/action/edit.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,164 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - edit a page + + This either calls the text or the GUI page editor. + + @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>, + 2006 by MoinMoin:ThomasWaldmann + @license: GNU GPL, see COPYING for details. +""" +from MoinMoin import wikiutil +from MoinMoin.Page import Page + +def execute(pagename, request): + """ edit a page """ + _ = request.getText + + if not request.user.may.write(pagename): + Page(request, pagename).send_page(request, + msg=_('You are not allowed to edit this page.')) + return + + valideditors = ['text', 'gui', ] + editor = '' + if request.user.valid: + editor = request.user.editor_default + if editor not in valideditors: + editor = request.cfg.editor_default + + editorparam = request.form.get('editor', [editor])[0] + if editorparam == "guipossible": + lasteditor = editor + elif editorparam == "textonly": + editor = lasteditor = 'text' + else: + editor = lasteditor = editorparam + + if request.cfg.editor_force: + editor = request.cfg.editor_default + + # if it is still nothing valid, we just use the text editor + if editor not in valideditors: + editor = 'text' + + savetext = request.form.get('savetext', [None])[0] + rev = int(request.form.get('rev', ['0'])[0]) + comment = request.form.get('comment', [u''])[0] + category = request.form.get('category', [None])[0] + rstrip = int(request.form.get('rstrip', ['0'])[0]) + trivial = int(request.form.get('trivial', ['0'])[0]) + + if request.form.has_key('button_switch'): + if editor == 'text': + editor = 'gui' + else: # 'gui' + editor = 'text' + + # load right editor class + if editor == 'gui': + from MoinMoin.PageGraphicalEditor import PageGraphicalEditor + pg = PageGraphicalEditor(request, pagename) + else: # 'text' + from MoinMoin.PageEditor import PageEditor + pg = PageEditor(request, pagename) + + # is invoked without savetext start editing + if savetext is None: + pg.sendEditor() + return + + # did user hit cancel button? + cancelled = request.form.has_key('button_cancel') + + # convert input from Graphical editor + from MoinMoin.converter.text_html_text_moin_wiki import convert, ConvertError + try: + if lasteditor == 'gui': + savetext = convert(request, pagename, savetext) + + # IMPORTANT: normalize text from the form. This should be done in + # one place before we manipulate the text. + savetext = pg.normalizeText(savetext, stripspaces=rstrip) + except ConvertError: + # we don't want to throw an exception if user cancelled anyway + if not cancelled: + raise + + if cancelled: + pg.sendCancel(savetext or "", rev) + return + + comment = wikiutil.clean_comment(comment) + + # Add category + + # TODO: this code does not work with extended links, and is doing + # things behind your back, and in general not needed. Either we have + # a full interface for categories (add, delete) or just add them by + # markup. + + if category and category != _('<No addition>', formatted=False): # opera 8.5 needs this + # strip trailing whitespace + savetext = savetext.rstrip() + + # Add category separator if last non-empty line contains + # non-categories. + lines = filter(None, savetext.splitlines()) + if lines: + + #TODO: this code is broken, will not work for extended links + #categories, e.g ["category hebrew"] + categories = lines[-1].split() + + if categories: + confirmed = wikiutil.filterCategoryPages(request, categories) + if len(confirmed) < len(categories): + # This was not a categories line, add separator + savetext += u'\n----\n' + + # Add new category + if savetext and savetext[-1] != u'\n': + savetext += ' ' + savetext += category + u'\n' # Should end with newline! + + # Preview, spellcheck or spellcheck add new words + if (request.form.has_key('button_preview') or + request.form.has_key('button_spellcheck') or + request.form.has_key('button_newwords')): + pg.sendEditor(preview=savetext, comment=comment) + + # Preview with mode switch + elif request.form.has_key('button_switch'): + pg.sendEditor(preview=savetext, comment=comment, staytop=1) + + # Save new text + else: + try: + still_conflict = wikiutil.containsConflictMarker(savetext) + pg.setConflict(still_conflict) + request.http_headers() # XXX WHY? XXX + savemsg = pg.saveText(savetext, rev, trivial=trivial, comment=comment) + except pg.EditConflict, e: + msg = e.message + + # Handle conflict and send editor + pg.set_raw_body(savetext, modified=1) + + pg.mergeEditConflict(rev) + # We don't send preview when we do merge conflict + pg.sendEditor(msg=msg, comment=comment) + return + + except pg.SaveError, msg: + # msg contains a unicode string + savemsg = unicode(msg) + + # Send new page after save or after unsuccessful conflict merge. + request.reset() + backto = request.form.get('backto', [None])[0] + if backto: + pg = Page(request, backto) + + pg.send_page(request, msg=savemsg) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/action/info.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,245 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - info action + + Displays page history, some general page infos and statistics. + + @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>, + 2006 by MoinMoin:ThomasWaldmann + @license: GNU GPL, see COPYING for details. +""" + +from MoinMoin import config, wikiutil, action +from MoinMoin.Page import Page +from MoinMoin.logfile import editlog + +def execute(pagename, request): + """ show misc. infos about a page """ + if not request.user.may.read(pagename): + Page(request, pagename).send_page(request) + return + + def general(page, pagename, request): + _ = request.getText + + request.write('<h2>%s</h2>\n' % _('General Information')) + + # show page size + request.write(("<p>%s</p>" % _("Page size: %d")) % page.size()) + + # show SHA digest fingerprint + import sha + digest = sha.new(page.get_raw_body().encode(config.charset)).hexdigest().upper() + request.write('<p>%(label)s <tt>%(value)s</tt></p>' % { + 'label': _("SHA digest of this page's content is:"), + 'value': digest, + }) + + # show attachments (if allowed) + attachment_info = action.getHandler(request, 'AttachFile', 'info') + if attachment_info: + request.write(attachment_info(pagename, request)) + + # show subscribers + subscribers = page.getSubscribers(request, include_self=1, return_users=1) + if subscribers: + request.write('<p>', _('The following users subscribed to this page:')) + for lang in subscribers.keys(): + request.write('<br>[%s] ' % lang) + for user in subscribers[lang]: + # do NOT disclose email addr, only WikiName + userhomepage = Page(request, user.name) + if userhomepage.exists(): + request.write(userhomepage.link_to(request) + ' ') + else: + request.write(user.name + ' ') + request.write('</p>') + + # show links + links = page.getPageLinks(request) + if links: + request.write('<p>', _('This page links to the following pages:'), '<br>') + for linkedpage in links: + request.write("%s%s " % (Page(request, linkedpage).link_to(request), ",."[linkedpage == links[-1]])) + request.write("</p>") + + def history(page, pagename, request): + # show history as default + _ = request.getText + + # open log for this page + from MoinMoin.util.dataset import TupleDataset, Column + + history = TupleDataset() + history.columns = [ + Column('rev', label='#', align='right'), + Column('mtime', label=_('Date'), align='right'), + Column('size', label=_('Size'), align='right'), + Column('diff', label='<input type="submit" value="%s">' % (_("Diff"))), + Column('editor', label=_('Editor'), hidden=not request.cfg.show_names), + Column('comment', label=_('Comment')), + Column('action', label=_('Action')), + ] + + # generate history list + revisions = page.getRevList() + versions = len(revisions) + + may_revert = request.user.may.revert(pagename) + + # read in the complete log of this page + log = editlog.EditLog(request, rootpagename=pagename) + count = 0 + for line in log.reverse(): + rev = int(line.rev) + actions = "" + if line.action in ['SAVE', 'SAVENEW', 'SAVE/REVERT', ]: + size = page.size(rev=rev) + if count == 0: # latest page + actions = '%s %s' % (actions, page.link_to(request, + text=_('view'), + querystr='')) + actions = '%s %s' % (actions, page.link_to(request, + text=_('raw'), + querystr='action=raw', rel='nofollow')) + actions = '%s %s' % (actions, page.link_to(request, + text=_('print'), + querystr='action=print', rel='nofollow')) + else: + actions = '%s %s' % (actions, page.link_to(request, + text=_('view'), + querystr='action=recall&rev=%d' % rev, rel='nofollow')) + actions = '%s %s' % (actions, page.link_to(request, + text=_('raw'), + querystr='action=raw&rev=%d' % rev, rel='nofollow')) + actions = '%s %s' % (actions, page.link_to(request, + text=_('print'), + querystr='action=print&rev=%d' % rev, rel='nofollow')) + if may_revert and size: # you can only revert to nonempty revisions + actions = '%s %s' % (actions, page.link_to(request, + text=_('revert'), + querystr='action=revert&rev=%d' % rev, rel='nofollow')) + if count == 0: + rchecked = ' checked="checked"' + lchecked = '' + elif count == 1: + lchecked = ' checked="checked"' + rchecked = '' + else: + lchecked = rchecked = '' + diff = '<input type="radio" name="rev1" value="%d"%s><input type="radio" name="rev2" value="%d"%s>' % (rev, lchecked, rev, rchecked) + comment = line.comment + if not comment and '/REVERT' in line.action: + comment = _("Revert to revision %(rev)d.") % {'rev': int(line.extra)} + else: # ATT* + rev = '-' + diff = '-' + + filename = wikiutil.url_unquote(line.extra) + comment = "%s: %s %s" % (line.action, filename, line.comment) + size = 0 + if line.action != 'ATTDEL': + from MoinMoin.action import AttachFile + page_dir = AttachFile.getAttachDir(request, pagename) + filepath = os.path.join(page_dir, filename) + try: + # FIXME, wrong path on non-std names + size = os.path.getsize(filepath) + except: + pass + if line.action == 'ATTNEW': + actions = '%s %s' % (actions, page.link_to(request, + text=_('view'), + querystr='action=AttachFile&do=view&target=%s' % filename, rel='nofollow')) + elif line.action == 'ATTDRW': + actions = '%s %s' % (actions, page.link_to(request, + text=_('edit'), + querystr='action=AttachFile&drawing=%s' % filename.replace(".draw", ""), rel='nofollow')) + + actions = '%s %s' % (actions, page.link_to(request, + text=_('get'), + querystr='action=AttachFile&do=get&target=%s' % filename, rel='nofollow')) + actions = '%s %s' % (actions, page.link_to(request, + text=_('del'), + querystr='action=AttachFile&do=del&target=%s' % filename, rel='nofollow')) + # XXX use?: wikiutil.escape(filename) + + history.addRow(( + rev, + request.user.getFormattedDateTime(wikiutil.version2timestamp(line.ed_time_usecs)), + str(size), + diff, + line.getEditor(request) or _("N/A"), + wikiutil.escape(comment) or ' ', + actions, + )) + count += 1 + if count >= 100: + break + + # print version history + from MoinMoin.widget.browser import DataBrowserWidget + + request.write('<h2>%s</h2>\n' % _('Revision History')) + + if not count: # there was no entry in logfile + request.write(_('No log entries found.')) + return + + # TODO: this form activates revert, which should use POST, but + # other actions should use get. Maybe we should put the revert + # into the page view itself, and not in this form. + request.write('<form method="GET" action="">\n') + request.write('<div id="page-history">\n') + request.write('<input type="hidden" name="action" value="diff">\n') + + history_table = DataBrowserWidget(request) + history_table.setData(history) + history_table.render() + request.write('</div>\n') + request.write('</form>\n') + + # main function + _ = request.getText + page = Page(request, pagename) + qpagename = wikiutil.quoteWikinameURL(pagename) + title = page.split_title(request) + + request.http_headers() + + # This action uses page or wiki language TODO: currently + # page.language is broken and not available now, when we fix it, + # this will be automatically fixed. + lang = page.language or request.cfg.language_default + request.setContentLanguage(lang) + + request.theme.send_title(_('Info for "%s"') % (title,), pagename=pagename) + menu_items = [ + (_('Show "%(title)s"') % {'title': _('Revision History')}, + {'action': 'info'}), + (_('Show "%(title)s"') % {'title': _('General Page Infos')}, + {'action': 'info', 'general': '1'}), + (_('Show "%(title)s"') % {'title': _('Page hits and edits')}, + {'action': 'info', 'hitcounts': '1'}), + ] + request.write('<div id="content">\n') # start content div + request.write("<p>") + for text, querystr in menu_items: + request.write("[%s] " % page.link_to(request, text=text, querystr=querystr, rel='nofollow')) + request.write("</p>") + + show_hitcounts = int(request.form.get('hitcounts', [0])[0]) != 0 + show_general = int(request.form.get('general', [0])[0]) != 0 + + if show_hitcounts: + from MoinMoin.stats import hitcounts + request.write(hitcounts.linkto(pagename, request, 'page=' + wikiutil.url_quote_plus(pagename))) + elif show_general: + general(page, pagename, request) + else: + history(page, pagename, request) + + request.write('</div>\n') # end content div + request.theme.send_footer(pagename) + request.theme.send_closing_html() +
--- a/MoinMoin/config.py Sat Jul 22 13:38:15 2006 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - site-wide configuration defaults (NOT per single wiki!) - - @copyright: 2005-2006 by Thomas Waldmann (MoinMoin:ThomasWaldmann) - @license: GNU GPL, see COPYING for details. -""" -import re - -# Threads flag - if you write a moin server that use threads, import -# config in the server and set this flag to True. -use_threads = False - -# Charset - we support only 'utf-8'. While older encodings might work, -# we don't have the resources to test them, and there is no real -# benefit for the user. IMPORTANT: use only lowercase 'utf-8'! -charset = 'utf-8' - -# Invalid characters - invisible characters that should not be in page -# names. Prevent user confusion and wiki abuse, e.g u'\u202aFrontPage'. -page_invalid_chars_regex = re.compile( - ur""" - \u0000 | # NULL - - # Bidi control characters - \u202A | # LRE - \u202B | # RLE - \u202C | # PDF - \u202D | # LRM - \u202E # RLM - """, - re.UNICODE | re.VERBOSE - ) - -# Other stuff -umask = 0770 -url_schemas = [] - -smileys = (r"X-( :D <:( :o :( :) B) :)) ;) /!\ <!> (!) :-? :\ >:> |) " + - r":-( :-) B-) :-)) ;-) |-) (./) {OK} {X} {i} {1} {2} {3} {*} {o}").split() - -# unicode: set the char types (upper, lower, digits, spaces) -from MoinMoin.util.chartypes import _chartypes -for key, val in _chartypes.items(): - if not vars().has_key(key): - vars()[key] = val - -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/config/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,50 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - site-wide configuration defaults (NOT per single wiki!) + + @copyright: 2005-2006 by Thomas Waldmann (MoinMoin:ThomasWaldmann) + @license: GNU GPL, see COPYING for details. +""" +import re + +# Threads flag - if you write a moin server that use threads, import +# config in the server and set this flag to True. +use_threads = False + +# Charset - we support only 'utf-8'. While older encodings might work, +# we don't have the resources to test them, and there is no real +# benefit for the user. IMPORTANT: use only lowercase 'utf-8'! +charset = 'utf-8' + +# When creating files, we use e.g. 0666 & config.umask for the mode: +umask = 0770 + +# Invalid characters - invisible characters that should not be in page +# names. Prevent user confusion and wiki abuse, e.g u'\u202aFrontPage'. +page_invalid_chars_regex = re.compile( + ur""" + \u0000 | # NULL + + # Bidi control characters + \u202A | # LRE + \u202B | # RLE + \u202C | # PDF + \u202D | # LRM + \u202E # RLM + """, + re.UNICODE | re.VERBOSE + ) + +# Other stuff +url_schemas = [] + +smileys = (r"X-( :D <:( :o :( :) B) :)) ;) /!\ <!> (!) :-? :\ >:> |) " + + r":-( :-) B-) :-)) ;-) |-) (./) {OK} {X} {i} {1} {2} {3} {*} {o}").split() + +# unicode: set the char types (upper, lower, digits, spaces) +from MoinMoin.util.chartypes import _chartypes +for key, val in _chartypes.items(): + if not vars().has_key(key): + vars()[key] = val + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/config/multiconfig.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,716 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - Multiple configuration handler and Configuration defaults class + + @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>, + 2005-2006 by MoinMoin:ThomasWaldmann. + @license: GNU GPL, see COPYING for details. +""" + +import re, os, sys +from MoinMoin import error +import MoinMoin.auth as authmodule + +_url_re_cache = None +_farmconfig_mtime = None +_config_cache = {} + + +def _importConfigModule(name): + """ Import and return configuration module and its modification time + + Handle all errors except ImportError, because missing file is not + always an error. + + @param name: module name + @rtype: tuple + @return: module, modification time + """ + try: + module = __import__(name, globals(), {}) + mtime = os.path.getmtime(module.__file__) + except ImportError: + raise + except IndentationError, err: + msg = '''IndentationError: %(err)s + +The configuration files are python modules. Therefore, whitespace is +important. Make sure that you use only spaces, no tabs are allowed here! +You have to use four spaces at the beginning of the line mostly. +''' % { + 'err': err, +} + raise error.ConfigurationError(msg) + except Exception, err: + msg = '%s: %s' % (err.__class__.__name__, str(err)) + raise error.ConfigurationError(msg) + return module, mtime + + +def _url_re_list(): + """ Return url matching regular expression + + Import wikis list from farmconfig on the first call and compile the + regexes. Later then return the cached regex list. + + @rtype: list of tuples of (name, compiled re object) + @return: url to wiki config name matching list + """ + global _url_re_cache, _farmconfig_mtime + if _url_re_cache is None: + try: + farmconfig, _farmconfig_mtime = _importConfigModule('farmconfig') + except ImportError: + # Default to wikiconfig for all urls. + _farmconfig_mtime = 0 + _url_re_cache = [('wikiconfig', re.compile(r'.')), ] # matches everything + else: + try: + cache = [] + for name, regex in farmconfig.wikis: + cache.append((name, re.compile(regex))) + _url_re_cache = cache + except AttributeError: + msg = """ +Missing required 'wikis' list in 'farmconfig.py'. + +If you run a single wiki you do not need farmconfig.py. Delete it and +use wikiconfig.py. +""" + raise error.ConfigurationError(msg) + return _url_re_cache + + +def _makeConfig(name): + """ Create and return a config instance + + Timestamp config with either module mtime or farmconfig mtime. This + mtime can be used later to invalidate older caches. + + @param name: module name + @rtype: DefaultConfig sub class instance + @return: new configuration instance + """ + global _farmconfig_mtime + try: + module, mtime = _importConfigModule(name) + configClass = getattr(module, 'Config') + cfg = configClass(name) + cfg.cfg_mtime = max(mtime, _farmconfig_mtime) + except ImportError, err: + msg = '''ImportError: %(err)s + +Check that the file is in the same directory as the server script. If +it is not, you must add the path of the directory where the file is +located to the python path in the server script. See the comments at +the top of the server script. + +Check that the configuration file name is either "wikiconfig.py" or the +module name specified in the wikis list in farmconfig.py. Note that the +module name does not include the ".py" suffix. +''' % { + 'err': err, +} + raise error.ConfigurationError(msg) + except AttributeError, err: + msg = '''AttributeError: %(err)s + +Could not find required "Config" class in "%(name)s.py". + +This might happen if you are trying to use a pre 1.3 configuration file, or +made a syntax or spelling error. + +Another reason for this could be a name clash. It is not possible to have +config names like e.g. stats.py - because that colides with MoinMoin/stats/ - +have a look into your MoinMoin code directory what other names are NOT +possible. + +Please check your configuration file. As an example for correct syntax, +use the wikiconfig.py file from the distribution. +''' % { + 'name': name, + 'err': err, +} + raise error.ConfigurationError(msg) + return cfg + + +def _getConfigName(url): + """ Return config name for url or raise """ + for name, regex in _url_re_list(): + match = regex.match(url) + if match: + return name + # nothing matched + msg = ''' +Could not find a match for url: "%(url)s". + +Check your URL regular expressions in the "wikis" list in +"farmconfig.py". +''' % { + 'url': url, +} + raise error.ConfigurationError(msg) + + +def getConfig(url): + """ Return cached config instance for url or create new one + + If called by many threads in the same time multiple config + instances might be created. The first created item will be + returned, using dict.setdefault. + + @param url: the url from request, possibly matching specific wiki + @rtype: DefaultConfig subclass instance + @return: config object for specific wiki + """ + configName = _getConfigName(url) + try: + config = _config_cache[configName] + except KeyError: + config = _makeConfig(configName) + config = _config_cache.setdefault(configName, config) + return config + + +# This is a way to mark some text for the gettext tools so that they don't +# get orphaned. See http://www.python.org/doc/current/lib/node278.html. +def _(text): return text + + +class DefaultConfig: + """ default config values """ + + # All acl_rights_* lines must use unicode! + acl_rights_default = u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write" + acl_rights_before = u"" + acl_rights_after = u"" + acl_rights_valid = ['read', 'write', 'delete', 'revert', 'admin'] + + actions_excluded = [] # ['DeletePage', 'AttachFile', 'RenamePage', 'test', ] + allow_xslt = 0 + attachments = None # {'dir': path, 'url': url-prefix} + auth = [authmodule.moin_login, authmodule.moin_session, ] + + backup_compression = 'gz' + backup_users = [] + backup_include = [] + backup_exclude = [ + r"(.+\.py(c|o)$)", + r"%(cache_dir)s", + r"%(/)spages%(/)s.+%(/)scache%(/)s[^%(/)s]+$" % {'/': os.sep}, + r"%(/)s(edit-lock|event-log|\.DS_Store)$" % {'/': os.sep}, + ] + backup_storage_dir = '/tmp' + backup_restore_target_dir = '/tmp' + + bang_meta = 1 + caching_formats = ['text_html'] + changed_time_fmt = '%H:%M' + + # chars_{upper,lower,digits,spaces} see MoinMoin/util/chartypes.py + + # if you have gdchart, add something like + # chart_options = {'width = 720, 'height': 540} + chart_options = None + + config_check_enabled = 0 + + cookie_domain = None # use '.domain.tld" for a farm with hosts in that domain + cookie_path = None # use '/wikifarm" for a farm with pathes below that path + cookie_lifetime = 12 # 12 hours from now + cookie_secret = '1234' # secret value for crypting session cookie - you should change this :) + + data_dir = './data/' + data_underlay_dir = './underlay/' + + date_fmt = '%Y-%m-%d' + datetime_fmt = '%Y-%m-%d %H:%M:%S' + + default_markup = 'wiki' + docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/" # correct for debian sarge + + editor_default = 'text' # which editor is called when nothing is specified + editor_ui = 'freechoice' # which editor links are shown on user interface + editor_force = False + editor_quickhelp = {# editor markup hints quickhelp + 'wiki': _("""\ + Emphasis:: [[Verbatim('')]]''italics''[[Verbatim('')]]; [[Verbatim(''')]]'''bold'''[[Verbatim(''')]]; [[Verbatim(''''')]]'''''bold italics'''''[[Verbatim(''''')]]; [[Verbatim('')]]''mixed ''[[Verbatim(''')]]'''''bold'''[[Verbatim(''')]] and italics''[[Verbatim('')]]; [[Verbatim(----)]] horizontal rule. + Headings:: [[Verbatim(=)]] Title 1 [[Verbatim(=)]]; [[Verbatim(==)]] Title 2 [[Verbatim(==)]]; [[Verbatim(===)]] Title 3 [[Verbatim(===)]]; [[Verbatim(====)]] Title 4 [[Verbatim(====)]]; [[Verbatim(=====)]] Title 5 [[Verbatim(=====)]]. + Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents. + Links:: [[Verbatim(JoinCapitalizedWords)]]; [[Verbatim(["brackets and double quotes"])]]; url; [url]; [url label]. + Tables:: || cell text |||| cell text spanning 2 columns ||; no trailing white space allowed after tables or titles. + +(!) For more help, see HelpOnEditing or SyntaxReference. +"""), + 'rst': _("""\ +Emphasis: <i>*italic*</i> <b>**bold**</b> ``monospace``<br/> +<br/><pre> +Headings: Heading 1 Heading 2 Heading 3 + ========= --------- ~~~~~~~~~ + +Horizontal rule: ---- +Links: TrailingUnderscore_ `multi word with backticks`_ external_ + +.. _external: http://external-site.net/foo/ + +Lists: * bullets; 1., a. numbered items. +</pre> +<br/> +(!) For more help, see the +<a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html"> +reStructuredText Quick Reference +</a>. +"""), + } + edit_locking = 'warn 10' # None, 'warn <timeout mins>', 'lock <timeout mins>' + edit_rows = 20 + + hacks = {} # { 'feature1': value1, ... } + # Configuration for features still in development. + # For boolean stuff just use config like this: + # hacks = { 'feature': True, ...} + # and in the code use: + # if cfg.hacks.get('feature', False): <doit> + # A non-existing hack key should ever mean False, None, "", [] or {}! + + hosts_deny = [] + + html_head = '' + html_head_queries = '''<meta name="robots" content="noindex,nofollow">\n''' + html_head_posts = '''<meta name="robots" content="noindex,nofollow">\n''' + html_head_index = '''<meta name="robots" content="index,follow">\n''' + html_head_normal = '''<meta name="robots" content="index,nofollow">\n''' + html_pagetitle = None + + interwiki_preferred = [] # list of wiki names to show at top of interwiki list + + language_default = 'en' + language_ignore_browser = False # ignore browser settings, use language_default + # or user prefs + + log_reverse_dns_lookups = True # if we do reverse dns lookups for logging hostnames + # instead of just IPs + + xapian_search = False # disabled until xapian is finished + xapian_index_dir = None + xapian_stemming = True + + mail_login = None # or "user pwd" if you need to use SMTP AUTH + mail_sendmail = None # "/usr/sbin/sendmail -t -i" to not use SMTP, but sendmail + mail_smarthost = None + mail_from = None # u'Juergen Wiki <noreply@jhwiki.org>' + + mail_import_subpage_template = u"$from-$date-$subject" # used for mail import + mail_import_wiki_address = None # the e-mail address for e-mails that should go into the wiki + mail_import_secret = "" + + navi_bar = [u'RecentChanges', u'FindPage', u'HelpContents', ] + nonexist_qm = 0 + + page_credits = [ + '<a href="http://moinmoin.wikiwikiweb.de/">MoinMoin Powered</a>', + '<a href="http://www.python.org/">Python Powered</a>', + '<a href="http://validator.w3.org/check?uri=referer">Valid HTML 4.01</a>', + ] + page_footer1 = '' + page_footer2 = '' + + page_header1 = '' + page_header2 = '' + + page_front_page = u'HelpOnLanguages' # this will make people choose a sane config + page_local_spelling_words = u'LocalSpellingWords' + page_category_regex = u'^Category[A-Z]' + page_dict_regex = u'[a-z0-9]Dict$' + page_group_regex = u'[a-z0-9]Group$' + page_template_regex = u'[a-z0-9]Template$' + + page_license_enabled = 0 + page_license_page = u'WikiLicense' + + # These icons will show in this order in the iconbar, unless they + # are not relevant, e.g email icon when the wiki is not configured + # for email. + page_iconbar = ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ] + + # Standard buttons in the iconbar + page_icons_table = { + # key last part of url, title, icon-key + 'help': ("%(q_page_help_contents)s", "%(page_help_contents)s", "help"), + 'find': ("%(q_page_find_page)s?value=%(q_page_name)s", "%(page_find_page)s", "find"), + 'diff': ("%(q_page_name)s?action=diff", _("Diffs"), "diff"), + 'info': ("%(q_page_name)s?action=info", _("Info"), "info"), + 'edit': ("%(q_page_name)s?action=edit", _("Edit"), "edit"), + 'unsubscribe': ("%(q_page_name)s?action=subscribe", _("UnSubscribe"), "unsubscribe"), + 'subscribe': ("%(q_page_name)s?action=subscribe", _("Subscribe"), "subscribe"), + 'raw': ("%(q_page_name)s?action=raw", _("Raw"), "raw"), + 'xml': ("%(q_page_name)s?action=show&mimetype=text/xml", _("XML"), "xml"), + 'print': ("%(q_page_name)s?action=print", _("Print"), "print"), + 'view': ("%(q_page_name)s", _("View"), "view"), + 'up': ("%(q_page_parent_page)s", _("Up"), "up"), + } + + refresh = None # (minimum_delay, type), e.g.: (2, 'internal') + rss_cache = 60 # suggested caching time for RecentChanges RSS, in seconds + shared_intermap = None # can be string or list of strings (filenames) + show_hosts = 1 + show_interwiki = 0 + show_login = 1 + show_names = True + show_section_numbers = 0 + show_timings = 0 + show_version = 0 + siteid = 'default' + stylesheets = [] # list of tuples (media, csshref) to insert after theme css, before user css + superuser = [] # list of unicode user names that have super powers :) + + surge_action_limits = {# allow max. <count> <action> requests per <dt> secs + # action: (count, dt) + 'all': (30, 30), + 'show': (30, 60), + 'recall': (5, 60), + 'raw': (20, 40), # some people use this for css + 'AttachFile': (90, 60), + 'diff': (30, 60), + 'fullsearch': (5, 60), + 'edit': (10, 120), + 'rss_rc': (1, 60), + 'default': (30, 60), + } + surge_lockout_time = 3600 # secs you get locked out when you ignore warnings + + theme_default = 'modern' + theme_force = False + + trail_size = 5 + tz_offset = 0.0 # default time zone offset in hours from UTC + + user_autocreate = False # do we auto-create user profiles + user_email_unique = True # do we check whether a user's email is unique? + + # a regex of HTTP_USER_AGENTS that should be excluded from logging + # and receive a FORBIDDEN for anything except viewing a page + ua_spiders = ('archiver|cfetch|crawler|curl|gigabot|googlebot|holmes|htdig|httrack|httpunit|jeeves|larbin|leech|' + 'linkbot|linkmap|linkwalk|mercator|mirror|msnbot|nutbot|omniexplorer|puf|robot|scooter|' + 'sherlock|slurp|sitecheck|spider|teleport|voyager|webreaper|wget') + + # Wiki identity + sitename = u'Untitled Wiki' + url_prefix = '/wiki' + logo_string = None + interwikiname = None + + url_mappings = {} + + user_checkbox_fields = [ + ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')), + ('edit_on_doubleclick', lambda _: _('Open editor on double click')), + ('remember_last_visit', lambda _: _('After login, jump to last visited page')), + ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')), + ('show_page_trail', lambda _: _('Show page trail')), + ('show_toolbar', lambda _: _('Show icon toolbar')), + ('show_topbottom', lambda _: _('Show top/bottom links in headings')), + ('show_fancy_diff', lambda _: _('Show fancy diffs')), + ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')), + ('remember_me', lambda _: _('Remember login information')), + ('want_trivial', lambda _: _('Subscribe to trivial changes')), + + ('disabled', lambda _: _('Disable this account forever')), + # if an account is disabled, it may be used for looking up + # id -> username for page info and recent changes, but it + # is not usable for the user any more: + ] + + user_checkbox_defaults = {'mailto_author': 0, + 'edit_on_doubleclick': 0, + 'remember_last_visit': 0, + 'show_nonexist_qm': nonexist_qm, + 'show_page_trail': 1, + 'show_toolbar': 1, + 'show_topbottom': 0, + 'show_fancy_diff': 1, + 'wikiname_add_spaces': 0, + 'remember_me': 1, + 'want_trivial': 0, + } + + # don't let the user change those + # user_checkbox_disable = ['disabled', 'want_trivial'] + user_checkbox_disable = [] + + # remove those checkboxes: + #user_checkbox_remove = ['edit_on_doubleclick', 'show_nonexist_qm', 'show_toolbar', 'show_topbottom', + # 'show_fancy_diff', 'wikiname_add_spaces', 'remember_me', 'disabled',] + user_checkbox_remove = [] + + user_form_fields = [ + ('name', _('Name'), "text", "36", _("(Use Firstname''''''Lastname)")), + ('aliasname', _('Alias-Name'), "text", "36", ''), + ('password', _('Password'), "password", "36", ''), + ('password2', _('Password repeat'), "password", "36", _('(Only for password change or new account)')), + ('email', _('Email'), "text", "36", ''), + ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')), + ('edit_rows', _('Editor size'), "text", "3", ''), + ] + + user_form_defaults = {# key: default - do NOT remove keys from here! + 'name': '', + 'aliasname': '', + 'password': '', + 'password2': '', + 'email': '', + 'css_url': '', + 'edit_rows': "20", + } + + # don't let the user change those, but show them: + #user_form_disable = ['name', 'aliasname', 'email',] + user_form_disable = [] + + # remove those completely: + #user_form_remove = ['password', 'password2', 'css_url', 'logout', 'create', 'account_sendmail',] + user_form_remove = [] + + # attributes we do NOT save to the userpref file + user_transient_fields = ['id', 'valid', 'may', 'auth_username', 'trusted', 'password', 'password2', 'auth_method', 'auth_attribs', ] + + user_homewiki = 'Self' # interwiki name for where user homepages are located + + unzip_single_file_size = 2.0 * 1000**2 + unzip_attachments_space = 200.0 * 1000**2 + unzip_attachments_count = 51 # 1 zip file + 50 files contained in it + + xmlrpc_putpage_enabled = 0 # if 0, putpage will write to a test page only + xmlrpc_putpage_trusted_only = 1 # if 1, you will need to be http auth authenticated + + SecurityPolicy = None + + def __init__(self, siteid): + """ Init Config instance """ + self.siteid = siteid + if self.config_check_enabled: + self._config_check() + + # define directories + self.moinmoin_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) + data_dir = os.path.normpath(self.data_dir) + self.data_dir = data_dir + for dirname in ('user', 'cache', 'plugin'): + name = dirname + '_dir' + if not getattr(self, name, None): + setattr(self, name, os.path.join(data_dir, dirname)) + + # Try to decode certain names which allow unicode + self._decode() + + self._check_directories() + + if not isinstance(self.superuser, list): + msg = """The superuser setting in your wiki configuration is not a list + (e.g. ['Sample User', 'AnotherUser']). + Please change it in your wiki configuration and try again.""" + raise error.ConfigurationError(msg) + + self._loadPluginModule() + + # Preparse user dicts + self._fillDicts() + + # Normalize values + self.language_default = self.language_default.lower() + + # Use site name as default name-logo + if self.logo_string is None: + self.logo_string = self.sitename + + # Check for needed modules + + # FIXME: maybe we should do this check later, just before a + # chart is needed, maybe in the chart module, instead doing it + # for each request. But this require a large refactoring of + # current code. + if self.chart_options: + try: + import gdchart + except ImportError: + self.chart_options = None + + # post process + # we replace any string placeholders with config values + # e.g u'%(page_front_page)s' % self + self.navi_bar = [elem % self for elem in self.navi_bar] + self.backup_exclude = [elem % self for elem in self.backup_exclude] + + # list to cache xapian searcher objects + self.xapian_searchers = [] + + # check if mail is possible and set flag: + self.mail_enabled = (self.mail_smarthost is not None or self.mail_sendmail is not None) and self.mail_from + + def _config_check(self): + """ Check namespace and warn about unknown names + + Warn about names which are not used by DefaultConfig, except + modules, classes, _private or __magic__ names. + + This check is disabled by default, when enabled, it will show an + error message with unknown names. + """ + unknown = ['"%s"' % name for name in dir(self) + if not name.startswith('_') and + not DefaultConfig.__dict__.has_key(name) and + not isinstance(getattr(self, name), (type(sys), type(DefaultConfig)))] + if unknown: + msg = """ +Unknown configuration options: %s. + +For more information, visit HelpOnConfiguration. Please check your +configuration for typos before requesting support or reporting a bug. +""" % ', '.join(unknown) + raise error.ConfigurationError(msg) + + def _decode(self): + """ Try to decode certain names, ignore unicode values + + Try to decode str using utf-8. If the decode fail, raise FatalError. + + Certain config variables should contain unicode values, and + should be defined with u'text' syntax. Python decode these if + the file have a 'coding' line. + + This will allow utf-8 users to use simple strings using, without + using u'string'. Other users will have to use u'string' for + these names, because we don't know what is the charset of the + config files. + """ + charset = 'utf-8' + message = u''' +"%(name)s" configuration variable is a string, but should be +unicode. Use %(name)s = u"value" syntax for unicode variables. + +Also check your "-*- coding -*-" line at the top of your configuration +file. It should match the actual charset of the configuration file. +''' + + decode_names = ( + 'sitename', 'logo_string', 'navi_bar', 'page_front_page', + 'page_category_regex', 'page_dict_regex', + 'page_group_regex', 'page_template_regex', 'page_license_page', + 'page_local_spelling_words', 'acl_rights_default', + 'acl_rights_before', 'acl_rights_after', 'mail_from' + ) + + for name in decode_names: + attr = getattr(self, name, None) + if attr: + # Try to decode strings + if isinstance(attr, str): + try: + setattr(self, name, unicode(attr, charset)) + except UnicodeError: + raise error.ConfigurationError(message % + {'name': name}) + # Look into lists and try to decode strings inside them + elif isinstance(attr, list): + for i in xrange(len(attr)): + item = attr[i] + if isinstance(item, str): + try: + attr[i] = unicode(item, charset) + except UnicodeError: + raise error.ConfigurationError(message % + {'name': name}) + + def _check_directories(self): + """ Make sure directories are accessible + + Both data and underlay should exists and allow read, write and + execute. + """ + mode = os.F_OK | os.R_OK | os.W_OK | os.X_OK + for attr in ('data_dir', 'data_underlay_dir'): + path = getattr(self, attr) + + # allow an empty underlay path or None + if attr == 'data_underlay_dir' and not path: + continue + + path_pages = os.path.join(path, "pages") + if not (os.path.isdir(path_pages) and os.access(path_pages, mode)): + msg = ''' +%(attr)s "%(path)s" does not exists, or has incorrect ownership or +permissions. + +Make sure the directory and the subdirectory pages are owned by the web +server and are readable, writable and executable by the web server user +and group. + +It is recommended to use absolute paths and not relative paths. Check +also the spelling of the directory name. +''' % {'attr': attr, 'path': path, } + raise error.ConfigurationError(msg) + + def _loadPluginModule(self): + """ import plugin module under configname.plugin + + To be able to import plugin from arbitrary path, we have to load + the base package once using imp.load_module. Later, we can use + standard __import__ call to load plugins in this package. + + Since each wiki has unique plugins, we load the plugin package + under the wiki configuration module, named self.siteid. + """ + import sys, imp + + name = self.siteid + '.plugin' + try: + # Lock other threads while we check and import + imp.acquire_lock() + try: + # If the module is not loaded, try to load it + if not name in sys.modules: + # Find module on disk and try to load - slow! + plugin_parent_dir = os.path.abspath(os.path.join(self.plugin_dir, '..')) + fp, path, info = imp.find_module('plugin', [plugin_parent_dir]) + try: + # Load the module and set in sys.modules + module = imp.load_module(name, fp, path, info) + sys.modules[self.siteid].plugin = module + finally: + # Make sure fp is closed properly + if fp: + fp.close() + finally: + imp.release_lock() + except ImportError, err: + msg = ''' +Could not import plugin package "%(path)s/plugin" because of ImportError: +%(err)s. + +Make sure your data directory path is correct, check permissions, and +that the data/plugin directory has an __init__.py file. +''' % { + 'path': self.data_dir, + 'err': str(err), +} + raise error.ConfigurationError(msg) + + def _fillDicts(self): + """ fill config dicts + + Fills in missing dict keys of derived user config by copying + them from this base class. + """ + # user checkbox defaults + for key, value in DefaultConfig.user_checkbox_defaults.items(): + if not self.user_checkbox_defaults.has_key(key): + self.user_checkbox_defaults[key] = value + + def __getitem__(self, item): + """ Make it possible to access a config object like a dict """ + return getattr(self, item) + +# remove the gettext pseudo function +del _ +
--- a/MoinMoin/converter/text_html_text_moin_wiki.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/converter/text_html_text_moin_wiki.py Mon Jul 24 22:18:49 2006 +0200 @@ -407,7 +407,7 @@ class ConvertError(error.FatalError): """ Raise when html to wiki conversion fails """ name = "MoinMoin Convert Error" - + class visitor(object): def do(self, tree): @@ -434,7 +434,7 @@ def visit_attribute(self, node): pass - + def visit_text(self, node): pass @@ -469,7 +469,7 @@ def __init__(self, request, pagename): self.request = request self.pagename = pagename - + def do(self, tree): self.depth = 0 self.text = [] @@ -520,7 +520,7 @@ name = node.localName if name is None: # not sure this can happen here (DOM comment node), but just for the case return - func = getattr(self, "process_%s" % name, None) + func = getattr(self, "process_%s" % name, None) if func: func(node) else: @@ -565,7 +565,7 @@ self.text.append(self.new_line) self.text.append("%s %s %s" % (hstr, text.replace("\n", " "), hstr)) self.text.append(self.new_line) - + process_h1 = process_heading process_h2 = process_heading process_h3 = process_heading @@ -593,7 +593,7 @@ if class_ == "gap": before = "\n" style = listitem.getAttribute("style") - if re.match(u"list-style-type:\s*none", style, re.I): + if re.match(ur"list-style-type:\s*none", style, re.I): markup = ". " else: markup = "* " @@ -666,7 +666,7 @@ if name in ('p', 'pre', 'ol', 'ul', 'dl', 'table',) and pending: self.empty_paragraph_queue(pending, indent, need_indent) need_indent = True - + if name == 'p': if need_indent: self.text.append(indent) @@ -737,7 +737,7 @@ def process_inline(self, node): if node.nodeType == Node.TEXT_NODE: - self.text.append(node.data.strip('\n').replace('\n',' ')) + self.text.append(node.data.strip('\n').replace('\n', ' ')) return name = node.localName # can be None for DOM Comment nodes @@ -748,8 +748,8 @@ text = self.node_list_text_only(node.childNodes).strip() # but can be inserted via the editor self.text.append(text) # so we just drop the header markup and keep the text return - - func = getattr(self, "process_%s" % name, None) + + func = getattr(self, "process_%s" % name, None) if func: func(node) return @@ -778,13 +778,13 @@ command = "" # just throw away font settings else: raise ConvertError("process_inline: Don't support %s element" % name) - + self.text.append(command) for i in node.childNodes: if i.nodeType == Node.ELEMENT_NODE: self.process_inline(i) elif i.nodeType == Node.TEXT_NODE: - self.text.append(i.data.strip('\n').replace('\n',' ')) + self.text.append(i.data.strip('\n').replace('\n', ' ')) if command_close: command = command_close self.text.append(command) @@ -865,11 +865,11 @@ #print i.localName self.text.extend(["}}}", self.new_line]) - _alignment = {"left" : "(", - "center" : ":", - "right" : ")", - "top" : "^", - "bottom" : "v"} + _alignment = {"left": "(", + "center": ":", + "right": ")", + "top": "^", + "bottom": "v"} def _check_length(self, value): try: @@ -933,7 +933,7 @@ colspan = 1 spanning = rowspan or colspan > 1 - + align = "" result = [] if node.hasAttribute("bgcolor"): @@ -970,7 +970,7 @@ result.append('id="%s"' % node.getAttribute("id")) if node.hasAttribute("style"): result.append('style="%s"' % node.getAttribute("style")) - + if align: result.insert(0, "%s" % align) result.append(rowspan) @@ -1049,7 +1049,7 @@ self.process_inline(i) found = True elif i.nodeType == Node.TEXT_NODE: - data = i.data.strip('\n').replace('\n',' ') + data = i.data.strip('\n').replace('\n', ' ') if data: found = True self.text.append(data) @@ -1083,7 +1083,7 @@ id = node.attributes.get("id", None) if id: id = id.nodeValue - + if href: title = class_ = interwikiname = None @@ -1102,14 +1102,14 @@ if not err and href.startswith(wikiurl): pagename, qpagename = pagename_from_url(href[len(wikiurl):].lstrip('/')) interwikiname = "%s:%s" % (wikitag, qpagename) - else: + else: raise ConvertError("Invalid InterWiki link: '%s'" % href) elif class_ == "badinterwiki" and title: if href == "/": # we used this as replacement for empty href href = "" pagename, qpagename = pagename_from_url(href) interwikiname = "%s:%s" % (title, qpagename) - if interwikiname and pagename == text: + if interwikiname and pagename == text: self.text.append("%s" % interwikiname) return elif title == 'Self': @@ -1118,7 +1118,7 @@ elif interwikiname: self.text.append("[wiki:%s %s]" % (interwikiname, text)) return - + # fix links generated by a broken copy & paste of gecko based browsers brokenness = '../../../..' if href.startswith(brokenness):
--- a/MoinMoin/filter/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/filter/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -12,7 +12,7 @@ filters = pysupport.getPackageModules(__file__) modules = filters -standard_codings = ['utf-8', 'iso-8859-15', 'iso-8859-1',] +standard_codings = ['utf-8', 'iso-8859-15', 'iso-8859-1', ] def execfilter(cmd, filename, codings=standard_codings): """ use cmd to get plaintext content of filename
--- a/MoinMoin/filter/application_octet_stream.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/filter/application_octet_stream.py Mon Jul 24 22:18:49 2006 +0200 @@ -36,7 +36,7 @@ norm = string.maketrans('', '') # builds a list of all non-alphanumeric characters: -non_alnum = string.translate(norm, norm, string.letters+string.digits) +non_alnum = string.translate(norm, norm, string.letters+string.digits) # translate table that replaces all non-alphanumeric by blanks: trans_nontext = string.maketrans(non_alnum, ' '*len(non_alnum))
--- a/MoinMoin/filter/text.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/filter/text.py Mon Jul 24 22:18:49 2006 +0200 @@ -24,5 +24,4 @@ f.close() data = data.decode('ascii', 'replace') return data -
--- a/MoinMoin/formatter/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -60,7 +60,7 @@ return "" # Document Level ##################################################### - + def startDocument(self, pagename): return "" @@ -74,13 +74,13 @@ return "" # Links ############################################################## - + def pagelink(self, on, pagename='', page=None, **kw): """ make a link to page <pagename>. Instead of supplying a pagename, it is also possible to give a live Page object, then page.page_name will be used. """ - if not self._store_pagelinks or not on or kw.get('generated'): + if not self._store_pagelinks or not on or kw.get('generated'): return '' if not pagename and page: pagename = page.page_name @@ -101,7 +101,7 @@ wikitail = wikiutil.url_unquote(wikitail) return self.pagelink(on, wikitail, **kw) return '' - + def url(self, on, url=None, css=None, **kw): raise NotImplementedError @@ -171,11 +171,11 @@ return self.text(text) # Text and Text Attributes ########################################### - + def text(self, text, **kw): if not self._highlight_re: return self._text(text) - + result = [] lastpos = 0 match = self._highlight_re.search(text) @@ -278,7 +278,7 @@ raise NotImplementedError # Tables ############################################################# - + def table(self, on, attrs={}, **kw): raise NotImplementedError @@ -289,10 +289,10 @@ raise NotImplementedError # Dynamic stuff / Plugins ############################################ - + def macro(self, macro_obj, name, args): # call the macro - return macro_obj.execute(name, args) + return macro_obj.execute(name, args) def _get_bang_args(self, line): if line[:2] == '#!': @@ -326,15 +326,15 @@ return '' # Other ############################################################## - + def div(self, on, **kw): """ open/close a blocklevel division """ return "" - + def span(self, on, **kw): """ open/close a inline span """ return "" - + def rawHTML(self, markup): """ This allows emitting pre-formatted HTML markup, and should be used wisely (i.e. very seldom).
--- a/MoinMoin/formatter/dom_xml.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/dom_xml.py Mon Jul 24 22:18:49 2006 +0200 @@ -57,7 +57,7 @@ 'ol': ['li'], 'ul': ['li'], } - + # FIXME - this overrides the values defined above - FIXME XXX close_on_open = {} close_on_close = {} @@ -69,7 +69,7 @@ self.document.documentElement = self.document.createElement('xml') self.position = self.document.documentElement self.tag_stack = [('xml', {})] - + def setPage(self, page): self.page = page @@ -110,7 +110,7 @@ for name, value in attrs.items(): if value: node.setAttribute(name, str(value)) - self.position.appendChild(node) + self.position.appendChild(node) return '' def _text(self, text): @@ -195,13 +195,13 @@ if not pagename and page is not None: pagename = page.page_name kw['pagename'] = pagename - return self._set_tag('pagelink', on, **kw) + return self._set_tag('pagelink', on, **kw) def interwikilink(self, on, interwiki='', pagename='', **kw): kw['wiki'] = interwiki kw['pagename'] = pagename return self._set_tag('interwiki', on, **kw) - + def macro(self, macro_obj, name, args): # call the macro return self._add_tag('macro', name=name, args=(args or '')) @@ -227,17 +227,17 @@ kw['href'] = url kw['type'] = 'link' return self._set_tag('attachment', 1, **kw) + self.text(text) + self._set_tag('attachment', 0, **kw) - + def attachment_image(self, url, **kw): kw['href'] = url kw['type'] = 'image' return self._add_tag('attachment', **kw) - + def attachment_drawing(self, url, **kw): kw['href'] = url kw['type'] = 'drawing' return self._add_tag('attachment', **kw) - + def attachment_inlined(self, url, **kw): kw['href'] = url kw['type'] = 'inline' @@ -295,7 +295,7 @@ return self.text('\n') else: return self._add_tag('br') - + def heading(self, on, depth, **kw): return self._set_tag('h%d' %depth, on, **kw) @@ -307,7 +307,7 @@ def table(self, on, attrs={}, **kw): return self._set_tag('table', on, **self._check_attrs(attrs)) - + def table_row(self, on, attrs={}, **kw): return self._set_tag('tr', on, **self._check_attrs(attrs)) @@ -338,7 +338,7 @@ if compact and on: return self._set_tag('dt compact', on) else: - return self._set_tag('dt', on) + return self._set_tag('dt', on) def definition_desc(self, on, **kw): # self._langAttr() missing
--- a/MoinMoin/formatter/pagelinks.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/pagelinks.py Mon Jul 24 22:18:49 2006 +0200 @@ -9,19 +9,19 @@ from MoinMoin.formatter import FormatterBase class Formatter(FormatterBase): - """ Collect pagelinks and format nothing :-) """ - + """ Collect pagelinks and format nothing :-) """ + def pagelink(self, on, pagename='', page=None, **kw): FormatterBase.pagelink(self, on, pagename, page, **kw) return self.null() - + def null(self, *args, **kw): return '' - + # All these must be overriden here because they raise # NotImplementedError!@#! or return html?! in the base class. set_highlight_re = rawHTML = url = image = smiley = text = null - strong = emphasis = underline = highlight = sup = sub = strike = null + strong = emphasis = underline = highlight = sup = sub = strike = null code = preformatted = small = big = code_area = code_line = null code_token = linebreak = paragraph = rule = icon = null number_list = bullet_list = listitem = definition_list = null
--- a/MoinMoin/formatter/text_docbook.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_docbook.py Mon Jul 24 22:18:49 2006 +0200 @@ -30,15 +30,15 @@ """ Format docbook output """ - + def __init__(self, dommDoc): self.doc = dommDoc self.curNode = dommDoc.documentElement - + def setHeading(self, headNode): self.domHeadNode = headNode return u"" - + def _printNode(self, node): """ Function print a node @@ -46,15 +46,15 @@ from xml.dom.ext import Print import StringIO from xml.dom.ext import Printer - + stream = StringIO.StringIO() - + visitor = Printer.PrintVisitor(stream, 'UTF-8') Printer.PrintWalker(visitor, node).run() # get value from stream ret = stream.getvalue() stream.close() - + return unicode(ret, 'utf-8') def getHeading(self): @@ -63,7 +63,7 @@ # print article info return '<?xml version="1.0"?><%s>%s' % (rootNode.nodeName, self._printNode(self.domHeadNode)) - + def getBody(self): body = [] # print all nodes inside dom behind heading @@ -81,7 +81,7 @@ ret.append("</%s>" % (self.curNode.nodeName, )) self.curNode = self.curNode.parentNode return ''.join(ret) - + def getFooter(self): return "</%s>" % self.doc.documentElement.nodeName @@ -93,7 +93,7 @@ section_should_break = ['abstract', 'para', 'emphasis'] def __init__(self, request, **kw): - '''We should use this for creating the doc''' + """We should use this for creating the doc""" FormatterBase.__init__(self, request, **kw) self.doc = dom.createDocument(None, "article", dom.createDocumentType( @@ -113,7 +113,7 @@ self.root.appendChild(info) # set heading node self.outputFormatter.setHeading(info) - + return self.outputFormatter.getHeading() def startContent(self, content_id="content", **kw): @@ -138,7 +138,7 @@ else: srcText = text if self.cur.nodeName == "screen": - if self.cur.lastChild != None: + if self.cur.lastChild is not None: from xml.dom.ext import Node if self.cur.lastChild.nodeType == Node.CDATA_SECTION_NODE: self.cur.lastChild.nodeValue = self.cur.lastChild.nodeValue + srcText @@ -151,7 +151,7 @@ def heading(self, on, depth, **kw): while self.cur.nodeName in self.section_should_break: self.cur = self.cur.parentNode - + if on: # try to go to higher level if needed if depth <= self.curdepth: @@ -165,7 +165,7 @@ # I don't understand this code - looks like unnecessary -- maybe it is used to gain some vertical space for large headings? # if len(self.cur.childNodes) < 3: # self._addEmptyNode("para") - + # check if not top-level if self.cur.nodeName != "article": self.cur = self.cur.parentNode @@ -225,7 +225,7 @@ cols = 1 if attrs and attrs.has_key('colspan'): s1 = attrs['colspan'] - s1 = str(s1).replace('"','') + s1 = str(s1).replace('"', '') cols = int(s1) return cols @@ -270,16 +270,16 @@ return self._handleNode(name, on, attributes) def strong(self, on, **kw): - return self._handleFormatting("emphasis", on, (('role','strong'), )) + return self._handleFormatting("emphasis", on, (('role', 'strong'), )) def emphasis(self, on, **kw): return self._handleFormatting("emphasis", on) def underline(self, on, **kw): - return self._handleFormatting("emphasis", on, (('role','underline'), )) + return self._handleFormatting("emphasis", on, (('role', 'underline'), )) def highlight(self, on, **kw): - return self._handleFormatting("emphasis", on, (('role','highlight'), )) + return self._handleFormatting("emphasis", on, (('role', 'highlight'), )) def sup(self, on, **kw): return self._handleFormatting("superscript", on) @@ -291,7 +291,7 @@ # does not yield <strike> using the HTML XSLT files here ... # but seems to be correct return self._handleFormatting("emphasis", on, - (('role','strikethrough'), )) + (('role', 'strikethrough'), )) def code(self, on, **kw): return self._handleFormatting("code", on) @@ -303,8 +303,8 @@ ### Lists ########################################################### def number_list(self, on, type=None, start=None, **kw): - docbook_ol_types = {'1': "arabic", - 'a': "loweralpha", + docbook_ol_types = {'1': "arabic", + 'a': "loweralpha", 'A': "upperalpha", 'i': "lowerroman", 'I': "upperroman"} @@ -320,22 +320,22 @@ return self._handleNode("itemizedlist", on) def definition_list(self, on, **kw): - return self._handleNode("glosslist", on) + return self._handleNode("glosslist", on) def definition_term(self, on, compact=0, **kw): # When on is false, we back out just on level. This is # ok because we know definition_desc gets called, and we # back out two levels there. if on: - entry=self.doc.createElement('glossentry') - term=self.doc.createElement('glossterm') + entry = self.doc.createElement('glossentry') + term = self.doc.createElement('glossterm') entry.appendChild(term) self.cur.appendChild(entry) self.cur = term else: self.cur = self.cur.parentNode return "" - + def definition_desc(self, on, **kw): # We backout two levels when 'on' is false, to leave the glossentry stuff if on: @@ -365,14 +365,14 @@ # FIXME: This is even more crappy def interwikilink(self, on, interwiki='', pagename='', **kw): if not on: - return self.url(on,kw) + return self.url(on, kw) wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:"%s"' % (interwiki, pagename)) wikiurl = wikiutil.mapURL(self.request, wikiurl) href = wikiutil.join_wiki(wikiurl, wikitail) return self.url(on, href) - + def url(self, on, url=None, css=None, **kw): return self._handleNode("ulink", on, (('url', url), )) @@ -382,11 +382,11 @@ return "" def anchorlink(self, on, name='', **kw): - id = kw.get('id',None) + id = kw.get('id', None) attrs = [] if name != '': attrs.append(('endterm', name)) - if id != None: + if id is not None: attrs.append(('linkend', id)) elif name != '': attrs.append(('linkend', name)) @@ -463,14 +463,14 @@ break if title: txtcontainer = self.doc.createElement('textobject') - media.appendChild(txtcontainer) + media.appendChild(txtcontainer) txtphrase = self.doc.createElement('phrase') txtphrase.appendChild(self.doc.createTextNode(title)) - txtcontainer.appendChild(txtphrase) - + txtcontainer.appendChild(txtphrase) + self.cur.appendChild(media) - return "" - + return "" + def smiley(self, text): return self.request.theme.make_icon(text) @@ -492,7 +492,7 @@ self._handleNode("tgroup", on) self._handleNode("tbody", on) return "" - + def table_row(self, on, attrs=None, **kw): self.table_current_row_cells = 0 sanitized_attrs = [] @@ -526,12 +526,12 @@ show = show and 'numbered' or 'unnumbered' if start < 1: start = 1 - + attrs = (('id', code_id), ('linenumbering', show), ('startinglinenumber', str(start)), ('language', code_type), - ('format','linespecific'), + ('format', 'linespecific'), ) return self._handleFormatting("screen", on, attrs) @@ -578,7 +578,7 @@ ### Not supported ################################################### - def rule(self, size = 0, **kw): + def rule(self, size=0, **kw): return "" def small(self, on, **kw):
--- a/MoinMoin/formatter/text_gedit.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_gedit.py Mon Jul 24 22:18:49 2006 +0200 @@ -42,7 +42,7 @@ """ apply(FormatterBase.pagelink, (self, on, pagename, page), kw) if page is None: - page = Page(self.request, pagename, formatter=self); + page = Page(self.request, pagename, formatter=self) return page.link_to(self.request, on=on, **kw) def interwikilink(self, on, interwiki='', pagename='', **kw): @@ -69,7 +69,7 @@ return (self.url(1, target, title="attachment:%s" % wikiutil.quoteWikinameURL(url)) + self.text(text) + self.url(0)) - + def attachment_image(self, url, **kw): _ = self.request.getText pagename = self.page.page_name @@ -91,10 +91,10 @@ return '<span style="background-color:#ffff11">!</span>' + self.text(text) # Dynamic stuff / Plugins ############################################ - + def macro(self, macro_obj, name, args): if args is not None: - result = "[[%s(%s)]]" % (name, args) + result = "[[%s(%s)]]" % (name, args) else: result = "[[%s]]" % name return '<span style="background-color:#ffff11">%s</span>' % result @@ -182,7 +182,7 @@ # Close table then div result.append(self._close('table')) - return ''.join(result) + return ''.join(result) def comment(self, text, **kw): text = text.rstrip() # workaround for growing amount of blanks at EOL @@ -205,10 +205,10 @@ if on: return self._open(tag, allowed_attrs=[], **kw) return self._close(tag) - + def line_anchordef(self, lineno): return '' # not needed for gui editor feeding - + def line_anchorlink(self, on, lineno=0): return '' # not needed for gui editor feeding
--- a/MoinMoin/formatter/text_html.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_html.py Mon Jul 24 22:18:49 2006 +0200 @@ -119,9 +119,9 @@ if ns == 'html': # We have an HTML attribute, fix according to DTD if name == 'content_type': # MIME type such as in <a> and <link> elements - name = 'type' + name = 'type' elif name == 'content_id': # moin historical convention - name = 'id' + name = 'id' elif name in ('css_class', 'css'): # to avoid python word 'class' name = 'class' elif name.startswith('on'): # event handler hook @@ -226,7 +226,7 @@ return {} #attr = {'xml:lang': lang, 'lang': lang, 'dir': i18n.getDirection(lang),} - attr = {'lang': lang, 'dir': i18n.getDirection(lang),} + attr = {'lang': lang, 'dir': i18n.getDirection(lang), } return attr def _formatAttributes(self, attr=None, allowed_attrs=None, **kw): @@ -335,12 +335,12 @@ if tag in _blocks: # Block elements result = [] - + # Add language attributes, but let caller overide the default attributes = self._langAttr() if attr: attributes.update(attr) - + # Format attributes = self._formatAttributes(attributes, allowed_attrs=allowed_attrs, **kw) result.append('<%s%s%s>' % (tag, attributes, is_self_closing)) @@ -388,7 +388,7 @@ if newline: result.append(self._newline()) result.append('</%s>' % (tag)) - tagstr = ''.join(result) + tagstr = ''.join(result) else: # Inline elements # Pull from stack, ignore order, that is not our problem. @@ -433,7 +433,7 @@ if newline: result.append('\n') return ''.join(result) - + def endContent(self, newline=True): """ Close page content div. @@ -455,7 +455,7 @@ result = [] result.append(self.anchordef(aid)) result.append(self._close('div', newline=newline)) - return ''.join(result) + return ''.join(result) def lang(self, on, lang_name): """ Insert text with specific lang and direction. @@ -472,10 +472,10 @@ return self._close(tag) # Direction did not change, no need for span - return '' - + return '' + # Links ############################################################## - + def pagelink(self, on, pagename='', page=None, **kw): """ Link to a page. @@ -486,7 +486,7 @@ """ apply(FormatterBase.pagelink, (self, on, pagename, page), kw) if page is None: - page = Page(self.request, pagename, formatter=self); + page = Page(self.request, pagename, formatter=self) if self.request.user.show_nonexist_qm and on and not page.exists(): self.pagelink_preclosed = True return (page.link_to(self.request, on=1, **kw) + @@ -565,7 +565,7 @@ if css: attrs['class'] = css - + markup = self._open('a', attr=attrs, **kw) else: markup = self._close('a') @@ -641,7 +641,7 @@ return (self.url(1, target, css='attachment', title="attachment:%s" % url) + self.text(text) + self.url(0)) - + def attachment_image(self, url, **kw): _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) @@ -659,7 +659,7 @@ title="attachment:%s" % url, src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1), css="attachment") - + def attachment_drawing(self, url, text, **kw): _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) @@ -724,10 +724,10 @@ self.image(alt=url, src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1), css="drawing"), title="%s" % (_('Edit drawing %(filename)s') % {'filename': self.text(fname)})) - - + + # Text ############################################################## - + def _text(self, text): text = wikiutil.escape(text) if self._in_code: @@ -735,7 +735,7 @@ return text # Inline ########################################################### - + def strong(self, on, **kw): """Creates an HTML <strong> element. @@ -826,11 +826,11 @@ """ tag = 'tt' # Maybe we don't need this, because we have tt will be in inlineStack. - self._in_code = on + self._in_code = on if on: return self._open(tag, allowed_attrs=[], **kw) return self._close(tag) - + def small(self, on, **kw): """Creates a <small> element for smaller font. @@ -867,7 +867,7 @@ if on: return self._open(tag, newline=1, **kw) return self._close(tag) - + # Use by code area _toggleLineNumbersScript = """ <script type="text/javascript"> @@ -920,7 +920,7 @@ } </script> """ - + def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): """Creates a formatted code region, with line numbering. @@ -997,7 +997,7 @@ return ['<span class="%s">' % tok_type, '</span>'][not on] # Paragraphs, Lines, Rules ########################################### - + def _indent_spaces(self): """Returns space(s) for indenting the html source so list nesting is easy to read. @@ -1023,7 +1023,7 @@ if self._in_code_area: preformatted = 1 return ['\n', '<br />\n'][not preformatted] + self._indent_spaces() - + def paragraph(self, on, **kw): """Creates a paragraph with a <p> element. @@ -1051,7 +1051,7 @@ # Add hr class: hr1 - hr6 return self._open('hr', newline=1, attr={'class': 'hr%d' % size}, **kw) return self._open('hr', newline=1, **kw) - + def icon(self, type): return self.request.theme.make_icon(type) @@ -1091,7 +1091,7 @@ else: tagstr = self._close(tag, newline=1) return tagstr - + def bullet_list(self, on, **kw): """Creates an HTML ordered list, <ul> element. @@ -1117,7 +1117,7 @@ """ tag = 'li' if on: - tagstr = self._open(tag, newline=1, **kw) + tagstr = self._open(tag, newline=1, **kw) else: tagstr = self._close(tag, newline=1) return tagstr @@ -1185,7 +1185,7 @@ # closing tag, with empty line after, to make source more readable if not on: return self._close('h%d' % heading_depth) + '\n' - + # create section number number = '' if self._show_section_numbers: @@ -1214,7 +1214,7 @@ self.url(0))) return "%s%s%s" % (result, kw.get('icons', ''), number) - + # Tables ############################################################# _allowed_table_attrs = { @@ -1303,8 +1303,8 @@ result.append(self._close('table')) result.append(self._close('div')) - return ''.join(result) - + return ''.join(result) + def table_row(self, on, attrs=None, **kw): tag = 'tr' if on: @@ -1316,7 +1316,7 @@ allowed_attrs=self._allowed_table_attrs['row'], **kw) return self._close(tag) + '\n' - + def table_cell(self, on, attrs=None, **kw): tag = 'td' if on: @@ -1349,7 +1349,7 @@ if on: return self._open(tag, attr={'class': 'message'}, **kw) return self._close(tag) - + def div(self, on, **kw): tag = 'div' if on: @@ -1361,5 +1361,5 @@ if on: return self._open(tag, **kw) return self._close(tag) - +
--- a/MoinMoin/formatter/text_plain.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_plain.py Mon Jul 24 22:18:49 2006 +0200 @@ -53,7 +53,7 @@ self._url = None self._text = None return u' [%s]' % (self._url) - + def url(self, on, url='', css=None, **kw): if on: self._url = url @@ -81,7 +81,7 @@ def attachment_drawing(self, url, text, **kw): return "[drawing:%s]" % text - + def text(self, text, **kw): self._did_para = 0 if self._text is not None: @@ -138,7 +138,7 @@ else: self._did_para = 1 return u'\n' - + def sup(self, on, **kw): return u'^' @@ -211,7 +211,7 @@ self._text = [] return '\n\n' else: - result = u'\n%s\n\n' % (u'=' * len("".join(self._text))) + result = u'\n%s\n\n' % (u'=' * len("".join(self._text))) self._text = None return result
--- a/MoinMoin/formatter/text_python.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_python.py Mon Jul 24 22:18:49 2006 +0200 @@ -21,7 +21,7 @@ """ defaultDependencies = ["time"] - + def __init__(self, request, static=[], formatter=None, **kw): if formatter: self.formatter = formatter @@ -71,7 +71,7 @@ i += 1 source.append(self.text_cmd_end) source.append(self.__adjust_formatter_state()) - + self.code_fragments = [] # clear code fragments to make # this object reusable return "".join(source) @@ -99,7 +99,7 @@ self.__lang = self.request.current_lang return 'request.current_lang = %r\n' % self.__lang return '' - + def __adjust_formatter_state(self): result = self.__adjust_language_state() if self.__in_p != self.formatter.in_p: @@ -109,11 +109,11 @@ if self.__in_pre != self.formatter.in_pre: result = "%s%s.in_pre = %r\n" % (result, self.__formatter, self.formatter.in_pre) - self.__in_pre = self.formatter.in_pre + self.__in_pre = self.formatter.in_pre return result - + # Public methods --------------------------------------------------- - + def pagelink(self, on, pagename='', page=None, **kw): if on: return self.__insert_code('page=Page(request, %r, formatter=%s);' @@ -133,24 +133,24 @@ return self.__insert_code( 'request.write(%s.attachment_image(%r, **%r))' % (self.__formatter, url, kw)) - + def attachment_drawing(self, url, text, **kw): return self.__insert_code( 'request.write(%s.attachment_drawing(%r, %r, **%r))' % (self.__formatter, url, text, kw)) - + def attachment_inlined(self, url, text, **kw): return self.__insert_code( 'request.write(%s.attachment_inlined(%r, %r, **%r))' % (self.__formatter, url, text, kw)) - def heading(self, on, depth, **kw): + def heading(self, on, depth, **kw): if on: code = [ self.__adjust_language_state(), 'request.write(%s.heading(%r, %r, **%r))' % (self.__formatter, on, depth, kw), - ] + ] return self.__insert_code(''.join(code)) else: return self.formatter.heading(on, depth, **kw) @@ -172,7 +172,7 @@ '%srequest.write(%s.macro(macro_obj, %r, %r))' % (self.__adjust_formatter_state(), self.__formatter, name, args)) - + def parser(self, parser_name, lines): """ parser_name MUST be valid! prints out the result instead of returning it!
--- a/MoinMoin/formatter/text_xml.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/formatter/text_xml.py Mon Jul 24 22:18:49 2006 +0200 @@ -175,11 +175,11 @@ return '<anchor id="%s"/>' % id def anchorlink(self, on, name='', **kw): - id = kw.get('id',None) + id = kw.get('id', None) extra = '' if id: extra = ' id="%s"' % id - return ('<link anchor="%s"%s>' % (name, extra) ,'</link>') [not on] + return ('<link anchor="%s"%s>' % (name, extra), '</link>') [not on] def underline(self, on, **kw): return self.strong(on) # no underline in StyleBook
--- a/MoinMoin/logfile/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/logfile/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -67,7 +67,7 @@ while i < length: result = self.offsets[i-1] + tmp tmp = self.offsets[i] - self.offsets[i] = result + self.offsets[i] = result i = i + 1 self.offsets[0] = offset @@ -79,7 +79,7 @@ Overwrite .parser() and .add() to customize this class to special log files """ - + def __init__(self, filename, buffer_size=65536): """ @param filename: name of the log file @@ -106,7 +106,7 @@ except StopIteration: return yield result - + def sanityCheck(self): """ Check for log file write access. @@ -122,7 +122,7 @@ """ generate some attributes when needed """ - if name=="_LogFile__rel_index": + if name == "_LogFile__rel_index": # starting iteration from begin self.__buffer1 = LineBuffer(self._input, 0, self.buffer_size) self.__buffer2 = LineBuffer(self._input, @@ -164,7 +164,7 @@ return os.path.getsize(self.__filename) except OSError, err: if err.errno == errno.ENOENT: - return 0 + return 0 raise def lines(self): @@ -194,7 +194,7 @@ def date(self): """ Return timestamp of log file in usecs """ try: - mtime = os.path.getmtime(self.__filename) + mtime = os.path.getmtime(self.__filename) except OSError, err: if err.errno == errno.ENOENT: # This can happen on fresh wiki when building the index @@ -237,7 +237,7 @@ self.__rel_index = (self.__rel_index + self.__buffer1.len) self.__buffer = self.__buffer1 - + while self.__rel_index >= self.__buffer.len: if self.__buffer == self.__buffer1: # change to buffer 2 @@ -248,7 +248,7 @@ tmpbuff = LineBuffer(self._input, self.__buffer1.offsets[-1], self.buffer_size) - if tmpbuff.len==0: + if tmpbuff.len == 0: # end of file if self.__lineno: self.__lineno = (self.__lineno + lines - @@ -258,7 +258,7 @@ return True # shift buffers self.__buffer1 = self.__buffer2 - self.__buffer2 = tmpbuff + self.__buffer2 = tmpbuff self.__rel_index = self.__rel_index - self.__buffer1.len if self.__lineno: self.__lineno += lines return False @@ -278,15 +278,16 @@ XXX It does not raise anything! """ result = None - while result == None: - while result == None: + while result is None: + while result is None: result = self.__next() if self.filter and not self.filter(result): result = None return result - + def __previous(self): - if self.peek(-1): raise StopIteration + if self.peek(-1): + raise StopIteration return self.parser(self.__buffer.lines[self.__rel_index]) def previous(self): @@ -295,8 +296,8 @@ raises StopIteration at file begin """ result = None - while result == None: - while result == None: + while result is None: + while result is None: result = self.__previous() if self.filter and not self.filter(result): result = None @@ -319,16 +320,16 @@ """moves file position to the end""" self._input.seek(0, 2) # to end of file size = self._input.tell() - if (not self.__buffer2) or (size>self.__buffer2.offsets[-1]): + if (not self.__buffer2) or (size > self.__buffer2.offsets[-1]): self.__buffer2 = LineBuffer(self._input, size, self.buffer_size, - forward = False) - + forward=False) + self.__buffer1 = LineBuffer(self._input, self.__buffer2.offsets[0], self.buffer_size, - forward = False) + forward=False) self.__buffer = self.__buffer2 self.__rel_index = self.__buffer2.len self.__lineno = None @@ -341,7 +342,7 @@ For this plain file implementation position is an Integer. """ return self.__buffer.offsets[self.__rel_index] - + def seek(self, position, line_no=None): """ moves file position to an value formerly gotten from .position(). To enable line counting line_no must be provided. @@ -362,7 +363,7 @@ self.__buffer1 = LineBuffer(self._input, position, self.buffer_size, - forward = False) + forward=False) self.__buffer2 = LineBuffer(self._input, position, self.buffer_size) @@ -374,7 +375,7 @@ def line_no(self): """@return: the current line number or None if line number is unknown""" return self.__lineno - + def calculate_line_no(self): """ Calculate the current line number from buffer offsets @@ -404,14 +405,14 @@ """ line = "\t".join(data) self._add(line) - + def _add(self, line): """ @param line: flat line @type line: String write on entry in the log file """ - if line != None: + if line is not None: if line[-1] != '\n': line += '\n' self._output.write(line)
--- a/MoinMoin/logfile/editlog.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/logfile/editlog.py Mon Jul 24 22:18:49 2006 +0200 @@ -34,8 +34,9 @@ def is_from_current_user(self, request): user = request.user - if user.id: return user.id==self.userid - return request.remote_addr==self.addr + if user.id: + return user.id == self.userid + return request.remote_addr == self.addr def getEditorData(self, request): """ Return a tuple of type id and string or Page object @@ -112,7 +113,7 @@ request.formatter.url(0)) elif kind == 'ip': idx = info.find('.') - if idx==-1: + if idx == -1: idx = len(info) title = wikiutil.escape('???' + title) text = wikiutil.escape(info[:idx]) @@ -124,7 +125,7 @@ class EditLog(LogFile): def __init__(self, request, filename=None, buffer_size=65536, **kw): - if filename == None: + if filename is None: rootpagename = kw.get('rootpagename', None) if rootpagename: filename = Page(request, rootpagename).getPagePath('edit-log', isfile=1) @@ -133,7 +134,7 @@ LogFile.__init__(self, filename, buffer_size) self._NUM_FIELDS = 9 self._usercache = {} - + # Used by antispam in order to show an internal name instead # of a confusing userid self.uid_override = kw.get('uid_override', None) @@ -155,16 +156,16 @@ hostname = host else: hostname = host - - remap_chars = {u'\t': u' ', u'\r': u' ', u'\n': u' ',} + + remap_chars = {u'\t': u' ', u'\r': u' ', u'\n': u' ', } comment = comment.translate(remap_chars) user_id = request.user.valid and request.user.id or '' - if self.uid_override != None: + if self.uid_override is not None: user_id = '' hostname = self.uid_override host = '' - + line = u"\t".join((str(long(mtime)), # has to be long for py 2.2.x "%08d" % rev, action, @@ -193,16 +194,16 @@ result.pagename = wikiutil.unquoteWikiname(result.pagename.encode('ascii')) result.ed_time_usecs = long(result.ed_time_usecs or '0') # has to be long for py 2.2.x return result - + def set_filter(self, **kw): expr = "1" for field in ['pagename', 'addr', 'hostname', 'userid']: if kw.has_key(field): expr = "%s and x.%s == %s" % (expr, field, `kw[field]`) - + if kw.has_key('ed_time_usecs'): expr = "%s and long(x.ed_time_usecs) == %s" % (expr, long(kw['ed_time_usecs'])) # must be long for py 2.2.x self.filter = eval("lambda x: " + expr) - +
--- a/MoinMoin/logfile/eventlog.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/logfile/eventlog.py Mon Jul 24 22:18:49 2006 +0200 @@ -10,9 +10,9 @@ from MoinMoin.util import web class EventLog(LogFile): - + def __init__(self, request, filename=None, buffer_size=65536, **kw): - if filename == None: + if filename is None: rootpagename = kw.get('rootpagename', None) if rootpagename: from MoinMoin.Page import Page @@ -28,7 +28,7 @@ """ if request.isSpiderAgent: return - + if mtime_usecs is None: mtime_usecs = wikiutil.timestamp2version(time.time()) @@ -52,9 +52,9 @@ # badly formatted line in file, skip it return None return long(time_usecs), eventtype, wikiutil.parseQueryString(kvpairs) - - def set_filter(self, event_types = None): - if event_types == None: + + def set_filter(self, event_types=None): + if event_types is None: self.filter = None else: self.filter = lambda line: (line[1] in event_types)
--- a/MoinMoin/macro/EditedSystemPages.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/macro/EditedSystemPages.py Mon Jul 24 22:18:49 2006 +0200 @@ -44,7 +44,7 @@ result.append(f.pagelink(0, name)) result.append(f.listitem(0)) result.append(f.number_list(0)) - + return ''.join(result)
--- a/MoinMoin/macro/Include.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/macro/Include.py Mon Jul 24 22:18:49 2006 +0200 @@ -45,7 +45,7 @@ h = title.strip() level = 1 while h[level:level+1] == '=': level = level+1 - depth = min(5,level) + depth = min(5, level) title_text = h[level:-level].strip() titles.append((title_text, level)) return titles @@ -65,7 +65,7 @@ # prepare including page result = [] - print_mode = macro.form.has_key('action') and macro.form['action'][0] in ("print", "format") + print_mode = request.action in ("print", "format") this_page = macro.formatter.page if not hasattr(this_page, '_macroInclude_pagelist'): this_page._macroInclude_pagelist = {} @@ -177,7 +177,7 @@ if not hasattr(request, "_Include_backto"): request._Include_backto = this_page.page_name - + # do headings level = None if args.group('heading') and args.group('hquote'):
--- a/MoinMoin/macro/MonthCalendar.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/macro/MonthCalendar.py Mon Jul 24 22:18:49 2006 +0200 @@ -240,7 +240,7 @@ _arg_anniversary = r',\s*(?P<anniversary>[+-]?\d+)?\s*' _arg_template = r',\s*(?P<template>[^, ]+)?\s*' # XXX see basepage comment _args_re_pattern = r'^(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?(%s)?$' % \ - (_arg_basepage, _arg_year, _arg_month, \ + (_arg_basepage, _arg_year, _arg_month, _arg_offset, _arg_offset2, _arg_height6, _arg_anniversary, _arg_template)
--- a/MoinMoin/macro/Navigation.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/macro/Navigation.py Mon Jul 24 22:18:49 2006 +0200 @@ -74,8 +74,7 @@ self._ = self.macro.request.getText self.pagename = self.macro.formatter.page.page_name - self.print_mode = self.macro.request.form.has_key('action') \ - and self.macro.request.form['action'][0] == 'print' + self.print_mode = self.macro.request.action == 'print' self.media = self.macro.request.form.get('media', [None])[0] self.querystr = self.print_mode and self.PROJECTION or ''
--- a/MoinMoin/macro/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/macro/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -66,20 +66,20 @@ defaultDependency = ["time"] Dependencies = { - "TitleSearch" : ["namespace"], - "Goto" : [], - "WordIndex" : ["namespace"], - "TitleIndex" : ["namespace"], - "InterWiki" : ["pages"], # if interwikimap is editable - "PageCount" : ["namespace"], - "Icon" : ["user"], # users have different themes and user prefs - "PageList" : ["namespace"], - "Date" : ["time"], - "DateTime" : ["time"], - "UserPreferences" :["time"], - "Anchor" : [], - "Mailto" : ["user"], - "GetVal" : ["pages"], + "TitleSearch": ["namespace"], + "Goto": [], + "WordIndex": ["namespace"], + "TitleIndex": ["namespace"], + "InterWiki": ["pages"], # if interwikimap is editable + "PageCount": ["namespace"], + "Icon": ["user"], # users have different themes and user prefs + "PageList": ["namespace"], + "Date": ["time"], + "DateTime": ["time"], + "UserPreferences": ["time"], + "Anchor": [], + "Mailto": ["user"], + "GetVal": ["pages"], "TemplateList": ["namespace"], }
--- a/MoinMoin/multiconfig.py Sat Jul 22 13:38:15 2006 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,716 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Multiple configuration handler and Configuration defaults class - - @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>, - 2005-2006 by MoinMoin:ThomasWaldmann. - @license: GNU GPL, see COPYING for details. -""" - -import re, os, sys -from MoinMoin import error -import MoinMoin.auth as authmodule - -_url_re_cache = None -_farmconfig_mtime = None -_config_cache = {} - - -def _importConfigModule(name): - """ Import and return configuration module and its modification time - - Handle all errors except ImportError, because missing file is not - always an error. - - @param name: module name - @rtype: tuple - @return: module, modification time - """ - try: - module = __import__(name, globals(), {}) - mtime = os.path.getmtime(module.__file__) - except ImportError: - raise - except IndentationError, err: - msg = '''IndentationError: %(err)s - -The configuration files are python modules. Therefore, whitespace is -important. Make sure that you use only spaces, no tabs are allowed here! -You have to use four spaces at the beginning of the line mostly. -''' % { - 'err': err, -} - raise error.ConfigurationError(msg) - except Exception, err: - msg = '%s: %s' % (err.__class__.__name__, str(err)) - raise error.ConfigurationError(msg) - return module, mtime - - -def _url_re_list(): - """ Return url matching regular expression - - Import wikis list from farmconfig on the first call and compile the - regexes. Later then return the cached regex list. - - @rtype: list of tuples of (name, compiled re object) - @return: url to wiki config name matching list - """ - global _url_re_cache, _farmconfig_mtime - if _url_re_cache is None: - try: - farmconfig, _farmconfig_mtime = _importConfigModule('farmconfig') - except ImportError: - # Default to wikiconfig for all urls. - _farmconfig_mtime = 0 - _url_re_cache = [('wikiconfig', re.compile(r'.')), ] # matches everything - else: - try: - cache = [] - for name, regex in farmconfig.wikis: - cache.append((name, re.compile(regex))) - _url_re_cache = cache - except AttributeError: - msg = """ -Missing required 'wikis' list in 'farmconfig.py'. - -If you run a single wiki you do not need farmconfig.py. Delete it and -use wikiconfig.py. -""" - raise error.ConfigurationError(msg) - return _url_re_cache - - -def _makeConfig(name): - """ Create and return a config instance - - Timestamp config with either module mtime or farmconfig mtime. This - mtime can be used later to invalidate older caches. - - @param name: module name - @rtype: DefaultConfig sub class instance - @return: new configuration instance - """ - global _farmconfig_mtime - try: - module, mtime = _importConfigModule(name) - configClass = getattr(module, 'Config') - cfg = configClass(name) - cfg.cfg_mtime = max(mtime, _farmconfig_mtime) - except ImportError, err: - msg = '''ImportError: %(err)s - -Check that the file is in the same directory as the server script. If -it is not, you must add the path of the directory where the file is -located to the python path in the server script. See the comments at -the top of the server script. - -Check that the configuration file name is either "wikiconfig.py" or the -module name specified in the wikis list in farmconfig.py. Note that the -module name does not include the ".py" suffix. -''' % { - 'err': err, -} - raise error.ConfigurationError(msg) - except AttributeError, err: - msg = '''AttributeError: %(err)s - -Could not find required "Config" class in "%(name)s.py". - -This might happen if you are trying to use a pre 1.3 configuration file, or -made a syntax or spelling error. - -Another reason for this could be a name clash. It is not possible to have -config names like e.g. stats.py - because that colides with MoinMoin/stats/ - -have a look into your MoinMoin code directory what other names are NOT -possible. - -Please check your configuration file. As an example for correct syntax, -use the wikiconfig.py file from the distribution. -''' % { - 'name': name, - 'err': err, -} - raise error.ConfigurationError(msg) - return cfg - - -def _getConfigName(url): - """ Return config name for url or raise """ - for name, regex in _url_re_list(): - match = regex.match(url) - if match: - return name - # nothing matched - msg = ''' -Could not find a match for url: "%(url)s". - -Check your URL regular expressions in the "wikis" list in -"farmconfig.py". -''' % { - 'url': url, -} - raise error.ConfigurationError(msg) - - -def getConfig(url): - """ Return cached config instance for url or create new one - - If called by many threads in the same time multiple config - instances might be created. The first created item will be - returned, using dict.setdefault. - - @param url: the url from request, possibly matching specific wiki - @rtype: DefaultConfig subclass instance - @return: config object for specific wiki - """ - configName = _getConfigName(url) - try: - config = _config_cache[configName] - except KeyError: - config = _makeConfig(configName) - config = _config_cache.setdefault(configName, config) - return config - - -# This is a way to mark some text for the gettext tools so that they don't -# get orphaned. See http://www.python.org/doc/current/lib/node278.html. -def _(text): return text - - -class DefaultConfig: - """ default config values """ - - # All acl_rights_* lines must use unicode! - acl_rights_default = u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write" - acl_rights_before = u"" - acl_rights_after = u"" - acl_rights_valid = ['read', 'write', 'delete', 'revert', 'admin'] - - actions_excluded = [] # ['DeletePage', 'AttachFile', 'RenamePage', 'test', ] - allow_xslt = 0 - attachments = None # {'dir': path, 'url': url-prefix} - auth = [authmodule.moin_login, authmodule.moin_session, ] - - backup_compression = 'gz' - backup_users = [] - backup_include = [] - backup_exclude = [ - r"(.+\.py(c|o)$)", - r"%(cache_dir)s", - r"%(/)spages%(/)s.+%(/)scache%(/)s[^%(/)s]+$" % {'/': os.sep}, - r"%(/)s(edit-lock|event-log|\.DS_Store)$" % {'/': os.sep}, - ] - backup_storage_dir = '/tmp' - backup_restore_target_dir = '/tmp' - - bang_meta = 1 - caching_formats = ['text_html'] - changed_time_fmt = '%H:%M' - - # chars_{upper,lower,digits,spaces} see MoinMoin/util/chartypes.py - - # if you have gdchart, add something like - # chart_options = {'width = 720, 'height': 540} - chart_options = None - - config_check_enabled = 0 - - cookie_domain = None # use '.domain.tld" for a farm with hosts in that domain - cookie_path = None # use '/wikifarm" for a farm with pathes below that path - cookie_lifetime = 12 # 12 hours from now - cookie_secret = '1234' # secret value for crypting session cookie - you should change this :) - - data_dir = './data/' - data_underlay_dir = './underlay/' - - date_fmt = '%Y-%m-%d' - datetime_fmt = '%Y-%m-%d %H:%M:%S' - - default_markup = 'wiki' - docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/" # correct for debian sarge - - editor_default = 'text' # which editor is called when nothing is specified - editor_ui = 'freechoice' # which editor links are shown on user interface - editor_force = False - editor_quickhelp = {# editor markup hints quickhelp - 'wiki': _("""\ - Emphasis:: [[Verbatim('')]]''italics''[[Verbatim('')]]; [[Verbatim(''')]]'''bold'''[[Verbatim(''')]]; [[Verbatim(''''')]]'''''bold italics'''''[[Verbatim(''''')]]; [[Verbatim('')]]''mixed ''[[Verbatim(''')]]'''''bold'''[[Verbatim(''')]] and italics''[[Verbatim('')]]; [[Verbatim(----)]] horizontal rule. - Headings:: [[Verbatim(=)]] Title 1 [[Verbatim(=)]]; [[Verbatim(==)]] Title 2 [[Verbatim(==)]]; [[Verbatim(===)]] Title 3 [[Verbatim(===)]]; [[Verbatim(====)]] Title 4 [[Verbatim(====)]]; [[Verbatim(=====)]] Title 5 [[Verbatim(=====)]]. - Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents. - Links:: [[Verbatim(JoinCapitalizedWords)]]; [[Verbatim(["brackets and double quotes"])]]; url; [url]; [url label]. - Tables:: || cell text |||| cell text spanning 2 columns ||; no trailing white space allowed after tables or titles. - -(!) For more help, see HelpOnEditing or SyntaxReference. -"""), - 'rst': _("""\ -Emphasis: <i>*italic*</i> <b>**bold**</b> ``monospace``<br/> -<br/><pre> -Headings: Heading 1 Heading 2 Heading 3 - ========= --------- ~~~~~~~~~ - -Horizontal rule: ---- -Links: TrailingUnderscore_ `multi word with backticks`_ external_ - -.. _external: http://external-site.net/foo/ - -Lists: * bullets; 1., a. numbered items. -</pre> -<br/> -(!) For more help, see the -<a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html"> -reStructuredText Quick Reference -</a>. -"""), - } - edit_locking = 'warn 10' # None, 'warn <timeout mins>', 'lock <timeout mins>' - edit_rows = 20 - - hacks = {} # { 'feature1': value1, ... } - # Configuration for features still in development. - # For boolean stuff just use config like this: - # hacks = { 'feature': True, ...} - # and in the code use: - # if cfg.hacks.get('feature', False): <doit> - # A non-existing hack key should ever mean False, None, "", [] or {}! - - hosts_deny = [] - - html_head = '' - html_head_queries = '''<meta name="robots" content="noindex,nofollow">\n''' - html_head_posts = '''<meta name="robots" content="noindex,nofollow">\n''' - html_head_index = '''<meta name="robots" content="index,follow">\n''' - html_head_normal = '''<meta name="robots" content="index,nofollow">\n''' - html_pagetitle = None - - interwiki_preferred = [] # list of wiki names to show at top of interwiki list - - language_default = 'en' - language_ignore_browser = False # ignore browser settings, use language_default - # or user prefs - - log_reverse_dns_lookups = True # if we do reverse dns lookups for logging hostnames - # instead of just IPs - - xapian_search = False # disabled until xapian is finished - xapian_index_dir = None - xapian_stemming = True - - mail_login = None # or "user pwd" if you need to use SMTP AUTH - mail_sendmail = None # "/usr/sbin/sendmail -t -i" to not use SMTP, but sendmail - mail_smarthost = None - mail_from = None # u'Juergen Wiki <noreply@jhwiki.org>' - - mail_import_subpage_template = u"$from-$date-$subject" # used for mail import - mail_import_wiki_address = None # the e-mail address for e-mails that should go into the wiki - mail_import_secret = "" - - navi_bar = [u'RecentChanges', u'FindPage', u'HelpContents', ] - nonexist_qm = 0 - - page_credits = [ - '<a href="http://moinmoin.wikiwikiweb.de/">MoinMoin Powered</a>', - '<a href="http://www.python.org/">Python Powered</a>', - '<a href="http://validator.w3.org/check?uri=referer">Valid HTML 4.01</a>', - ] - page_footer1 = '' - page_footer2 = '' - - page_header1 = '' - page_header2 = '' - - page_front_page = u'HelpOnLanguages' # this will make people choose a sane config - page_local_spelling_words = u'LocalSpellingWords' - page_category_regex = u'^Category[A-Z]' - page_dict_regex = u'[a-z0-9]Dict$' - page_group_regex = u'[a-z0-9]Group$' - page_template_regex = u'[a-z0-9]Template$' - - page_license_enabled = 0 - page_license_page = u'WikiLicense' - - # These icons will show in this order in the iconbar, unless they - # are not relevant, e.g email icon when the wiki is not configured - # for email. - page_iconbar = ["up", "edit", "view", "diff", "info", "subscribe", "raw", "print", ] - - # Standard buttons in the iconbar - page_icons_table = { - # key last part of url, title, icon-key - 'help': ("%(q_page_help_contents)s", "%(page_help_contents)s", "help"), - 'find': ("%(q_page_find_page)s?value=%(q_page_name)s", "%(page_find_page)s", "find"), - 'diff': ("%(q_page_name)s?action=diff", _("Diffs"), "diff"), - 'info': ("%(q_page_name)s?action=info", _("Info"), "info"), - 'edit': ("%(q_page_name)s?action=edit", _("Edit"), "edit"), - 'unsubscribe': ("%(q_page_name)s?action=subscribe", _("UnSubscribe"), "unsubscribe"), - 'subscribe': ("%(q_page_name)s?action=subscribe", _("Subscribe"), "subscribe"), - 'raw': ("%(q_page_name)s?action=raw", _("Raw"), "raw"), - 'xml': ("%(q_page_name)s?action=show&mimetype=text/xml", _("XML"), "xml"), - 'print': ("%(q_page_name)s?action=print", _("Print"), "print"), - 'view': ("%(q_page_name)s", _("View"), "view"), - 'up': ("%(q_page_parent_page)s", _("Up"), "up"), - } - - refresh = None # (minimum_delay, type), e.g.: (2, 'internal') - rss_cache = 60 # suggested caching time for RecentChanges RSS, in seconds - shared_intermap = None # can be string or list of strings (filenames) - show_hosts = 1 - show_interwiki = 0 - show_login = 1 - show_names = True - show_section_numbers = 0 - show_timings = 0 - show_version = 0 - siteid = 'default' - stylesheets = [] # list of tuples (media, csshref) to insert after theme css, before user css - superuser = [] # list of unicode user names that have super powers :) - - surge_action_limits = {# allow max. <count> <action> requests per <dt> secs - # action: (count, dt) - 'all': (30, 30), - 'show': (30, 60), - 'recall': (5, 60), - 'raw': (20, 40), # some people use this for css - 'AttachFile': (90, 60), - 'diff': (30, 60), - 'fullsearch': (5, 60), - 'edit': (10, 120), - 'rss_rc': (1, 60), - 'default': (30, 60), - } - surge_lockout_time = 3600 # secs you get locked out when you ignore warnings - - theme_default = 'modern' - theme_force = False - - trail_size = 5 - tz_offset = 0.0 # default time zone offset in hours from UTC - - user_autocreate = False # do we auto-create user profiles - user_email_unique = True # do we check whether a user's email is unique? - - # a regex of HTTP_USER_AGENTS that should be excluded from logging - # and receive a FORBIDDEN for anything except viewing a page - ua_spiders = ('archiver|cfetch|crawler|curl|gigabot|googlebot|holmes|htdig|httrack|httpunit|jeeves|larbin|leech|' - 'linkbot|linkmap|linkwalk|mercator|mirror|msnbot|nutbot|omniexplorer|puf|robot|scooter|' - 'sherlock|slurp|sitecheck|spider|teleport|voyager|webreaper|wget') - - # Wiki identity - sitename = u'Untitled Wiki' - url_prefix = '/wiki' - logo_string = None - interwikiname = None - - url_mappings = {} - - user_checkbox_fields = [ - ('mailto_author', lambda _: _('Publish my email (not my wiki homepage) in author info')), - ('edit_on_doubleclick', lambda _: _('Open editor on double click')), - ('remember_last_visit', lambda _: _('After login, jump to last visited page')), - ('show_nonexist_qm', lambda _: _('Show question mark for non-existing pagelinks')), - ('show_page_trail', lambda _: _('Show page trail')), - ('show_toolbar', lambda _: _('Show icon toolbar')), - ('show_topbottom', lambda _: _('Show top/bottom links in headings')), - ('show_fancy_diff', lambda _: _('Show fancy diffs')), - ('wikiname_add_spaces', lambda _: _('Add spaces to displayed wiki names')), - ('remember_me', lambda _: _('Remember login information')), - ('want_trivial', lambda _: _('Subscribe to trivial changes')), - - ('disabled', lambda _: _('Disable this account forever')), - # if an account is disabled, it may be used for looking up - # id -> username for page info and recent changes, but it - # is not usable for the user any more: - ] - - user_checkbox_defaults = {'mailto_author': 0, - 'edit_on_doubleclick': 0, - 'remember_last_visit': 0, - 'show_nonexist_qm': nonexist_qm, - 'show_page_trail': 1, - 'show_toolbar': 1, - 'show_topbottom': 0, - 'show_fancy_diff': 1, - 'wikiname_add_spaces': 0, - 'remember_me': 1, - 'want_trivial': 0, - } - - # don't let the user change those - # user_checkbox_disable = ['disabled', 'want_trivial'] - user_checkbox_disable = [] - - # remove those checkboxes: - #user_checkbox_remove = ['edit_on_doubleclick', 'show_nonexist_qm', 'show_toolbar', 'show_topbottom', - # 'show_fancy_diff', 'wikiname_add_spaces', 'remember_me', 'disabled',] - user_checkbox_remove = [] - - user_form_fields = [ - ('name', _('Name'), "text", "36", _("(Use Firstname''''''Lastname)")), - ('aliasname', _('Alias-Name'), "text", "36", ''), - ('password', _('Password'), "password", "36", ''), - ('password2', _('Password repeat'), "password", "36", _('(Only for password change or new account)')), - ('email', _('Email'), "text", "36", ''), - ('css_url', _('User CSS URL'), "text", "40", _('(Leave it empty for disabling user CSS)')), - ('edit_rows', _('Editor size'), "text", "3", ''), - ] - - user_form_defaults = {# key: default - do NOT remove keys from here! - 'name': '', - 'aliasname': '', - 'password': '', - 'password2': '', - 'email': '', - 'css_url': '', - 'edit_rows': "20", - } - - # don't let the user change those, but show them: - #user_form_disable = ['name', 'aliasname', 'email',] - user_form_disable = [] - - # remove those completely: - #user_form_remove = ['password', 'password2', 'css_url', 'logout', 'create', 'account_sendmail',] - user_form_remove = [] - - # attributes we do NOT save to the userpref file - user_transient_fields = ['id', 'valid', 'may', 'auth_username', 'trusted', 'password', 'password2', 'auth_method', 'auth_attribs', ] - - user_homewiki = 'Self' # interwiki name for where user homepages are located - - unzip_single_file_size = 2.0 * 1000**2 - unzip_attachments_space = 200.0 * 1000**2 - unzip_attachments_count = 51 # 1 zip file + 50 files contained in it - - xmlrpc_putpage_enabled = 0 # if 0, putpage will write to a test page only - xmlrpc_putpage_trusted_only = 1 # if 1, you will need to be http auth authenticated - - SecurityPolicy = None - - def __init__(self, siteid): - """ Init Config instance """ - self.siteid = siteid - if self.config_check_enabled: - self._config_check() - - # define directories - self.moinmoin_dir = os.path.abspath(os.path.dirname(__file__)) - data_dir = os.path.normpath(self.data_dir) - self.data_dir = data_dir - for dirname in ('user', 'cache', 'plugin'): - name = dirname + '_dir' - if not getattr(self, name, None): - setattr(self, name, os.path.join(data_dir, dirname)) - - # Try to decode certain names which allow unicode - self._decode() - - self._check_directories() - - if not isinstance(self.superuser, list): - msg = """The superuser setting in your wiki configuration is not a list - (e.g. ['Sample User', 'AnotherUser']). - Please change it in your wiki configuration and try again.""" - raise error.ConfigurationError(msg) - - self._loadPluginModule() - - # Preparse user dicts - self._fillDicts() - - # Normalize values - self.language_default = self.language_default.lower() - - # Use site name as default name-logo - if self.logo_string is None: - self.logo_string = self.sitename - - # Check for needed modules - - # FIXME: maybe we should do this check later, just before a - # chart is needed, maybe in the chart module, instead doing it - # for each request. But this require a large refactoring of - # current code. - if self.chart_options: - try: - import gdchart - except ImportError: - self.chart_options = None - - # post process - # we replace any string placeholders with config values - # e.g u'%(page_front_page)s' % self - self.navi_bar = [elem % self for elem in self.navi_bar] - self.backup_exclude = [elem % self for elem in self.backup_exclude] - - # list to cache xapian searcher objects - self.xapian_searchers = [] - - # check if mail is possible and set flag: - self.mail_enabled = (self.mail_smarthost is not None or self.mail_sendmail is not None) and self.mail_from - - def _config_check(self): - """ Check namespace and warn about unknown names - - Warn about names which are not used by DefaultConfig, except - modules, classes, _private or __magic__ names. - - This check is disabled by default, when enabled, it will show an - error message with unknown names. - """ - unknown = ['"%s"' % name for name in dir(self) - if not name.startswith('_') and - not DefaultConfig.__dict__.has_key(name) and - not isinstance(getattr(self, name), (type(sys), type(DefaultConfig)))] - if unknown: - msg = """ -Unknown configuration options: %s. - -For more information, visit HelpOnConfiguration. Please check your -configuration for typos before requesting support or reporting a bug. -""" % ', '.join(unknown) - raise error.ConfigurationError(msg) - - def _decode(self): - """ Try to decode certain names, ignore unicode values - - Try to decode str using utf-8. If the decode fail, raise FatalError. - - Certain config variables should contain unicode values, and - should be defined with u'text' syntax. Python decode these if - the file have a 'coding' line. - - This will allow utf-8 users to use simple strings using, without - using u'string'. Other users will have to use u'string' for - these names, because we don't know what is the charset of the - config files. - """ - charset = 'utf-8' - message = u''' -"%(name)s" configuration variable is a string, but should be -unicode. Use %(name)s = u"value" syntax for unicode variables. - -Also check your "-*- coding -*-" line at the top of your configuration -file. It should match the actual charset of the configuration file. -''' - - decode_names = ( - 'sitename', 'logo_string', 'navi_bar', 'page_front_page', - 'page_category_regex', 'page_dict_regex', - 'page_group_regex', 'page_template_regex', 'page_license_page', - 'page_local_spelling_words', 'acl_rights_default', - 'acl_rights_before', 'acl_rights_after', 'mail_from' - ) - - for name in decode_names: - attr = getattr(self, name, None) - if attr: - # Try to decode strings - if isinstance(attr, str): - try: - setattr(self, name, unicode(attr, charset)) - except UnicodeError: - raise error.ConfigurationError(message % - {'name': name}) - # Look into lists and try to decode strings inside them - elif isinstance(attr, list): - for i in xrange(len(attr)): - item = attr[i] - if isinstance(item, str): - try: - attr[i] = unicode(item, charset) - except UnicodeError: - raise error.ConfigurationError(message % - {'name': name}) - - def _check_directories(self): - """ Make sure directories are accessible - - Both data and underlay should exists and allow read, write and - execute. - """ - mode = os.F_OK | os.R_OK | os.W_OK | os.X_OK - for attr in ('data_dir', 'data_underlay_dir'): - path = getattr(self, attr) - - # allow an empty underlay path or None - if attr == 'data_underlay_dir' and not path: - continue - - path_pages = os.path.join(path, "pages") - if not (os.path.isdir(path_pages) and os.access(path_pages, mode)): - msg = ''' -%(attr)s "%(path)s" does not exists, or has incorrect ownership or -permissions. - -Make sure the directory and the subdirectory pages are owned by the web -server and are readable, writable and executable by the web server user -and group. - -It is recommended to use absolute paths and not relative paths. Check -also the spelling of the directory name. -''' % {'attr': attr, 'path': path, } - raise error.ConfigurationError(msg) - - def _loadPluginModule(self): - """ import plugin module under configname.plugin - - To be able to import plugin from arbitrary path, we have to load - the base package once using imp.load_module. Later, we can use - standard __import__ call to load plugins in this package. - - Since each wiki has unique plugins, we load the plugin package - under the wiki configuration module, named self.siteid. - """ - import sys, imp - - name = self.siteid + '.plugin' - try: - # Lock other threads while we check and import - imp.acquire_lock() - try: - # If the module is not loaded, try to load it - if not name in sys.modules: - # Find module on disk and try to load - slow! - plugin_parent_dir = os.path.abspath(os.path.join(self.plugin_dir, '..')) - fp, path, info = imp.find_module('plugin', [plugin_parent_dir]) - try: - # Load the module and set in sys.modules - module = imp.load_module(name, fp, path, info) - sys.modules[self.siteid].plugin = module - finally: - # Make sure fp is closed properly - if fp: - fp.close() - finally: - imp.release_lock() - except ImportError, err: - msg = ''' -Could not import plugin package "%(path)s/plugin" because of ImportError: -%(err)s. - -Make sure your data directory path is correct, check permissions, and -that the data/plugin directory has an __init__.py file. -''' % { - 'path': self.data_dir, - 'err': str(err), -} - raise error.ConfigurationError(msg) - - def _fillDicts(self): - """ fill config dicts - - Fills in missing dict keys of derived user config by copying - them from this base class. - """ - # user checkbox defaults - for key, value in DefaultConfig.user_checkbox_defaults.items(): - if not self.user_checkbox_defaults.has_key(key): - self.user_checkbox_defaults[key] = value - - def __getitem__(self, item): - """ Make it possible to access a config object like a dict """ - return getattr(self, item) - -# remove the gettext pseudo function -del _ -
--- a/MoinMoin/request/CGI.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/CGI.py Mon Jul 24 22:18:49 2006 +0200 @@ -7,7 +7,7 @@ 2003-2006 MoinMoin:ThomasWaldmann @license: GNU GPL, see COPYING for details. """ -import sys, os +import sys, os, cgi from MoinMoin import config from MoinMoin.request import RequestBase @@ -29,6 +29,11 @@ except Exception, err: self.fail(err) + def _setup_args_from_cgi_form(self): + """ Override to create cgi form """ + form = cgi.FieldStorage() + return RequestBase._setup_args_from_cgi_form(self, form) + def open_logs(self): # create log file for catching stderr output if not self.opened_logs:
--- a/MoinMoin/request/CLI.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/CLI.py Mon Jul 24 22:18:49 2006 +0200 @@ -30,6 +30,12 @@ self.cfg.caching_formats = [] # don't spoil the cache self.initTheme() # usually request.run() does this, but we don't use it + def _setup_args_from_cgi_form(self): + """ Override to create cli form """ + #form = cgi.FieldStorage() + #return RequestBase._setup_args_from_cgi_form(self, form) + return {} + def read(self, n=None): """ Read from input stream. """ if n is None:
--- a/MoinMoin/request/FCGI.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/FCGI.py Mon Jul 24 22:18:49 2006 +0200 @@ -32,11 +32,9 @@ except Exception, err: self.fail(err) - def _setup_args_from_cgi_form(self, form=None): + def _setup_args_from_cgi_form(self): """ Override to use FastCGI form """ - if form is None: - form = self.fcgform - return RequestBase._setup_args_from_cgi_form(self, form) + return RequestBase._setup_args_from_cgi_form(self, self.fcgform) def read(self, n=None): """ Read from input stream. """
--- a/MoinMoin/request/MODPYTHON.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/MODPYTHON.py Mon Jul 24 22:18:49 2006 +0200 @@ -76,15 +76,14 @@ RequestBase.fixURI(self, env) - def _setup_args_from_cgi_form(self, form=None): + def _setup_args_from_cgi_form(self): """ Override to use mod_python.util.FieldStorage - Its little different from cgi.FieldStorage, so we need to + It's little different from cgi.FieldStorage, so we need to duplicate the conversion code. """ from mod_python import util - if form is None: - form = util.FieldStorage(self.mpyreq) + form = util.FieldStorage(self.mpyreq) args = {} for key in form.keys():
--- a/MoinMoin/request/STANDALONE.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/STANDALONE.py Mon Jul 24 22:18:49 2006 +0200 @@ -54,7 +54,7 @@ except Exception, err: self.fail(err) - def _setup_args_from_cgi_form(self, form=None): + def _setup_args_from_cgi_form(self): """ Override to create standalone form """ form = cgi.FieldStorage(self.rfile, headers=self.headers, environ={'REQUEST_METHOD': 'POST'}) return RequestBase._setup_args_from_cgi_form(self, form)
--- a/MoinMoin/request/TWISTED.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/TWISTED.py Mon Jul 24 22:18:49 2006 +0200 @@ -64,7 +64,7 @@ return self.finish() RequestBase.run(self) - def setup_args(self, form=None): + def setup_args(self): """ Return args dict Twisted already parsed args, including __filename__ hacking,
--- a/MoinMoin/request/WSGI.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/WSGI.py Mon Jul 24 22:18:49 2006 +0200 @@ -6,7 +6,7 @@ 2003-2006 MoinMoin:ThomasWaldmann @license: GNU GPL, see COPYING for details. """ -import sys, os +import sys, os, cgi from MoinMoin import config from MoinMoin.request import RequestBase @@ -30,12 +30,11 @@ except Exception, err: self.fail(err) - def setup_args(self, form=None): + def setup_args(self): # TODO: does this include query_string args for POST requests? # see also how CGI works now - if form is None: - form = cgi.FieldStorage(fp=self.stdin, environ=self.env, keep_blank_values=1) - return self._setup_args_from_cgi_form(form) + form = cgi.FieldStorage(fp=self.stdin, environ=self.env, keep_blank_values=1) + return RequestBase._setup_args_from_cgi_form(self, form) def read(self, n=None): if n is None:
--- a/MoinMoin/request/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/request/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -141,11 +141,13 @@ # # no extra path after script name # rootname = u"" - self.args = {} - self.form = {} - - if not self.query_string.startswith('action=xmlrpc'): + if self.query_string.startswith('action=xmlrpc'): + self.args = {} + self.form = {} + self.action = 'xmlrpc' + else: self.args = self.form = self.setup_args() + self.action = self.form.get('action', ['show'])[0] rootname = u'' self.rootpage = Page(self, rootname, is_rootpage=1) @@ -156,7 +158,7 @@ self.user = self.get_user_from_form() - if not self.query_string.startswith('action=xmlrpc'): + if self.action != 'xmlrpc': if not self.forbidden and self.isForbidden(): self.makeForbidden403() if not self.forbidden and self.surge_protect(): @@ -181,7 +183,7 @@ current_id = validuser and self.user.name or self.remote_addr if not validuser and current_id.startswith('127.'): # localnet return False - current_action = self.form.get('action', ['show'])[0] + current_action = self.action limits = self.cfg.surge_action_limits default_limit = self.cfg.surge_action_limits.get('default', (30, 60)) @@ -263,7 +265,7 @@ def _load_multi_cfg(self): # protect against calling multiple times if not hasattr(self, 'cfg'): - from MoinMoin import multiconfig + from MoinMoin.config import multiconfig self.cfg = multiconfig.getConfig(self.url) def setAcceptedCharsets(self, accept_charset): @@ -544,7 +546,6 @@ # during the rendering of a page by lang macros self.current_lang = self.cfg.language_default - self._all_pages = None # caches unique ids self._page_ids = {} # keeps track of pagename/heading combinations @@ -863,11 +864,12 @@ forbidden = 0 # we do not have a parsed query string here, so we can just do simple matching qs = self.query_string + action = self.action if ((qs != '' or self.request_method != 'GET') and - not 'action=rss_rc' in qs and + action != 'rss_rc' and # allow spiders to get attachments and do 'show' - not ('action=AttachFile' in qs and 'do=get' in qs) and - not 'action=show' in qs + not (action == 'AttachFile' and 'do=get' in qs) and + action != 'show' ): forbidden = self.isSpiderAgent @@ -884,40 +886,33 @@ break return forbidden - def setup_args(self, form=None): + def setup_args(self): """ Return args dict First, we parse the query string (usually this is used in GET methods, but TwikiDraw uses ?action=AttachFile&do=savedrawing plus posted stuff). Second, we update what we got in first step by the stuff we get from the form (or by a POST). We invoke _setup_args_from_cgi_form to handle possible file uploads. - - Warning: calling with a form might fail, depending on the type of the - request! Only the request knows which kind of form it can handle. - - TODO: The form argument should be removed in 1.5. """ args = cgi.parse_qs(self.query_string, keep_blank_values=1) args = self.decodeArgs(args) - # if we have form data (e.g. in a POST), those override the stuff we already have: - if form is not None or self.request_method == 'POST': - postargs = self._setup_args_from_cgi_form(form) + # if we have form data (in a POST), those override the stuff we already have: + if self.request_method == 'POST': + postargs = self._setup_args_from_cgi_form() args.update(postargs) return args def _setup_args_from_cgi_form(self, form=None): """ Return args dict from a FieldStorage - - Create the args from a standard cgi.FieldStorage or from given form. - Each key contain a list of values. + + Create the args from a given form. Each key contain a list of values. + This method usually gets overridden in classes derived from this - it + is their task to call this method with an appropriate form parameter. @param form: a cgi.FieldStorage @rtype: dict @return: dict with form keys, each contains a list of values """ - if form is None: - form = cgi.FieldStorage() - args = {} for key in form: values = form[key] @@ -1028,22 +1023,19 @@ self.html_formatter = Formatter(self) self.formatter = self.html_formatter - if self.query_string == 'action=xmlrpc': + action_name = self.action + if action_name == 'xmlrpc': from MoinMoin import xmlrpc - xmlrpc.xmlrpc(self) - return self.finish() - - if self.query_string == 'action=xmlrpc2': - from MoinMoin import xmlrpc - xmlrpc.xmlrpc2(self) + if self.query_string == 'action=xmlrpc': + xmlrpc.xmlrpc(self) + elif self.query_string == 'action=xmlrpc2': + xmlrpc.xmlrpc2(self) return self.finish() # parse request data try: self.initTheme() - action_name = self.form.get('action', ['show'])[0] - # The last component in path_info is the page name, if any path = self.getPathinfo() if path.startswith('/'): @@ -1098,18 +1090,21 @@ else: self.page = Page(self, pagename) + msg = None # Complain about unknown actions if not action_name in self.getKnownActions(): - self.http_headers() - self.write(u'<html><body><h1>Unknown action %s</h1></body>' % wikiutil.escape(action_name)) + msg = _("Unknown action %(action_name)s.") % { + 'action_name': wikiutil.escape(action_name), } # Disallow non available actions elif action_name[0].isupper() and not action_name in self.getAvailableActions(self.page): - # Send page with error - msg = _("You are not allowed to do %s on this page.") % wikiutil.escape(action_name) + msg = _("You are not allowed to do %(action_name)s on this page.") % { + 'action_name': wikiutil.escape(action_name), } if not self.user.valid: # Suggest non valid user to login msg += " " + _("Login and try again.", formatted=0) + + if msg: self.page.send_page(self, msg=msg) # Try action
--- a/MoinMoin/script/cli/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/script/cli/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -1,6 +1,6 @@ # -*- coding: iso-8859-1 -*- """ - MoinMoin - Migration Script Package + MoinMoin - CLI usage Script Package @copyright: 2006 by Thomas Waldmann @license: GNU GPL, see COPYING for details. @@ -9,6 +9,6 @@ from MoinMoin.util import pysupport # create a list of extension scripts from the subpackage directory -migration_scripts = pysupport.getPackageModules(__file__) -modules = migration_scripts +cli_scripts = pysupport.getPackageModules(__file__) +modules = cli_scripts
--- a/MoinMoin/stats/hitcounts.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/stats/hitcounts.py Mon Jul 24 22:18:49 2006 +0200 @@ -47,16 +47,17 @@ def get_data(pagename, request, filterpage=None): + cache_days, cache_views, cache_edits = [], [], [] + cache_date = 0 # Get results from cache if filterpage: arena = Page(request, pagename) + cache = caching.CacheEntry(request, arena, 'hitcounts', scope='item') else: arena = 'charts' + cache = caching.CacheEntry(request, arena, 'hitcounts', scope='wiki') - cache_days, cache_views, cache_edits = [], [], [] - cache_date = 0 - cache = caching.CacheEntry(request, arena, 'hitcounts', scope='wiki') if cache.exists(): try: cache_date, cache_days, cache_views, cache_edits = eval(cache.content())
--- a/MoinMoin/theme/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/theme/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -20,9 +20,9 @@ use without rewriting the same code. If you want to change certain elements, override them. """ - + name = 'base' - + # fake _ function to get gettext recognize those texts: _ = lambda x: x @@ -64,7 +64,7 @@ # search forms 'searchbutton': ("[?]", "moin-search.png", 12, 12), 'interwiki': ("[%(wikitag)s]", "moin-inter.png", 16, 16), - + # smileys (this is CONTENT, but good looking smileys depend on looking # adapted to the theme background color and theme style in general) #vvv == vvv this must be the same for GUI editor converter @@ -86,7 +86,7 @@ ':\\': (":\\", 'ohwell.png', 15, 15), '>:>': (">:>", 'devil.png', 15, 15), '|)': ("|)", 'tired.png', 15, 15), - + # some folks use noses in their emoticons ':-(': (":-(", 'sad.png', 15, 15), ':-)': (":-)", 'smile.png', 15, 15), @@ -94,7 +94,7 @@ ':-))': (":-))", 'smile3.png', 15, 15), ';-)': (";-)", 'smile4.png', 15, 15), '|-)': ("|-)", 'tired.png', 15, 15), - + # version 1.0 '(./)': ("(./)", 'checkmark.png', 20, 15), '{OK}': ("{OK}", 'thumbs-up.png', 14, 12), @@ -135,7 +135,7 @@ # media basename ('all', 'common'), ('all', 'projection'), - ) + ) stylesheetsCharset = 'utf-8' @@ -157,7 +157,7 @@ @return: the image href """ return "%s/%s/img/%s" % (self.cfg.url_prefix, self.name, img) - + def emit_custom_html(self, html): """ generate custom HTML code in `html` @@ -196,15 +196,15 @@ @rtype: string @return: interwiki html """ - html = u'' if self.request.cfg.show_interwiki: - # Show our interwikiname or Self (and link to page_front_page) - pagename = wikiutil.getFrontPage(self.request).page_name - pagename = wikiutil.quoteWikinameURL(pagename) - link = wikiutil.link_tag(self.request, pagename, self.request.cfg.interwikiname or 'Self') + page = wikiutil.getFrontPage(self.request) + text = self.request.cfg.interwikiname or 'Self' + link = page.link_to(self.request, text=text, rel='nofollow') html = u'<div id="interwiki"><span>%s</span></div>' % link + else: + html = u'' return html - + def title(self, d): """ Assemble the title (now using breadcrumbs) @@ -246,7 +246,7 @@ """ request = self.request _ = request.getText - + userlinks = [] # Add username/homepage link for registered users. We don't care # if it exists, the user can create it. @@ -261,11 +261,11 @@ homelink = (request.formatter.interwikilink(1, title=title, id="userhome", *interwiki) + request.formatter.text(name) + request.formatter.interwikilink(0, title=title, id="userhome", *interwiki)) - userlinks.append(homelink) + userlinks.append(homelink) # link to userprefs action userlinks.append(d['page'].link_to(request, text=_('Preferences'), querystr={'action': 'userprefs'}, id='userprefs', rel='nofollow')) - + if request.cfg.show_login: if request.user.valid: userlinks.append(d['page'].link_to(request, text=_('Logout', formatted=False), @@ -295,7 +295,7 @@ @return: pagename or url, link to page or url """ request = self.request - + # Handle [pagename title] or [url title] formats if text.startswith('[') and text.endswith(']'): try: @@ -343,10 +343,10 @@ page + self.request.formatter.interwikilink(False, interwiki, page) ) - + except ValueError: pass - + pagename = request.normalizePagename(pagename) link = Page(request, pagename).link_to(request, title) @@ -375,10 +375,10 @@ half, left = divmod(maxLength - 3, 2) name = u'%s...%s' % (name[:half + left], name[-half:]) return name - + def maxPagenameLength(self): """ Return maximum length for shortened page names """ - return 25 + return 25 def navibar(self, d): """ Assemble the navibar @@ -461,9 +461,9 @@ alt, icon, w, h = self.iconsByFile[icon] else: alt, icon, w, h = '', icon, '', '' - + return alt, self.img_url(icon), w, h - + def make_icon(self, icon, vars=None): """ This is the central routine for making <img> tags for icons! @@ -527,13 +527,13 @@ close = d['page'].link_to(self.request, text=_('Clear message'), querystr={'action': 'show'}) - html = u'<p>%s</p>\n<div class="buttons">%s</div>\n' % (msg, close) + html = u'<p>%s</p>\n<div class="buttons">%s</div>\n' % (msg, close) else: # msg is a widget html = msg.render() return u'<div id="message">\n%s\n</div>\n' % html - + def trail(self, d): """ Assemble page trail @@ -559,7 +559,7 @@ continue else: pagename = page - + except ValueError: pass page = Page(request, pagename) @@ -606,9 +606,10 @@ for media, csshref in self.request.cfg.stylesheets: html.append(link % (self.stylesheetsCharset, media, csshref)) - + # tribute to the most sucking browser... - if self.cfg.hacks.get('ie7', False): + if self.cfg.hacks.get('ie7', False) and self.request.action != 'edit': + # using FCKeditor and IE7 at the same time makes nices crashes in IE html.append(""" <!-- compliance patch for microsoft browsers --> <!--[if lt IE 7]> @@ -619,7 +620,7 @@ # Add user css url (assuming that user css uses same charset) if usercss and usercss.lower() != "none": html.append(link % (self.stylesheetsCharset, 'all', usercss)) - + return '\n'.join(html) def shouldShowPageinfo(self, page): @@ -640,10 +641,9 @@ contentActions = [u'', u'show', u'refresh', u'preview', u'diff', u'subscribe', u'RenamePage', u'DeletePage', u'SpellCheck', u'print'] - action = self.request.form.get('action', [''])[0] - return action in contentActions + return self.request.action in contentActions return False - + def pageinfo(self, page): """ Return html fragment with page meta data @@ -673,7 +673,7 @@ 'info': info } return html - + def searchform(self, d): """ assemble HTML code for the search forms @@ -685,10 +685,10 @@ _ = self.request.getText form = self.request.form updates = { - 'search_label' : _('Search:'), + 'search_label': _('Search:'), 'search_value': wikiutil.escape(form.get('value', [''])[0], 1), - 'search_full_label' : _('Text', formatted=False), - 'search_title_label' : _('Titles', formatted=False), + 'search_full_label': _('Text', formatted=False), + 'search_title_label': _('Titles', formatted=False), } d.update(updates) @@ -732,7 +732,7 @@ html = (u'<div id="version">MoinMoin Release %s [Revision %s], ' 'Copyright 2000-2006 by Juergen Hermann</div>') % (version.release, version.revision, ) return html - + def headscript(self, d): """ Return html head script with common functions @@ -747,9 +747,9 @@ @return: script for html head """ # Don't add script for print view - if self.request.form.get('action', [''])[0] == 'print': + if self.request.action == 'print': return u'' - + _ = self.request.getText script = u""" <script type=\"text/javascript\"> @@ -820,10 +820,10 @@ //--> </script> """ % { - 'search_hint' : _('Search', formatted=False), + 'search_hint': _('Search', formatted=False), } return script - + def shouldUseRSS(self): """ Return True if rss feature is available, or False @@ -837,16 +837,16 @@ except ImportError: # This error reported on Python 2.2 return False - + def rsshref(self): """ Create rss href, used for rss button and head link @rtype: unicode @return: rss href """ - return (u'%s/RecentChanges?action=rss_rc&ddiffs=1&unique=1' + return (u'%s/RecentChanges?action=rss_rc&ddiffs=1&unique=1' % self.request.getScriptname()) - + def rsslink(self): """ Create rss link in head, used by FireFox @@ -863,7 +863,7 @@ self.cfg.sitename, self.rsshref() ) return link - + def html_head(self, d): """ Assemble html head @@ -917,7 +917,7 @@ """ request = self.request _ = request.getText - + menu = [ 'raw', 'print', @@ -964,7 +964,7 @@ # "disabled", e.g IE, Safari # for XHTML: data['disabled'] = ' disabled="disabled"' disabled = ' disabled class="disabled"' - + # Format standard actions available = request.getAvailableActions(page) for action in menu: @@ -984,7 +984,7 @@ # Actions which are not available for this wiki, user or page if (action == '__separator__' or (action[0].isupper() and not action in available)): - data['disabled'] = disabled + data['disabled'] = disabled options.append(option % data) @@ -1034,9 +1034,9 @@ </script> </form> ''' % data - - return html - + + return html + def editbar(self, d): """ Assemble the page edit bar. @@ -1057,7 +1057,7 @@ for item in self.editbarItems(page) if item]) html = u'<ul class="editbar">%s</ul>\n' % items self._cache['editbar'] = html - + return html def shouldShowEditbar(self, page): @@ -1077,7 +1077,7 @@ if (page.exists(includeDeleted=1) and self.request.user.may.read(page.page_name)): form = self.request.form - action = form.get('action', [''])[0] + action = self.request.action # Do not show editbar on edit but on save/cancel return not (action == 'edit' and not form.has_key('button_save') and @@ -1095,7 +1095,8 @@ self.subscribeLink(page), self.quicklinkLink(page), self.attachmentsLink(page), - self.actionsMenu(page),] + self.actionsMenu(page), + ] def guiworks(self, page): """ Return whether the gui editor / converter can work for that page. @@ -1103,7 +1104,7 @@ The GUI editor currently only works for wiki format. """ return page.pi_format == 'wiki' - + def editorLink(self, page): """ Return a link to the editor @@ -1115,27 +1116,26 @@ if not (page.isWritable() and self.request.user.may.write(page.page_name)): return self.disabledEdit() - + _ = self.request.getText - params = (wikiutil.quoteWikinameURL(page.page_name) + - '?action=edit&editor=') - + querystr = {'action': 'edit'} + guiworks = self.guiworks(page) if self.showBothEditLinks() and guiworks: text = _('Edit (Text)', formatted=False) - params = params + 'text' + querystr['editor'] = 'text' attrs = {'name': 'texteditlink', 'rel': 'nofollow', } else: text = _('Edit', formatted=False) if guiworks: # 'textonly' will be upgraded dynamically to 'guipossible' by JS - params = params + 'textonly' + querystr['editor'] = 'textonly' attrs = {'name': 'editlink', 'rel': 'nofollow', } else: - params = params + 'text' + querystr['editor'] = 'text' attrs = {'name': 'texteditlink', 'rel': 'nofollow', } - - return wikiutil.link_tag(self.request, params, text, **attrs) + + return page.link_to(self.request, text=text, querystr=querystr, **attrs) def showBothEditLinks(self): """ Return True if both edit links should be displayed """ @@ -1164,21 +1164,22 @@ var gui_editor_link_text = "%(text)s"; </script> """ % {'url': page.url(self.request), - 'text': _('Edit (GUI)', formatted=False),} + 'text': _('Edit (GUI)', formatted=False), + } def disabledEdit(self): """ Return a disabled edit link """ _ = self.request.getText - return ('<span class="disabled">%s</span>' + return ('<span class="disabled">%s</span>' % _('Immutable Page', formatted=False)) - + def infoLink(self, page): """ Return link to page information """ _ = self.request.getText return page.link_to(self.request, - text=_('Info', formatted=False), - querystr='action=info', rel='nofollow') - + text=_('Info', formatted=False), + querystr={'action': 'info'}, id='info', rel='nofollow') + def subscribeLink(self, page): """ Return subscribe/unsubscribe link to valid users @@ -1187,14 +1188,13 @@ """ if not (self.cfg.mail_enabled and self.request.user.valid): return '' - + _ = self.request.getText if self.request.user.isSubscribedTo([page.page_name]): text = _("Unsubscribe", formatted=False) else: text = _("Subscribe", formatted=False) - params = wikiutil.quoteWikinameURL(page.page_name) + '?action=subscribe' - return wikiutil.link_tag(self.request, params, text, self.request.formatter, rel='nofollow') + return page.link_to(self.request, text=text, querystr={'action': 'subscribe'}, id='subscribe', rel='nofollow') def quicklinkLink(self, page): """ Return add/remove quicklink link @@ -1204,21 +1204,20 @@ """ if not self.request.user.valid: return '' - + _ = self.request.getText if self.request.user.isQuickLinkedTo([page.page_name]): text = _("Remove Link", formatted=False) else: text = _("Add Link", formatted=False) - params = wikiutil.quoteWikinameURL(page.page_name) + '?action=quicklink' - return wikiutil.link_tag(self.request, params, text, self.request.formatter, rel='nofollow') + return page.link_to(self.request, text=text, querystr={'action': 'quicklink'}, id='quicklink', rel='nofollow') def attachmentsLink(self, page): """ Return link to page attachments """ _ = self.request.getText return page.link_to(self.request, - text=_('Attachments', formatted=False), - querystr='action=AttachFile', rel='nofollow') + text=_('Attachments', formatted=False), + querystr={'action': 'AttachFile'}, id='attachments', rel='nofollow') def startPage(self): """ Start page div with page language and direction @@ -1227,15 +1226,15 @@ @return: page div with language and direction attribtues """ return u'<div id="page"%s>\n' % self.content_lang_attr() - + def endPage(self): """ End page div Add an empty page bottom div to prevent floating elements to float out of the page bottom over the footer. """ - return '<div id="pagebottom"></div>\n</div>\n' - + return '<div id="pagebottom"></div>\n</div>\n' + # Public functions ##################################################### def header(self, d, **kw): @@ -1249,9 +1248,9 @@ @return: page header html """ return self.startPage() - + editorheader = header - + def footer(self, d, **keywords): """ Assemble page footer @@ -1278,40 +1277,40 @@ _ = self.request.getText html = [] html.append('<tr>\n') - + html.append('<td class="rcicon1">%(icon_html)s</td>\n' % d) - + html.append('<td class="rcpagelink">%(pagelink_html)s</td>\n' % d) - + html.append('<td class="rctime">') if d['time_html']: html.append("%(time_html)s" % d) html.append('</td>\n') html.append('<td class="rcicon2">%(info_html)s</td>\n' % d) - + html.append('<td class="rceditor">') if d['editors']: html.append('<br>'.join(d['editors'])) html.append('</td>\n') - + html.append('<td class="rccomment">') if d['comments']: if d['changecount'] > 1: notfirst = 0 for comment in d['comments']: html.append('%s<tt>#%02d</tt> %s' % ( - notfirst and '<br>' or '' , comment[0], comment[1])) + notfirst and '<br>' or '', comment[0], comment[1])) notfirst = 1 else: comment = d['comments'][0] html.append('%s' % comment[1]) html.append('</td>\n') - + html.append('</tr>\n') - + return ''.join(html) - + def recentchanges_daybreak(self, d): """ Assemble a rc daybreak indication (table row) @@ -1338,7 +1337,7 @@ @return: recentchanges header html """ _ = self.request.getText - + # Should use user interface language and direction html = '<div class="recentchanges"%s>\n' % self.ui_lang_attr() html += '<div>\n' @@ -1366,7 +1365,7 @@ self.request.formatter, rel='nofollow')) days = ' | '.join(days) html += (_("Show %s days.") % (days,)) - + if d['rc_update_bookmark']: html += " %(rc_update_bookmark)s %(rc_curr_bookmark)s" % d @@ -1392,7 +1391,7 @@ return html # Language stuff #################################################### - + def ui_lang_attr(self): """Generate language attributes for user interface elements @@ -1439,14 +1438,14 @@ """ request = self.request _ = request.getText - + if keywords.has_key('page'): page = keywords['page'] pagename = page.page_name else: pagename = keywords.get('pagename', '') page = Page(request, pagename) - + scriptname = request.getScriptname() pagename_quoted = wikiutil.quoteWikinameURL(pagename) @@ -1461,7 +1460,7 @@ page_find_page = wikiutil.getSysPage(request, 'FindPage').page_name home_page = wikiutil.getInterwikiHomePage(request) # XXX sorry theme API change!!! Either None or tuple (wikiname,pagename) now. page_parent_page = getattr(page.getParentPage(), 'page_name', None) - + # Prepare the HTML <head> element user_head = [request.cfg.html_head] @@ -1492,7 +1491,7 @@ page_title_index, 'TitleIndex', page_find_page, 'FindPage', page_site_navigation, 'SiteNavigation', - 'RecentChanges',]: + 'RecentChanges', ]: user_head.append(request.cfg.html_head_index) # if it is a normal page, index it, but do not follow the links, because # there are a lot of illegal links (like actions) or duplicates: @@ -1501,7 +1500,7 @@ if keywords.has_key('pi_refresh') and keywords['pi_refresh']: user_head.append('<meta http-equiv="refresh" content="%(delay)d;URL=%(url)s">' % keywords['pi_refresh']) - + # output buffering increases latency but increases throughput as well output = [] # later: <html xmlns=\"http://www.w3.org/1999/xhtml\"> @@ -1566,7 +1565,7 @@ '<link rel="Glossary" href="%s/%s">\n' % (scriptname, wikiutil.quoteWikinameURL(page_word_index)), '<link rel="Help" href="%s/%s">\n' % (scriptname, wikiutil.quoteWikinameURL(page_help_formatting)), ]) - + output.append("</head>\n") request.write(''.join(output)) output = [] @@ -1590,7 +1589,7 @@ # Set body to the user interface language and direction bodyattr.append(' %s' % self.ui_lang_attr()) - + body_onload = keywords.get('body_onload', '') if body_onload: bodyattr.append(''' onload="%s"''' % body_onload) @@ -1600,11 +1599,11 @@ # If in print mode, start page div and emit the title if keywords.get('print_mode', 0): - d = {'title_text': text, 'title_link': None, 'page': page,} + d = {'title_text': text, 'title_link': None, 'page': page, } request.themedict = d output.append(self.startPage()) - output.append(self.interwiki(d)) - output.append(self.title(d)) + output.append(self.interwiki(d)) + output.append(self.title(d)) # In standard mode, emit theme.header else: @@ -1657,7 +1656,7 @@ output.append(self.editorheader(d)) else: output.append(self.header(d)) - + # emit it request.write(''.join(output)) output = [] @@ -1693,8 +1692,7 @@ request.clock.stop('total') # Close html code - if (request.cfg.show_timings and - request.form.get('action', [None])[0] != 'print'): + if request.cfg.show_timings and request.action != 'print': request.write('<ul id="timings">\n') for t in request.clock.dump(): request.write('<li>%s</li>\n' % t)
--- a/MoinMoin/theme/classic.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/theme/classic.py Mon Jul 24 22:18:49 2006 +0200 @@ -8,7 +8,7 @@ If you want modified behaviour, just override the stuff you want to change in the child class. - @copyright: 2003 by ThomasWaldmann (LinuxWiki:ThomasWaldmann) + @copyright: 2003-2006 by MoinMoin:ThomasWaldmann @license: GNU GPL, see COPYING for details. """ @@ -22,7 +22,7 @@ """ here are the functions generating the html responsible for the look and feel of your wiki site """ - + name = "classic" def footer(self, d, **keywords): @@ -45,9 +45,9 @@ self.editbar(d, **keywords), self.credits(d), self.showversion(d, **keywords), - + # Post footer custom html - self.emit_custom_html(self.cfg.page_footer2),] + self.emit_custom_html(self.cfg.page_footer2), ] return u'\n'.join(parts) def editbar(self, d, **keywords): @@ -56,7 +56,7 @@ parts = [u'<div id="footer">', self.edit_link(d, **keywords), self.availableactions(d), - u'</div>',] + u'</div>', ] return ''.join(parts) def iconbar(self, d): @@ -82,7 +82,7 @@ iconbar.append('<li>%s</li>\n' % self.make_iconlink(icon, d)) iconbar.append('</ul>\n') return ''.join(iconbar) - + def header(self, d): """ Assemble page header @@ -95,10 +95,10 @@ 'config_header1_html': self.emit_custom_html(self.cfg.page_header1), 'config_header2_html': self.emit_custom_html(self.cfg.page_header2), 'search_form_html': self.searchform(d), - 'logo_html': self.logo(), - 'interwiki_html': self.interwiki(d), - 'title_html': self.title(d), - 'username_html': self.username(d), + 'logo_html': self.logo(), + 'interwiki_html': self.interwiki(d), + 'title_html': self.title(d), + 'username_html': self.username(d), 'navibar_html': self.navibar(d), 'iconbar_html': self.iconbar(d), 'msg_html': self.msg(d), @@ -160,7 +160,7 @@ return html # Footer stuff ####################################################### - + def edit_link(self, d, **keywords): """ Assemble EditText link (or indication that page cannot be edited) @@ -172,7 +172,7 @@ page = d['page'] return u'<ul class="editbar"><li>%s</li></ul>' % self.editorLink(page) - def availableactions(self, d): + def availableactions(self, d): """ assemble HTML code for the available actions @@ -194,14 +194,12 @@ title = Page(request, action).split_title(request, force=1) # Use translated version if available title = _(title, formatted=False) - params = '%s?action=%s' % (d['q_page_name'], action) - link = wikiutil.link_tag(request, params, title, request.formatter, rel='nofollow') + link = page.link_to(request, text=title, querystr={'action': action}, rel='nofollow') html.append(link) - + title = _("DeleteCache", formatted=False) - params = '%s?action=%s' % (d['page_name'], 'refresh') - link = wikiutil.link_tag(request, params, title, request.formatter, rel='nofollow') - + link = page.link_to(request, text=title, querystr={'action': 'refresh'}, rel='nofollow') + cache = caching.CacheEntry(request, page, page.getFormatterName(), scope='item') date = request.user.getFormattedDateTime(cache.mtime()) deletecache = u'<p>%s %s</p>' % (link, _('(cached %s)') % date)
--- a/MoinMoin/theme/modern.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/theme/modern.py Mon Jul 24 22:18:49 2006 +0200 @@ -22,7 +22,7 @@ html = [ # Pre header custom html self.emit_custom_html(self.cfg.page_header1), - + # Header u'<div id="header">', self.logo(), @@ -39,10 +39,10 @@ self.msg(d), self.editbar(d), u'</div>', - + # Post header custom html (not recommended) self.emit_custom_html(self.cfg.page_header2), - + # Start of page self.startPage(), ] @@ -58,16 +58,16 @@ html = [ # Pre header custom html self.emit_custom_html(self.cfg.page_header1), - + # Header u'<div id="header">', self.title(d), self.msg(d), u'</div>', - + # Post header custom html (not recommended) self.emit_custom_html(self.cfg.page_header2), - + # Start of page self.startPage(), ] @@ -86,23 +86,23 @@ # End of page self.pageinfo(page), self.endPage(), - + # Pre footer custom html (not recommended!) self.emit_custom_html(self.cfg.page_footer1), - + # Footer u'<div id="footer">', self.editbar(d), self.credits(d), self.showversion(d, **keywords), u'</div>', - + # Post footer custom html self.emit_custom_html(self.cfg.page_footer2), ] return u'\n'.join(html) - + def execute(request): """ Generate and return a theme object
--- a/MoinMoin/theme/rightsidebar.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/theme/rightsidebar.py Mon Jul 24 22:18:49 2006 +0200 @@ -25,7 +25,7 @@ u'</div>', ] return u'\n'.join(html) - + def pagepanel(self, d): """ Create page panel """ _ = self.request.getText @@ -37,15 +37,15 @@ u'</div>', ] return u'\n'.join(html) - return '' - + return '' + def userpanel(self, d): """ Create user panel """ _ = self.request.getText html = [ u'<div class="sidepanel">', - u'<h1>%s</h1>' % _("User"), + u'<h1>%s</h1>' % _("User"), self.username(d), u'</div>' ] @@ -75,7 +75,7 @@ u'</div>', self.trail(d), u'</div>', - + # Custom html below header (not recomended!) self.emit_custom_html(self.cfg.page_header2), @@ -87,12 +87,12 @@ u'</div>', self.msg(d), - + # Page self.startPage(), ] return u'\n'.join(html) - + def editorheader(self, d): """ Assemble page header for editor @@ -112,7 +112,7 @@ #self.searchform(d), #self.logo(), #u'</div>', - + # Custom html below header (not recomended!) self.emit_custom_html(self.cfg.page_header2), @@ -124,13 +124,13 @@ u'</div>', self.msg(d), - + # Page self.startPage(), #self.title(d), ] return u'\n'.join(html) - + def footer(self, d, **keywords): """ Assemble wiki footer @@ -144,16 +144,16 @@ # End of page self.pageinfo(page), self.endPage(), - + # Pre footer custom html (not recommended!) self.emit_custom_html(self.cfg.page_footer1), - + # Footer u'<div id="footer">', self.credits(d), self.showversion(d, **keywords), u'</div>', - + # Post footer custom html self.emit_custom_html(self.cfg.page_footer2), ]
--- a/MoinMoin/user.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/user.py Mon Jul 24 22:18:49 2006 +0200 @@ -119,7 +119,7 @@ pwd = '{SHA}' + base64.encodestring(pwd).rstrip() return pwd - + def normalizeName(name): """ Make normalized user name @@ -148,7 +148,7 @@ return name - + def isValidName(request, name): """ Validate user name @@ -173,7 +173,7 @@ if not item: continue line.append(item) - + line = '\t'.join(line) return line @@ -193,7 +193,7 @@ items.append(item) return items - + class User: """A MoinMoin User""" @@ -220,7 +220,7 @@ self.auth_username = auth_username self.auth_method = kw.get('auth_method', 'internal') self.auth_attribs = kw.get('auth_attribs', ()) - + # create some vars automatically self.__dict__.update(self._cfg.user_form_defaults) @@ -254,7 +254,7 @@ self.editor_default = self._cfg.editor_default self.editor_ui = self._cfg.editor_ui self.last_saved = str(time.time()) - + # attrs not saved to profile self._request = request self._trail = [] @@ -284,7 +284,7 @@ else: from security import Default self.may = Default(self) - + if self.language and not self.language in i18n.wikiLanguages(): self.language = 'en' @@ -299,7 +299,7 @@ # and some other things identifying remote users, then we could also # use it reliably in edit locking from random import randint - return "%s.%d" % (str(time.time()), randint(0,65535)) + return "%s.%d" % (str(time.time()), randint(0, 65535)) def create_or_update(self, changed=False): """ Create or update a user profile @@ -309,7 +309,7 @@ if self._cfg.user_autocreate: if not self.valid and not self.disabled or changed: # do we need to save/update? self.save() # yes, create/update user profile - + def __filename(self): """ Get filename of the user's file on disk @@ -373,7 +373,7 @@ return # Check for a valid password, possibly changing encoding valid, changed = self._validatePassword(user_data) - if not valid: + if not valid: return else: self.trusted = 1 @@ -395,7 +395,7 @@ if hasattr(self, attr): delattr(self, attr) changed = 1 - + # make sure checkboxes are boolean for key, label in self._cfg.user_checkbox_fields: try: @@ -458,12 +458,12 @@ # Get the clear text password from the form (require non empty # password) - password = self._request.form.get('password',[None])[0] + password = self._request.form.get('password', [None])[0] if not password: - return False, False - + return False, False + # First get all available pre13 charsets on this system - pre13 = ['iso-8859-1', 'iso-8859-2', 'euc-jp', 'gb2312', 'big5',] + pre13 = ['iso-8859-1', 'iso-8859-2', 'euc-jp', 'gb2312', 'big5', ] available = [] for charset in pre13: try: @@ -471,7 +471,7 @@ available.append(charset) except LookupError: pass # missing on this system - + # Now try to match the password for charset in available: # Try to encode, failure is expected @@ -506,7 +506,7 @@ # !!! should write to a temp file here to avoid race conditions, # or even better, use locking - + data = codecs.open(self.__filename(), "w", config.charset) data.write("# Data saved '%s' for id '%s'\n" % ( time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())), @@ -624,7 +624,7 @@ @return: pages this user has subscribed to """ return self.subscribed_pages - + def isSubscribedTo(self, pagelist): """ Check if user subscription matches any page in pagelist. @@ -640,15 +640,15 @@ """ if not self.valid: return False - - import re + + import re # Create a new list with both names and interwiki names. pages = pagelist[:] if self._cfg.interwikiname: pages += [self._interWikiName(pagename) for pagename in pagelist] # Create text for regular expression search text = '\n'.join(pages) - + for pattern in self.getSubscriptionList(): # Try simple match first if pattern in pages: @@ -673,15 +673,15 @@ @type pagename: unicode @rtype: bool @return: if page was subscribed - """ + """ if self._cfg.interwikiname: pagename = self._interWikiName(pagename) - + if pagename not in self.subscribed_pages: self.subscribed_pages.append(pagename) self.save() return True - + return False def unsubscribe(self, pagename): @@ -710,16 +710,16 @@ if pagename in self.subscribed_pages: self.subscribed_pages.remove(pagename) changed = True - - interWikiName = self._interWikiName(pagename) + + interWikiName = self._interWikiName(pagename) if interWikiName and interWikiName in self.subscribed_pages: self.subscribed_pages.remove(interWikiName) changed = True - + if changed: self.save() return not self.isSubscribedTo([pagename]) - + # ----------------------------------------------------------------- # Quicklinks @@ -740,14 +740,14 @@ """ if not self.valid: return False - + for pagename in pagelist: if pagename in self.quicklinks: return True interWikiName = self._interWikiName(pagename) if interWikiName and interWikiName in self.quicklinks: return True - + return False def addQuicklink(self, pagename): @@ -796,8 +796,8 @@ changed = True if pagename in self.quicklinks: self.quicklinks.remove(pagename) - changed = True - + changed = True + if changed: self.save() return changed @@ -810,7 +810,7 @@ """ if not self._cfg.interwikiname: return None - + return "%s:%s" % (self._cfg.interwikiname, pagename) # ----------------------------------------------------------------- @@ -826,7 +826,7 @@ if self.valid and (self.show_page_trail or self.remember_last_visit): # load trail if not known - self.getTrail() + self.getTrail() # Add only existing pages that the user may read if self._request: @@ -851,7 +851,7 @@ self.saveTrail() # TODO: release lock here - + def saveTrail(self): """ Save trail file @@ -924,7 +924,7 @@ """ if not self.name: return self.host() - + wikiname, pagename = wikiutil.getInterwikiHomePage(self._request, self.name) if wikiname == 'Self': @@ -933,7 +933,7 @@ else: markup = pagename else: - markup = '%s:%s' % (wikiname, pagename) + markup = '%s:%s' % (wikiname, pagename) return markup def mailAccountData(self, cleartext_passwd=None): @@ -944,14 +944,14 @@ if not self.enc_password: # generate pw if there is none yet from random import randint import base64 - + charset = 'utf-8' pwd = "%s%d" % (str(time.time()), randint(0, 65535)) pwd = pwd.encode(charset) pwd = sha.new(pwd).digest() pwd = '{SHA}%s' % base64.encodestring(pwd).rstrip() - + self.enc_password = pwd self.save()
--- a/MoinMoin/util/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -31,7 +31,7 @@ """ new_string, num_subst = re.subn(g_undoUtf8Pattern, lambda m: m.group(1), text) new_string, num_subst = re.subn(g_cdataCharPattern, lambda m, d=g_charToEntity: d[m.group()], new_string) - new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#x%02X;'%ord(m.group()), new_string) + new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#x%02X;' % ord(m.group()), new_string) return new_string def TranslateText(text): @@ -41,7 +41,7 @@ """ new_string, num_subst = re.subn(g_undoUtf8Pattern, lambda m: m.group(1), text) new_string, num_subst = re.subn(g_textCharPattern, lambda m, d=g_charToEntity: d[m.group()], new_string) - new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#x%02X;'%ord(m.group()), new_string) + new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#x%02X;' % ord(m.group()), new_string) return new_string @@ -79,7 +79,7 @@ result = '<dt><strong>Form entries</strong></dt>' for k in form.keys(): v = form.get(k, ["<empty>"]) - v = "|".join(v) + v = "|".join(v) result = result + '<dd><em>%s</em>=%s</dd>' % (k, wikiutil.escape(v)) return result @@ -100,12 +100,12 @@ def __init__(self): self.buffer = [] - + def write(self, foo): if not isinstance(foo, unicode): foo = foo.decode("iso-8859-1", "replace") self.buffer.append(foo) - + def getvalue(self): return u''.join(self.buffer)
--- a/MoinMoin/util/bdiff.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/bdiff.py Mon Jul 24 22:18:49 2006 +0200 @@ -30,17 +30,17 @@ bin = [] la = lb = 0 - + p = [0] for i in a: p.append(p[-1] + len(i)) - + for am, bm, size in difflib.SequenceMatcher(None, a, b).get_matching_blocks(): s = "".join(b[lb:bm]) if am > la or s: bin.append(struct.pack(BDIFF_PATT, p[la], p[am], len(s)) + s) la = am + size lb = bm + size - + return "".join(bin) def textdiff(a, b): @@ -78,12 +78,12 @@ def test(): a = ("foo\n" * 30) b = (" fao" * 30) - + a = file(r"C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Progra\Python\MoinMoin\moin-1.6-sync\MoinMoin\util\test.1").read() b = file(r"C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Progra\Python\MoinMoin\moin-1.6-sync\MoinMoin\util\test.2").read() a = a.splitlines(1) b = b.splitlines(1) - + d = diff(a, b) z = compress(d) print `patchtext(d)`
--- a/MoinMoin/util/chartypes_create.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/chartypes_create.py Mon Jul 24 22:18:49 2006 +0200 @@ -10,7 +10,7 @@ lowercase = [] digits = [] space = [] -for code in range(1,65535): +for code in range(1, 65535): c = unichr(code) str = "\\u%04x" % code if c.isupper():
--- a/MoinMoin/util/diff.py Sat Jul 22 13:38:15 2006 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -# -*- coding: iso-8859-1 -*- -""" - MoinMoin - Side by side diffs - - @copyright: 2002 by Jürgen Hermann <jh@web.de> - @copyright: 2002 by Scott Moonen <smoonen@andstuff.org> - @license: GNU GPL, see COPYING for details. -""" - -from MoinMoin.support import difflib -from MoinMoin.wikiutil import escape - -def indent(line): - eol = '' - while line and line[0] == '\n': - eol += '\n' - line = line[1:] - stripped = line.lstrip() - if len(line) - len(stripped): - line = " " * (len(line) - len(stripped)) + stripped - #return "%d / %d / %s" % (len(line), len(stripped), line) - return eol + line - - -# This code originally by Scott Moonen, used with permission. -def diff(request, old, new): - """ Find changes between old and new and return - HTML markup visualising them. - """ - _ = request.getText - t_line = _("Line") + " %d" - - seq1 = old.splitlines() - seq2 = new.splitlines() - - seqobj = difflib.SequenceMatcher(None, seq1, seq2) - linematch = seqobj.get_matching_blocks() - - if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)): - # No differences. - return _("No differences found!") - - lastmatch = (0, 0) - - result = """ -<table class="diff"> -<tr> -<td class="diff-removed"> -<span> -%s -</span> -</td> -<td class="diff-added"> -<span> -%s -</span> -</td> -</tr> -""" % (_('Deletions are marked like this.'), _('Additions are marked like this.'),) - - # Print all differences - for match in linematch: - # Starts of pages identical? - if lastmatch == match[0:2]: - lastmatch = (match[0] + match[2], match[1] + match[2]) - continue - llineno, rlineno = lastmatch[0]+1, lastmatch[1]+1 - result += """ -<tr class="diff-title"> -<td> -%s: -</td> -<td> -%s: -</td> -</tr> -""" % ( request.formatter.line_anchorlink(1, llineno) + request.formatter.text(t_line % llineno) + request.formatter.line_anchorlink(0), - request.formatter.line_anchorlink(1, rlineno) + request.formatter.text(t_line % rlineno) + request.formatter.line_anchorlink(0)) - - leftpane = '' - rightpane = '' - linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1]) - for line in range(linecount): - if line < match[0] - lastmatch[0]: - if line > 0: - leftpane += '\n' - leftpane += seq1[lastmatch[0] + line] - if line < match[1] - lastmatch[1]: - if line > 0: - rightpane += '\n' - rightpane += seq2[lastmatch[1] + line] - - charobj = difflib.SequenceMatcher(None, leftpane, rightpane) - charmatch = charobj.get_matching_blocks() - - if charobj.ratio() < 0.5: - # Insufficient similarity. - if leftpane: - leftresult = """<span>%s</span>""" % indent(escape(leftpane)) - else: - leftresult = '' - - if rightpane: - rightresult = """<span>%s</span>""" % indent(escape(rightpane)) - else: - rightresult = '' - else: - # Some similarities; markup changes. - charlast = (0, 0) - - leftresult = '' - rightresult = '' - for thismatch in charmatch: - if thismatch[0] - charlast[0] != 0: - leftresult += """<span>%s</span>""" % indent( - escape(leftpane[charlast[0]:thismatch[0]])) - if thismatch[1] - charlast[1] != 0: - rightresult += """<span>%s</span>""" % indent( - escape(rightpane[charlast[1]:thismatch[1]])) - leftresult += escape(leftpane[thismatch[0]:thismatch[0] + thismatch[2]]) - rightresult += escape(rightpane[thismatch[1]:thismatch[1] + thismatch[2]]) - charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2]) - - leftpane = '<br>\n'.join(map(indent, leftresult.splitlines())) - rightpane = '<br>\n'.join(map(indent, rightresult.splitlines())) - - # removed width="50%%" - result += """ -<tr> -<td class="diff-removed"> -%s -</td> -<td class="diff-added"> -%s -</td> -</tr> -""" % (leftpane, rightpane) - - lastmatch = (match[0] + match[2], match[1] + match[2]) - - result += '</table>\n' - return result -
--- a/MoinMoin/util/diff3.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/diff3.py Mon Jul 24 22:18:49 2006 +0200 @@ -25,7 +25,7 @@ old_nr, other_nr, new_nr = 0, 0, 0 old_len, other_len, new_len = len(old), len(other), len(new) result = [] - while old_nr < old_len and other_nr < other_len and new_nr < new_len: + while old_nr < old_len and other_nr < other_len and new_nr < new_len: # unchanged if old[old_nr] == other[other_nr] == new[new_nr]: result.append(old[old_nr]) @@ -82,7 +82,7 @@ # process tail # all finished - if old_nr == old_len and other_nr == other_len and new_nr == new_len: + if old_nr == old_len and other_nr == other_len and new_nr == new_len: pass # new added lines elif old_nr == old_len and other_nr == other_len: @@ -122,9 +122,9 @@ if match_len == difference: return (new_match[0], other_match[1]+difference, new_match[1]) else: - other_match = find_match(old, other, - other_match[0] + match_len, - other_match[1] + match_len) + other_match = find_match(old, other, + other_match[0] + match_len, + other_match[1] + match_len) # other changed more lines elif difference < 0: difference = -difference @@ -134,14 +134,14 @@ return (other_match[0], other_match[1], new_match[0] + difference) else: - new_match = find_match(old, new, - new_match[0] + match_len, - new_match[1] + match_len) + new_match = find_match(old, new, + new_match[0] + match_len, + new_match[1] + match_len) # both conflicts change same number of lines # or no match till the end else: return (new_match[0], other_match[1], new_match[1]) - + def match(list1, list2, nr1, nr2, maxcount=3): """ return the number matching items after the given positions maximum maxcount lines are are processed @@ -176,10 +176,10 @@ hit1 = (i, idx2) break i += 1 - + i = nr2 while i < idx2: - hit_count = match(list1, list2, idx1, i, mincount) + hit_count = match(list1, list2, idx1, i, mincount) if hit_count >= mincount: hit2 = (idx1, i) break
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/util/diff_html.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,143 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - Side by side diffs + + @copyright: 2002 by Jürgen Hermann <jh@web.de> + @copyright: 2002 by Scott Moonen <smoonen@andstuff.org> + @license: GNU GPL, see COPYING for details. +""" + +from MoinMoin.support import difflib +from MoinMoin.wikiutil import escape + +def indent(line): + eol = '' + while line and line[0] == '\n': + eol += '\n' + line = line[1:] + stripped = line.lstrip() + if len(line) - len(stripped): + line = " " * (len(line) - len(stripped)) + stripped + #return "%d / %d / %s" % (len(line), len(stripped), line) + return eol + line + + +# This code originally by Scott Moonen, used with permission. +def diff(request, old, new): + """ Find changes between old and new and return + HTML markup visualising them. + """ + _ = request.getText + t_line = _("Line") + " %d" + + seq1 = old.splitlines() + seq2 = new.splitlines() + + seqobj = difflib.SequenceMatcher(None, seq1, seq2) + linematch = seqobj.get_matching_blocks() + + if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)): + # No differences. + return _("No differences found!") + + lastmatch = (0, 0) + + result = """ +<table class="diff"> +<tr> +<td class="diff-removed"> +<span> +%s +</span> +</td> +<td class="diff-added"> +<span> +%s +</span> +</td> +</tr> +""" % (_('Deletions are marked like this.'), _('Additions are marked like this.'),) + + # Print all differences + for match in linematch: + # Starts of pages identical? + if lastmatch == match[0:2]: + lastmatch = (match[0] + match[2], match[1] + match[2]) + continue + llineno, rlineno = lastmatch[0]+1, lastmatch[1]+1 + result += """ +<tr class="diff-title"> +<td> +%s: +</td> +<td> +%s: +</td> +</tr> +""" % (request.formatter.line_anchorlink(1, llineno) + request.formatter.text(t_line % llineno) + request.formatter.line_anchorlink(0), + request.formatter.line_anchorlink(1, rlineno) + request.formatter.text(t_line % rlineno) + request.formatter.line_anchorlink(0)) + + leftpane = '' + rightpane = '' + linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1]) + for line in range(linecount): + if line < match[0] - lastmatch[0]: + if line > 0: + leftpane += '\n' + leftpane += seq1[lastmatch[0] + line] + if line < match[1] - lastmatch[1]: + if line > 0: + rightpane += '\n' + rightpane += seq2[lastmatch[1] + line] + + charobj = difflib.SequenceMatcher(None, leftpane, rightpane) + charmatch = charobj.get_matching_blocks() + + if charobj.ratio() < 0.5: + # Insufficient similarity. + if leftpane: + leftresult = """<span>%s</span>""" % indent(escape(leftpane)) + else: + leftresult = '' + + if rightpane: + rightresult = """<span>%s</span>""" % indent(escape(rightpane)) + else: + rightresult = '' + else: + # Some similarities; markup changes. + charlast = (0, 0) + + leftresult = '' + rightresult = '' + for thismatch in charmatch: + if thismatch[0] - charlast[0] != 0: + leftresult += """<span>%s</span>""" % indent( + escape(leftpane[charlast[0]:thismatch[0]])) + if thismatch[1] - charlast[1] != 0: + rightresult += """<span>%s</span>""" % indent( + escape(rightpane[charlast[1]:thismatch[1]])) + leftresult += escape(leftpane[thismatch[0]:thismatch[0] + thismatch[2]]) + rightresult += escape(rightpane[thismatch[1]:thismatch[1] + thismatch[2]]) + charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2]) + + leftpane = '<br>\n'.join(map(indent, leftresult.splitlines())) + rightpane = '<br>\n'.join(map(indent, rightresult.splitlines())) + + # removed width="50%%" + result += """ +<tr> +<td class="diff-removed"> +%s +</td> +<td class="diff-added"> +%s +</td> +</tr> +""" % (leftpane, rightpane) + + lastmatch = (match[0] + match[2], match[1] + match[2]) + + result += '</table>\n' + return result +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MoinMoin/util/diff_text.py Mon Jul 24 22:18:49 2006 +0200 @@ -0,0 +1,78 @@ +# -*- coding: iso-8859-1 -*- +""" + MoinMoin - simple text diff (uses difflib) + + @copyright: 2006 by MoinMoin:ThomasWaldmann + @license: GNU GPL, see COPYING for details. +""" +from MoinMoin.support import difflib + +def diff(oldlines, newlines, **kw): + """ + Find changes between oldlines and newlines. + + @param oldlines: list of old text lines + @param newlines: list of new text lines + @keyword ignorews: if 1: ignore whitespace + @rtype: list + @return: lines like diff tool does output. + """ + false = lambda s: None + if kw.get('ignorews', 0): + d = difflib.Differ(false) + else: + d = difflib.Differ(false, false) + + lines = list(d.compare(oldlines, newlines)) + + # return empty list if there were no changes + changed = 0 + for l in lines: + if l[0] != ' ': + changed = 1 + break + if not changed: return [] + + if not "we want the unchanged lines, too": + if "no questionmark lines": + lines = filter(lambda line: line[0] != '?', lines) + return lines + + + # calculate the hunks and remove the unchanged lines between them + i = 0 # actual index in lines + count = 0 # number of unchanged lines + lcount_old = 0 # line count old file + lcount_new = 0 # line count new file + while i < len(lines): + marker = lines[i][0] + if marker == ' ': + count = count + 1 + i = i + 1 + lcount_old = lcount_old + 1 + lcount_new = lcount_new + 1 + elif marker in ['-', '+']: + if (count == i) and count > 3: + lines[:i-3] = [] + i = 4 + count = 0 + elif count > 6: + # remove lines and insert new hunk indicator + lines[i-count+3:i-3] = ['@@ -%i, +%i @@\n' % + (lcount_old, lcount_new)] + i = i - count + 8 + count = 0 + else: + count = 0 + i += 1 + if marker == '-': lcount_old = lcount_old + 1 + else: lcount_new = lcount_new + 1 + elif marker == '?': + lines[i:i+1] = [] + + # remove unchanged lines a the end + if count > 3: + lines[-count+3:] = [] + + return lines +
--- a/MoinMoin/util/filesys.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/filesys.py Mon Jul 24 22:18:49 2006 +0200 @@ -109,7 +109,7 @@ """ names = os.listdir(src) os.mkdir(dst) - copystat(src,dst) + copystat(src, dst) errors = [] for name in names: srcname = os.path.join(src, name) @@ -167,3 +167,4 @@ def realPathCase(path): return None +
--- a/MoinMoin/util/lock.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/lock.py Mon Jul 24 22:18:49 2006 +0200 @@ -23,7 +23,7 @@ """ defaultSleep = 0.25 maxSleep = 0.25 - + def __init__(self, timeout): self.setTimeout(timeout) self._start = None @@ -35,7 +35,7 @@ self._sleep = self.defaultSleep else: self._sleep = min(timeout / 10.0, self.maxSleep) - + def start(self): """ Start the countdown """ if self.timeout is None: @@ -53,7 +53,7 @@ def sleep(self): """ Sleep without sleeping over timeout """ if self._stop is not None: - timeLeft = max(self._stop - time.time(), 0) + timeLeft = max(self._stop - time.time(), 0) sleep = min(self._sleep, timeLeft) else: sleep = self._sleep @@ -62,7 +62,7 @@ def elapsed(self): return time.time() - self._start - + class ExclusiveLock: """ Exclusive lock @@ -77,7 +77,7 @@ """ fileName = '' # The directory is the lockDir timerClass = Timer - + def __init__(self, dir, timeout=None): """ Init a write lock @@ -96,7 +96,7 @@ self.lockDir = os.path.join(dir, self.fileName) self._makeDir() else: - self.lockDir = dir + self.lockDir = dir self._locked = False def acquire(self, timeout=None): @@ -165,7 +165,7 @@ return False # Private ------------------------------------------------------- - + def _makeDir(self): """ Make sure directory exists """ try: @@ -180,7 +180,7 @@ try: os.rmdir(self.lockDir) except OSError, err: - if err.errno != errno.ENOENT: + if err.errno != errno.ENOENT: raise @@ -195,7 +195,7 @@ lock will try to expire all existing ReadLocks. """ fileName = 'write_lock' - + def __init__(self, dir, timeout=None, readlocktimeout=None): """ Init a write lock @@ -211,7 +211,7 @@ self.readlocktimeout = timeout else: self.readlocktimeout = readlocktimeout - + def acquire(self, timeout=None): """ Acquire an exclusive write lock @@ -221,7 +221,7 @@ acquired. Return True if lock acquired, False otherwise. - """ + """ if self._locked: raise RuntimeError("lock already locked") result = False @@ -242,9 +242,9 @@ else: self.release() return False - + # Private ------------------------------------------------------- - + def _expireReadLocks(self): """ Expire old read locks """ readLockFileName = ReadLock.fileName @@ -255,7 +255,7 @@ ExclusiveLock(LockDir, self.readlocktimeout).expire() def _haveReadLocks(self): - """ Return True if read locks exists; False otherwise """ + """ Return True if read locks exists; False otherwise """ readLockFileName = ReadLock.fileName for name in os.listdir(self.dir): if name.startswith(readLockFileName): @@ -273,7 +273,7 @@ Allows only one lock per instance. """ fileName = 'read_lock_' - + def __init__(self, dir, timeout=None): """ Init a read lock @@ -302,6 +302,6 @@ # log('acquired read lock: %s\n' % self.lockDir) return True finally: - self.writeLock.release() + self.writeLock.release() return False
--- a/MoinMoin/util/profile.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/profile.py Mon Jul 24 22:18:49 2006 +0200 @@ -64,7 +64,7 @@ self.count = 0 # count between somples self.requests = 0 # requests added self.data = {'collect': 'NA'} # Sample data - + def addRequest(self): """ Add a request to the profile @@ -76,12 +76,12 @@ Invoke sample when self.count reach self.requestsPerSample. """ self.requests += 1 - self.count += 1 + self.count += 1 if self.count == self.requestsPerSample: # Time for a sample self.count = 0 self.sample() - + def sample(self): """ Make a sample of memory usage and log it @@ -90,13 +90,13 @@ Invoke common methods for all profilers. Some profilers like TwistedProfiler override this method. - """ + """ self._setData() self._setMemory() self._log() - + # Private methods ------------------------------------------------------ - + def _setData(self): """ Collect sample data into self.data @@ -109,7 +109,7 @@ d['collect'] = str(gc.collect()) d['objects'] = len(gc.get_objects()) d['garbage'] = len(gc.garbage) - + def _setMemory(self): """ Get process memory usage @@ -120,14 +120,14 @@ """ lines = os.popen('/bin/ps -p %s -o rss' % self.pid).readlines() self.data['memory'] = lines[1].strip() - + def _log(self): """ Format sample and write to log Private method used by profilers. """ line = ('%(date)s req:%(requests)d mem:%(memory)sKB collect:%(collect)s ' - 'objects:%(objects)d garbage:%(garbage)d\n' % self.data) + 'objects:%(objects)d garbage:%(garbage)d\n' % self.data) self.logfile.write(line) self.logfile.flush() @@ -145,10 +145,10 @@ Invoke Profiler.__init__ and import getProcessOuput from twisted. """ - Profiler.__init__(self, name, requestsPerSample, collect) + Profiler.__init__(self, name, requestsPerSample, collect) from twisted.internet.utils import getProcessOutput - self._getProcessOutput = getProcessOutput - + self._getProcessOutput = getProcessOutput + def sample(self): """ Make a sample of memory usage and log it @@ -161,23 +161,22 @@ """ self._setData() # Memory will be available little later - deferred = self._getProcessOutput('/bin/ps', + deferred = self._getProcessOutput('/bin/ps', ('-p', str(self.pid), '-o', 'rss')) deferred.addCallback(self._callback) # Private methods ------------------------------------------------------ - - def _callback(self, data): + + def _callback(self, data): """ Called from deferred when ps output is available Private method, don't call this. """ self.data['memory'] = data.split('\n')[1].strip() - self._log() - - + self._log() + + if __name__ == '__main__': # In case someone try to run as a script print __doc__ -
--- a/MoinMoin/util/pysupport.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/pysupport.py Mon Jul 24 22:18:49 2006 +0200 @@ -30,7 +30,7 @@ import os, re packagedir = os.path.dirname(packagefile) - + in_plugin_dir = lambda dir, ops=os.path.split: ops(ops(dir)[0])[1] == "plugin" moinmodule = __import__('MoinMoin') @@ -85,12 +85,12 @@ if lock is None: import threading lock = threading.Lock() - + def decorated(*args, **kw): lock.acquire() try: return function(*args, **kw) finally: lock.release() - + return decorated
--- a/MoinMoin/util/thread_monitor.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/util/thread_monitor.py Mon Jul 24 22:18:49 2006 +0200 @@ -41,7 +41,7 @@ def dump_hook(a, b, c): # arguments are ignored global dumping - + if dumping and sys.exc_info()[0] is None: thread = threading.currentThread() if thread in to_dump: @@ -65,7 +65,7 @@ """ Activates the thread monitor hook. Note that this interferes with any kind of profiler and some debugging extensions. """ global hook_enabled - + sys.setprofile(dump_hook) threading.setprofile(dump_hook) hook_enabled = True @@ -78,6 +78,6 @@ while 1: sleep(seconds) trigger_dump() - + threading.Thread(target=background_dumper, args=(seconds, )).start()
--- a/MoinMoin/widget/base.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/widget/base.py Mon Jul 24 22:18:49 2006 +0200 @@ -12,5 +12,5 @@ self.request = request def render(self): - raise NotImplementedError + raise NotImplementedError
--- a/MoinMoin/widget/html.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/widget/html.py Mon Jul 24 22:18:49 2006 +0200 @@ -26,7 +26,7 @@ def __unicode__(self): return wikiutil.escape(self.text) - + class Raw: """ Raw HTML code. """ @@ -36,7 +36,7 @@ def __unicode__(self): return self.markup - + class Element: """ Abstract base class for HTML elements. """ @@ -86,9 +86,9 @@ return ' '.join(result) def __unicode__(self): - raise NotImplementedError + raise NotImplementedError - + class EmptyElement(Element): """ HTML elements with an empty content model. """
--- a/MoinMoin/wikiutil.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/wikiutil.py Mon Jul 24 22:18:49 2006 +0200 @@ -9,7 +9,6 @@ import os, re, urllib, cgi import codecs, types -from MoinMoin.support import difflib from MoinMoin import util, version, config from MoinMoin.util import pysupport, filesys @@ -1449,76 +1448,6 @@ """ Returns true if there is a conflict marker in the text. """ return "/!\ '''Edit conflict" in text -def linediff(oldlines, newlines, **kw): - """ - Find changes between oldlines and newlines. - - @param oldlines: list of old text lines - @param newlines: list of new text lines - @keyword ignorews: if 1: ignore whitespace - @rtype: list - @return: lines like diff tool does output. - """ - false = lambda s: None - if kw.get('ignorews', 0): - d = difflib.Differ(false) - else: - d = difflib.Differ(false, false) - - lines = list(d.compare(oldlines, newlines)) - - # return empty list if there were no changes - changed = 0 - for l in lines: - if l[0] != ' ': - changed = 1 - break - if not changed: return [] - - if not "we want the unchanged lines, too": - if "no questionmark lines": - lines = filter(lambda line: line[0] != '?', lines) - return lines - - - # calculate the hunks and remove the unchanged lines between them - i = 0 # actual index in lines - count = 0 # number of unchanged lines - lcount_old = 0 # line count old file - lcount_new = 0 # line count new file - while i < len(lines): - marker = lines[i][0] - if marker == ' ': - count = count + 1 - i = i + 1 - lcount_old = lcount_old + 1 - lcount_new = lcount_new + 1 - elif marker in ['-', '+']: - if (count == i) and count > 3: - lines[:i-3] = [] - i = 4 - count = 0 - elif count > 6: - # remove lines and insert new hunk indicator - lines[i-count+3:i-3] = ['@@ -%i, +%i @@\n' % - (lcount_old, lcount_new)] - i = i - count + 8 - count = 0 - else: - count = 0 - i += 1 - if marker == '-': lcount_old = lcount_old + 1 - else: lcount_new = lcount_new + 1 - elif marker == '?': - lines[i:i+1] = [] - - # remove unchanged lines a the end - if count > 3: - lines[-count+3:] = [] - - return lines - - def pagediff(request, pagename1, rev1, pagename2, rev2, **kw): """ Calculate the "diff" between two page contents. @@ -1532,10 +1461,11 @@ @return: lines of diff output """ from MoinMoin.Page import Page + from MoinMoin.util import diff_text lines1 = Page(request, pagename1, rev=rev1).getlines() lines2 = Page(request, pagename2, rev=rev2).getlines() - lines = linediff(lines1, lines2, **kw) + lines = diff_text.diff(lines1, lines2, **kw) return lines
--- a/MoinMoin/wikixml/marshal.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/wikixml/marshal.py Mon Jul 24 22:18:49 2006 +0200 @@ -34,7 +34,7 @@ # Container Tags ROOT_CONTAINER = "data" ITEM_CONTAINER = "item" - + # List of private prefixes PRIVATE_PREFIXES = ['_'] @@ -42,7 +42,7 @@ TAG_MAP = {} - def __toXML(self, element, data): + def __toXML(self, element, data): """ Recursive helper method that transforms an object to XML. Returns a list of strings, which constitute the XML document.
--- a/MoinMoin/xmlrpc/ProcessMail.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/xmlrpc/ProcessMail.py Mon Jul 24 22:18:49 2006 +0200 @@ -12,13 +12,13 @@ request = xmlrpcobj.request secret = xmlrpcobj._instr(secret) mail = str(mail) - + if not request.cfg.mail_import_secret: return u"No password set" - + if request.cfg.mail_import_secret != secret: return u"Invalid password" - + try: mailimport.import_mail_from_string(request, mail) except mailimport.ProcessingError, e:
--- a/MoinMoin/xmlrpc/UpdateGroup.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/xmlrpc/UpdateGroup.py Mon Jul 24 22:18:49 2006 +0200 @@ -34,7 +34,7 @@ # change your wikiconfig to have xmlrpc_putpage_trusted_only = 0 # and make very very sure that nobody untrusted can access your wiki # via network or somebody will raid your wiki some day! - + if self.request.cfg.xmlrpc_putpage_trusted_only and not self.request.user.trusted: return xmlrpclib.Fault(1, "You are not allowed to edit this page") @@ -45,7 +45,7 @@ # check if groupname matches page_group_regex if not re.match(self.request.cfg.page_group_regex, groupname): return xmlrpclib.Fault(2, "The groupname %s does not match your page_group_regex (%s)" % ( - groupname, self.request.cfg.page_group_regex)) + groupname, self.request.cfg.page_group_regex)) newtext = """\ #acl %(acl)s @@ -56,7 +56,7 @@ 'comment': groupcomment, 'memberlist': "\n * ".join([''] + memberlist) } - + page = PageEditor(self.request, pagename) try: msg = page.saveText(newtext, 0)
--- a/MoinMoin/xmlrpc/__init__.py Sat Jul 22 13:38:15 2006 +0200 +++ b/MoinMoin/xmlrpc/__init__.py Mon Jul 24 22:18:49 2006 +0200 @@ -59,7 +59,7 @@ @return: string in config.charset """ raise "NotImplementedError" - + def _outstr(self, text): """ Convert outbound string to utf-8. @@ -68,7 +68,7 @@ @return: string in utf-8 """ raise "NotImplementedError" - + def _inlob(self, text): """ Convert inbound base64-encoded utf-8 to Large OBject. @@ -93,7 +93,7 @@ if config.charset != 'utf-8': text = unicode(text, config.charset).encode('utf-8') return xmlrpclib.Binary(text) - + def _dump_exc(self): """ Convert an exception to a string. @@ -113,13 +113,13 @@ try: data = self.request.read() params, method = xmlrpclib.loads(data) - + if _debug: sys.stderr.write('- XMLRPC ' + '-' * 70 + '\n') sys.stderr.write('%s(%s)\n\n' % (method, repr(params))) - + response = self.dispatch(method, params) - + except: # report exception back to server response = xmlrpclib.dumps(xmlrpclib.Fault(1, self._dump_exc())) @@ -142,7 +142,7 @@ def dispatch(self, method, params): method = method.replace(".", "_") - + try: fn = getattr(self, 'xmlrpc_' + method) except AttributeError: @@ -156,16 +156,16 @@ response = fn(self, *params) else: response = fn(*params) - + return response # Common faults ----------------------------------------------------- - + def notAllowedFault(self): return xmlrpclib.Fault(1, "You are not allowed to read this page.") def noSuchPageFault(self): - return xmlrpclib.Fault(1, "No such page was found.") + return xmlrpclib.Fault(1, "No such page was found.") ############################################################################# ### System methods @@ -193,13 +193,13 @@ results.append([self.dispatch(method_name, params)]) except xmlrpclib.Fault, fault: results.append( - {'faultCode' : fault.faultCode, - 'faultString' : fault.faultString} + {'faultCode': fault.faultCode, + 'faultString': fault.faultString} ) except: results.append( - {'faultCode' : 1, - 'faultString' : "%s:%s" % (sys.exc_type, sys.exc_value)} + {'faultCode': 1, + 'faultString': "%s:%s" % (sys.exc_type, sys.exc_value)} ) return results @@ -269,9 +269,9 @@ * version (int) : Current version. """ - + return_items = [] - + edit_log = editlog.EditLog(self.request) for log in edit_log.reverse(): # get last-modified UTC (DateTime) from log @@ -281,11 +281,11 @@ # skip if older than "date" if lastModified_date < date: break - + # skip if knowledge not permitted if not self.request.user.may.read(log.pagename): continue - + # get page name (str) from log pagename_str = self._outstr(log.pagename) @@ -297,12 +297,12 @@ author_str = userdata.name author_str = self._outstr(author_str) - return_item = { 'name': pagename_str, - 'lastModified': lastModified_date, - 'author': author_str, - 'version': int(log.rev) } + return_item = {'name': pagename_str, + 'lastModified': lastModified_date, + 'author': author_str, + 'version': int(log.rev) } return_items.append(return_item) - + return return_items def xmlrpc_getPageInfo(self, pagename): @@ -328,7 +328,7 @@ if not self.request.user.may.read(pn): return self.notAllowedFault() - if rev != None: + if rev is not None: page = Page(self.request, pn, rev=rev) else: page = Page(self.request, pn) @@ -339,10 +339,10 @@ return self.noSuchPageFault() # Get page info - last_edit = page.last_edit(self.request) + last_edit = page.last_edit(self.request) mtime = wikiutil.version2timestamp(long(last_edit['timestamp'])) # must be long for py 2.2.x gmtuple = tuple(time.gmtime(mtime)) - + version = rev # our new rev numbers: 1,2,3,4,.... ####################################################################### @@ -355,10 +355,10 @@ if self.request.cfg.sitename == 'MoinMaster' and pagename == 'BadContent': version = int(mtime) ####################################################################### - + return { 'name': self._outstr(page.page_name), - 'lastModified' : xmlrpclib.DateTime(gmtuple), + 'lastModified': xmlrpclib.DateTime(gmtuple), 'author': self._outstr(last_edit['editor']), 'version': version, } @@ -374,14 +374,14 @@ @param rev: revision number (int) @rtype: str @return: utf-8 encoded page data - """ + """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() - if rev != None: + if rev is not None: page = Page(self.request, pagename, rev=rev) else: page = Page(self.request, pagename) @@ -414,7 +414,7 @@ if not self.request.user.may.read(pagename): return self.notAllowedFault() - if rev != None: + if rev is not None: page = Page(self.request, pagename, rev=rev) else: page = Page(self.request, pagename) @@ -422,11 +422,11 @@ # Non existing page? if not page.exists(): return self.noSuchPageFault() - + # Render page into a buffer result = self.request.redirectedOutput(page.send_page, self.request, content_only=1) - + # Return rendered page if self.version == 2: return self._outstr(result) @@ -454,10 +454,10 @@ # Non existing page? if not page.exists(): return self.noSuchPageFault() - + links_out = [] for link in page.getPageLinks(self.request): - links_out.append({ 'name': self._outstr(link), 'type': 0 }) + links_out.append({'name': self._outstr(link), 'type': 0 }) return links_out def xmlrpc_putPage(self, pagename, pagetext): @@ -469,10 +469,10 @@ @return: true on success """ # READ THIS OR IT WILL NOT WORK =================================== - + # we use a test page instead of using the requested pagename, if # xmlrpc_putpage_enabled was not set in wikiconfig. - + if self.request.cfg.xmlrpc_putpage_enabled: pagename = self._instr(pagename) else: @@ -484,7 +484,7 @@ # change your wikiconfig to have xmlrpc_putpage_trusted_only = 0 # and make very very sure that nobody untrusted can access your wiki # via network or somebody will raid your wiki some day! - + if self.request.cfg.xmlrpc_putpage_trusted_only and not self.request.user.trusted: return xmlrpclib.Fault(1, "You are not allowed to edit this page") @@ -529,7 +529,7 @@ # authorization methods - + def xmlrpc_getAuthToken(self, username, password, *args): """ Returns a token which can be used for authentication in other XMLRPC calls. If the token is empty, the username @@ -539,7 +539,7 @@ return u.id else: return "" - + def xmlrpc_applyAuthToken(self, auth_token): """ Applies the auth token and thereby authenticates the user. """ u = user.User(self.request, id=auth_token, auth_method='xmlrpc_applytoken') @@ -555,7 +555,7 @@ def xmlrpc_getDiff(self, pagename, from_rev, to_rev): """ Gets the binary difference between two page revisions. See MoinMoin:WikiSyncronisation. """ from MoinMoin.util.bdiff import textdiff, compress - + pagename = self._instr(pagename) # User may read page? @@ -569,44 +569,44 @@ if not allowed_rev_type(from_rev): return xmlrpclib.Fault("FROMREV_INVALID", "Incorrect type for from_rev.") - + if not allowed_rev_type(to_rev): return xmlrpclib.Fault("TOREV_INVALID", "Incorrect type for to_rev.") - + currentpage = Page(self.request, pagename) if not currentpage.exists(): return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.") - + revisions = currentpage.getRevList() - + if from_rev is not None and from_rev not in revisions: return xmlrpclib.Fault("FROMREV_INVALID", "Unknown from_rev.") if to_rev is not None and to_rev not in revisions: return xmlrpclib.Fault("TOREV_INVALID", "Unknown to_rev.") - + # use lambda to defer execution in the next lines if from_rev is None: oldcontents = lambda: "" else: oldpage = Page(request, pagename, rev=from_rev) oldcontents = lambda: oldpage.get_raw_body_str() - + if to_rev is None: newcontents = lambda: currentpage.get_raw_body() else: newpage = Page(request, pagename, rev=to_rev) newcontents = lambda: newpage.get_raw_body_str() newrev = newpage.get_real_rev() - + if oldcontents() and oldpage.get_real_rev() == newpage.get_real_rev(): return xmlrpclib.Fault("ALREADY_CURRENT", "There are no changes.") - + newcontents = newcontents() conflict = wikiutil.containsConflictMarker(newcontents) diffblob = xmlrpclib.Binary(compress(textdiff(oldcontents(), newcontents))) - + return {"conflict": conflict, "diff": diffblob, "diffversion": 1, "current": currentpage.get_real_rev()} - + def xmlrpc_interwikiName(self): """ Returns the interwiki name of the current wiki. """ name = self.request.cfg.interwikiname @@ -614,7 +614,7 @@ return None else: return self._outstr(name) - + def xmlrpc_mergeChanges(self, pagename, diff, local_rev, delta_remote_rev, last_remote_rev, interwiki_name): """ Merges a diff sent by the remote machine and returns the number of the new revision. Additionally, this method tags the new revision. @@ -629,9 +629,9 @@ from MoinMoin.util.bdiff import decompress, patch from MoinMoin.wikisync import TagStore LASTREV_INVALID = xmlrpclib.Fault("LASTREV_INVALID", "The page was changed") - + pagename = self._instr(pagename) - + comment = u"Remote - %r" % interwiki_name # User may read page? @@ -639,22 +639,22 @@ return self.notAllowedFault() # XXX add locking here! - + # current version of the page currentpage = PageEditor(self.request, pagename, do_editor_backup=0) if currentpage.get_real_rev() != last_remote_rev: return LASTREV_INVALID - + if not currentpage.exists() and diff is None: return xmlrpclib.Fault("NOT_EXIST", "The page does not exist and no diff was supplied.") - + # base revision used for the diff basepage = Page(self.request, pagename, rev=delta_remote_rev) - + # generate the new page revision by applying the diff newcontents = patch(basepage.get_raw_body_str(), decompress(str(diff))) - + # write page try: currentpage.saveText(newcontents.encode("utf-8"), last_remote_rev, comment=comment) @@ -686,12 +686,12 @@ @param pagename: pagename (utf-8) @rtype: list @return: a list of utf-8 attachment names - """ + """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() - + result = AttachFile._get_files(self.request, pagename) return result @@ -735,7 +735,7 @@ # also check ACLs if not self.request.user.may.write(pagename): return xmlrpclib.Fault(1, "You are not allowed to edit this page") - + attachname = wikiutil.taintfilename(attachname) filename = AttachFile.getFilename(self.request, pagename, attachname) if os.path.exists(filename) and not os.path.isfile(filename): @@ -744,12 +744,12 @@ os.chmod(filename, 0666 & config.umask) AttachFile._addLogEntry(self.request, 'ATTNEW', pagename, filename) return xmlrpclib.Boolean(1) - + # XXX END WARNING XXX class XmlRpc1(XmlRpcBase): - + def __init__(self, request): XmlRpcBase.__init__(self, request) self.version = 1 @@ -772,9 +772,9 @@ """ return wikiutil.url_quote(text) # config.charset must be utf-8 - + class XmlRpc2(XmlRpcBase): - + def __init__(self, request): XmlRpcBase.__init__(self, request) self.version = 2 @@ -798,9 +798,9 @@ @return: text encoded in utf-8 """ if isinstance(text, unicode): - text = text.encode('utf-8') - elif config.charset != 'utf-8': - text = unicode(text, config.charset).encode('utf-8') + text = text.encode('utf-8') + elif config.charset != 'utf-8': + text = unicode(text, config.charset).encode('utf-8') return text
--- a/docs/CHANGES Sat Jul 22 13:38:15 2006 +0200 +++ b/docs/CHANGES Mon Jul 24 22:18:49 2006 +0200 @@ -67,6 +67,8 @@ * refactored some actions to use ActionBase base class * moved "test" action from wikiaction to MoinMoin/action/ (and use ActionBase) + * moved MoinMoin/config.py to MoinMoin/config/__init__.py + * moved MoinMoin/multiconfig.py to MoinMoin/config/multiconfig.py * moved "SystemInfo" macro from wikimacro to MoinMoin/macro/ * moved wikiaction.py stuff to MoinMoin/action/__init__.py * moved wikimacro.py stuff to MoinMoin/macro/__init__.py @@ -116,6 +118,7 @@ * removed all _ magic in URLs and filenames TODO: write mig script for data_dir TODO: make blanks in interwiki pagelinks possible + * request.action now has the action requested, default: 'show'. New Features: * Removed "underscore in URL" == "blank in pagename magic" - it made more @@ -189,6 +192,9 @@ internally, too. So if GUI editor invocation is broken due to browser compatibility issues or a wrong browser version check, please file a bug at FCKeditor development or browser development. + * HINT: instead of "from MoinMoin.multiconfig import DefaultConfig" you + need to use "from MoinMoin.config.multiconfig import DefaultConfig" now. + You need to change this in you wikiconfig.py or farmconfig.py file. Version 1.5.4-current: * increased maxlength of some input fields from 80 to 200
--- a/wiki/config/more_samples/ldap_smb_farmconfig.py Sat Jul 22 13:38:15 2006 +0200 +++ b/wiki/config/more_samples/ldap_smb_farmconfig.py Mon Jul 24 22:18:49 2006 +0200 @@ -69,7 +69,7 @@ # this is to get everything to sane defaults, so we need to change only what # we like to have different: -from MoinMoin.multiconfig import DefaultConfig +from MoinMoin.config.multiconfig import DefaultConfig # Now we subclass this DefaultConfig. This means that we inherit every setting # from the DefaultConfig, except those we explicitely define different.
--- a/wiki/config/wikiconfig.py Sat Jul 22 13:38:15 2006 +0200 +++ b/wiki/config/wikiconfig.py Mon Jul 24 22:18:49 2006 +0200 @@ -15,7 +15,7 @@ Note that there are more config options than you'll find in the version of this file that is installed by default; see - the module MoinMoin.multiconfig for a full list of names and their + the module MoinMoin.config.multiconfig for a full list of names and their default values. Also, the URL http://moinmoin.wikiwikiweb.de/HelpOnConfiguration has @@ -25,7 +25,7 @@ from the wikifarm directory instead! ** """ -from MoinMoin.multiconfig import DefaultConfig +from MoinMoin.config.multiconfig import DefaultConfig class Config(DefaultConfig):
--- a/wiki/config/wikifarm/farmconfig.py Sat Jul 22 13:38:15 2006 +0200 +++ b/wiki/config/wikifarm/farmconfig.py Mon Jul 24 22:18:49 2006 +0200 @@ -14,7 +14,7 @@ Note that there are more config options than you'll find in the version of this file that is installed by default; see - the module MoinMoin.multiconfig for a full list of names and their + the module MoinMoin.config.multiconfig for a full list of names and their default values. Also, the URL http://moinmoin.wikiwikiweb.de/HelpOnConfiguration has @@ -42,10 +42,10 @@ wikis = [ # Standalone server needs the port e.g. localhost:8000 # Twisted server can now use the port, too. - + # wikiname, url regular expression (no protocol) # --------------------------------------------------------------- - ("mywiki", r".*"), # this is ok for a single wiki + ("mywiki", r".*"), # this is ok for a single wiki # for multiple wikis, do something like this: #("moinmoin", r"^moinmoin.wikiwikiweb.de/.*$"), @@ -65,7 +65,7 @@ # this is to get everything to sane defaults, so we need to change only what # we like to have different: -from MoinMoin.multiconfig import DefaultConfig +from MoinMoin.config.multiconfig import DefaultConfig # Now we subclass this DefaultConfig. This means that we inherit every setting # from the DefaultConfig, except those we explicitely define different.