changeset 2004:2334273e3850 namespaces

merged default branch into namespaces branch
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 16 Feb 2013 23:21:46 +0100
parents 70b9962f1860 (current diff) 8c71a45e11f2 (diff)
children f5b13839b63a
files
diffstat 215 files changed, 1395 insertions(+), 1076 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,23 +8,21 @@
 """
 
 
-import os, shutil
-import socket, errno
+import socket
 from StringIO import StringIO
 
-from flask import current_app as app
 from flask import g as flaskg
 
-from MoinMoin import config, security, user
-from MoinMoin.config import NAME, CONTENTTYPE
+from MoinMoin.constants.contenttypes import CHARSET
+from MoinMoin.constants.keys import NAME, CONTENTTYPE
 from MoinMoin.items import Item
 from MoinMoin.util.crypto import random_string
-from MoinMoin.storage.error import ItemAlreadyExistsError
 
 # Promoting the test user -------------------------------------------
 # Usually the tests run as anonymous user, but for some stuff, you
 # need more privs...
 
+
 def become_valid(username=u"ValidUser"):
     """ modify flaskg.user to make the user valid.
         Note that a valid user will only be in ACL special group "Known", if
@@ -49,7 +47,7 @@
 def update_item(name, meta, data):
     """ creates or updates an item  """
     if isinstance(data, unicode):
-        data = data.encode(config.charset)
+        data = data.encode(CHARSET)
     item = flaskg.storage[name]
 
     meta = meta.copy()
@@ -60,11 +58,13 @@
     rev = item.store_revision(meta, StringIO(data), return_rev=True)
     return rev
 
+
 def create_random_string_list(length=14, count=10):
     """ creates a list of random strings """
     chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
     return [u"{0}".format(random_string(length, chars)) for counter in range(count)]
 
+
 def nuke_item(name):
     """ complete destroys an item """
     item = Item.create(name)
--- a/MoinMoin/_tests/_test_template.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/_test_template.py	Sat Feb 16 23:21:46 2013 +0100
@@ -45,6 +45,7 @@
     )
 
     from MoinMoin._tests import wikiconfig
+
     class Config(wikiconfig.Config):
         foo = 'bar'  # we want to have this non-default setting
 
--- a/MoinMoin/_tests/ldap_testbase.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/ldap_testbase.py	Sat Feb 16 23:21:46 2013 +0100
@@ -39,7 +39,11 @@
 SLAPD_EXECUTABLE = 'slapd'  # filename of LDAP server executable - if it is not
                             # in your PATH, you have to give full path/filename.
 
-import os, shutil, tempfile, time, base64
+import os
+import shutil
+import tempfile
+import time
+import base64
 from StringIO import StringIO
 import signal
 import subprocess
@@ -80,7 +84,7 @@
     def __init__(self,
                  config=None,  # config filename for -f
                  executable=SLAPD_EXECUTABLE,
-                 debug_flags='', # None,  # for -d stats,acl,args,trace,sync,config
+                 debug_flags='',  # None,  # for -d stats,acl,args,trace,sync,config
                  proto='ldap', ip='127.0.0.1', port=3890,  # use -h proto://ip:port
                  service_name=''  # defaults to -n executable:port, use None to not use -n
                 ):
@@ -90,7 +94,7 @@
         self.proto = proto
         self.ip = ip
         self.port = port
-        self.url = '{0}://{1}:{2}'.format(proto, ip, port) # can be used for ldap.initialize() call
+        self.url = '{0}://{1}:{2}'.format(proto, ip, port)  # can be used for ldap.initialize() call
         if service_name == '':
             self.service_name = '{0}:{1}'.format(executable, port)
         else:
@@ -109,7 +113,7 @@
         started = None
         if timeout:
             lo = ldap.initialize(self.url)
-            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) # ldap v2 is outdated
+            ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)  # ldap v2 is outdated
             started = False
             wait_until = time.time() + timeout
             while time.time() < wait_until:
@@ -200,14 +204,14 @@
 
     def start_slapd(self):
         """ start a slapd and optionally wait until it talks with us """
-        self.slapd = Slapd(config=self.slapd_conf, port=3890+self.instance)
+        self.slapd = Slapd(config=self.slapd_conf, port=3890 + self.instance)
         started = self.slapd.start(timeout=self.timeout)
         return started
 
     def load_directory(self, ldif_content):
         """ load the directory with the ldif_content (str) """
         lo = ldap.initialize(self.slapd.url)
-        ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) # ldap v2 is outdated
+        ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)  # ldap v2 is outdated
         lo.simple_bind_s(self.rootdn, self.rootpw)
 
         class LDIFLoader(ldif.LDIFParser):
--- a/MoinMoin/_tests/test_error.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/test_error.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,8 +8,6 @@
 """
 
 
-import pytest
-
 from MoinMoin import error
 
 
--- a/MoinMoin/_tests/test_test_environ.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/test_test_environ.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,14 +7,10 @@
 
 from StringIO import StringIO
 
-import pytest
-
 from flask import current_app as app
 from flask import g as flaskg
 
-from MoinMoin.conftest import init_test_app, deinit_test_app
-from MoinMoin.config import NAME, CURRENT, CONTENTTYPE, IS_SYSITEM, SYSITEM_VERSION
-from MoinMoin.storage.error import NoSuchItemError
+from MoinMoin.constants.keys import NAME, CONTENTTYPE
 
 from MoinMoin._tests import wikiconfig
 
--- a/MoinMoin/_tests/test_user.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/test_user.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,13 +9,9 @@
 """
 
 
-import pytest
-
-from flask import current_app as app
 from flask import g as flaskg
 
 from MoinMoin import user
-from MoinMoin.util import crypto
 
 
 class TestSimple(object):
--- a/MoinMoin/_tests/test_wikiutil.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/test_wikiutil.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,8 +11,8 @@
 
 from flask import current_app as app
 
-from MoinMoin import config, wikiutil
-from MoinMoin._tests import wikiconfig
+from MoinMoin.constants.chartypes import CHARS_SPACES
+from MoinMoin import wikiutil
 
 from werkzeug import MultiDict
 
@@ -112,7 +112,7 @@
             (u'a     b     c', u'a b c'),
             (u'a   b  /  c    d  /  e   f', u'a b/c d/e f'),
             # All 30 unicode spaces
-            (config.chars_spaces, u''),
+            (CHARS_SPACES, u''),
             )
         for test, expected in cases:
             result = wikiutil.normalize_pagename(test, app.cfg)
@@ -166,11 +166,11 @@
     assert result == expected
 
 def testdrawing2fname():
-    # with extension not in config.drawing_extensions
+    # with extension not in DRAWING_EXTENSIONS
     result = wikiutil.drawing2fname('Moin_drawing.txt')
     expected = 'Moin_drawing.txt.tdraw'
     assert result == expected
-    # with extension in config.drawing_extensions
+    # with extension in DRAWING_EXTENSIONS
     result = wikiutil.drawing2fname('Moindir.Moin_drawing.jpg')
     expected = 'Moindir.Moin_drawing.jpg'
     assert result == expected
--- a/MoinMoin/_tests/wikiconfig.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/_tests/wikiconfig.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,10 +15,11 @@
 from os.path import abspath, dirname, join
 from MoinMoin.config.default import DefaultConfig
 
+
 class Config(DefaultConfig):
     _here = abspath(dirname(__file__))
     _root = abspath(join(_here, '..', '..'))
-    data_dir = join(_here, 'wiki', 'data') # needed for plugins package TODO
+    data_dir = join(_here, 'wiki', 'data')  # needed for plugins package TODO
     index_storage = 'FileStorage', (join(_here, 'wiki', 'index'), ), {}
     content_acl = None
     item_root = 'FrontPage'
--- a/MoinMoin/app.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/app.py	Sat Feb 16 23:21:46 2013 +0100
@@ -28,6 +28,7 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
+from MoinMoin.constants.misc import ANON
 from MoinMoin.i18n import i18n_init
 from MoinMoin.i18n import _, L_, N_
 
@@ -109,8 +110,6 @@
 
             Rule('/<itemname:wikipage>')
             Rule('/<itemname:wikipage>/edit')
-
-        :param map: the :class:`Map`.
         """
         regex = '[^/]+?(/[^/]+?)*'
         weight = 200
@@ -225,7 +224,7 @@
 
     # if we still have no user obj, create a dummy:
     if not userobj:
-        userobj = user.User(name=u'anonymous', auth_method='invalid')
+        userobj = user.User(name=ANON, auth_method='invalid')
     # if we have a valid user we store it in the session
     if userobj.valid:
         session['user.itemid'] = userobj.itemid
--- a/MoinMoin/apps/admin/templates/admin/wikiconfig.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/admin/templates/admin/wikiconfig.html	Sat Feb 16 23:21:46 2013 +0100
@@ -30,6 +30,6 @@
 </td>
 </tr>
 {% endfor %}
-</tdbody>
+</tbody>
 </table>
 {% endblock %}
--- a/MoinMoin/apps/admin/views.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/admin/views.py	Sat Feb 16 23:21:46 2013 +0100
@@ -20,16 +20,17 @@
 from MoinMoin.themes import render_template
 from MoinMoin.apps.admin import admin
 from MoinMoin import user
-from MoinMoin.storage.error import NoSuchRevisionError
-from MoinMoin.config import NAME, ITEMID, SIZE, EMAIL
-from MoinMoin.config import SUPERUSER
+from MoinMoin.constants.keys import NAME, ITEMID, SIZE, EMAIL
+from MoinMoin.constants.rights import SUPERUSER
 from MoinMoin.security import require_permission
 
+
 @admin.route('/superuser')
 @require_permission(SUPERUSER)
 def index():
     return render_template('admin/index.html', title_name=_(u"Admin"))
 
+
 @admin.route('/user')
 def index_user():
     return render_template('user/index_user.html', title_name=_(u"User"))
@@ -42,7 +43,7 @@
     User Account Browser
     """
     groups = flaskg.groups
-    revs = user.search_users() # all users
+    revs = user.search_users()  # all users
     user_accounts = [dict(uid=rev.meta[ITEMID],
                           name=rev.meta[NAME],
                           email=rev.meta[EMAIL],
@@ -100,7 +101,7 @@
 @admin.route('/sysitems_upgrade', methods=['GET', 'POST', ])
 @require_permission(SUPERUSER)
 def sysitems_upgrade():
-    from MoinMoin.storage.backends import upgrade_sysitems
+    from MoinMoin.storage.backends import upgrade_sysitems  # XXX broken import, either fix or kill this
     from MoinMoin.storage.error import BackendError
     if request.method == 'GET':
         action = 'syspages_upgrade'
@@ -120,6 +121,7 @@
 
 from MoinMoin.config import default as defaultconfig
 
+
 @admin.route('/wikiconfig', methods=['GET', ])
 @require_permission(SUPERUSER)
 def wikiconfig():
--- a/MoinMoin/apps/feed/_tests/test_feed.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/feed/_tests/test_feed.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,8 +7,7 @@
 
 from flask import url_for
 
-from MoinMoin.items import Item
-from MoinMoin.config import CONTENTTYPE, COMMENT
+from MoinMoin.constants.keys import COMMENT
 from MoinMoin._tests import update_item, wikiconfig
 
 class TestFeeds(object):
--- a/MoinMoin/apps/feed/views.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/feed/views.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,7 +14,6 @@
 from flask import request, Response
 from flask import current_app as app
 from flask import g as flaskg
-from flask import url_for
 
 from werkzeug.contrib.atom import AtomFeed
 from jinja2 import Markup
@@ -26,14 +25,13 @@
 
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.apps.feed import feed
-from MoinMoin.config import (NAME, NAME_EXACT, WIKINAME, ACL, ACTION, ADDRESS,
-                            HOSTNAME, USERID, COMMENT, MTIME, REVID, ALL_REVS,
-                            PARENTID, LATEST_REVS)
+from MoinMoin.constants.keys import NAME, NAME_EXACT, WIKINAME, COMMENT, MTIME, REVID, ALL_REVS, PARENTID, LATEST_REVS
 from MoinMoin.themes import get_editor_info, render_template
 from MoinMoin.items import Item
 from MoinMoin.util.crypto import cache_key
 from MoinMoin.util.interwiki import url_for_item
 
+
 @feed.route('/atom/<itemname:item_name>')
 @feed.route('/atom', defaults=dict(item_name=''))
 def atom(item_name):
@@ -78,7 +76,8 @@
                     content = hl_item.content._render_data_diff_atom(previous_rev, this_rev)
                 else:
                     # full html rendering for new items
-                    content = render_template('atom.html', get='first_revision', rev=this_rev, content=Markup(hl_item.content._render_data()), revision=this_revid)
+                    content = render_template('atom.html', get='first_revision', rev=this_rev,
+                                              content=Markup(hl_item.content._render_data()), revision=this_revid)
                 content_type = 'html'
             except Exception as e:
                 logging.exception("content rendering crashed")
@@ -89,7 +88,8 @@
             if rev_comment:
                 # Trim down extremely long revision comment
                 if len(rev_comment) > 80:
-                    content = render_template('atom.html', get='comment_cont_merge', comment=rev_comment[79:], content=Markup(content))
+                    content = render_template('atom.html', get='comment_cont_merge', comment=rev_comment[79:],
+                                              content=Markup(content))
                     rev_comment = u"{0}...".format(rev_comment[:79])
                 feed_title = u"{0} - {1}".format(author.get(NAME, ''), rev_comment)
             else:
--- a/MoinMoin/apps/frontend/_tests/test_frontend.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/frontend/_tests/test_frontend.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,16 +8,12 @@
 
 from StringIO import StringIO
 
-import pytest
-
 from flask import url_for
 from flask import g as flaskg
 from werkzeug import ImmutableMultiDict, FileStorage
 
 from MoinMoin.apps.frontend import views
 from MoinMoin import user
-from MoinMoin.util import crypto
-from MoinMoin._tests import wikiconfig
 
 
 class TestFrontend(object):
--- a/MoinMoin/apps/frontend/views.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/frontend/views.py	Sat Feb 16 23:21:46 2013 +0100
@@ -21,11 +21,10 @@
 import mimetypes
 import json
 from datetime import datetime
-from itertools import chain
 from collections import namedtuple
 from functools import wraps, partial
 
-from flask import request, url_for, flash, Response, make_response, redirect, session, abort, jsonify
+from flask import request, url_for, flash, Response, make_response, redirect, abort, jsonify
 from flask import current_app as app
 from flask import g as flaskg
 from flask.ext.babel import format_date
@@ -45,18 +44,20 @@
 logging = log.getLogger(__name__)
 
 from MoinMoin.i18n import _, L_, N_
-from MoinMoin.themes import render_template, get_editor_info, contenttype_to_class
+from MoinMoin.themes import render_template, contenttype_to_class
 from MoinMoin.apps.frontend import frontend
-from MoinMoin.forms import OptionalText, RequiredText, URL, YourOpenID, YourEmail, RequiredPassword, Checkbox, InlineCheckbox, Select, Names, Tags, Natural, Submit, Hidden, MultiSelect
+from MoinMoin.forms import (OptionalText, RequiredText, URL, YourOpenID, YourEmail, RequiredPassword, Checkbox,
+                            InlineCheckbox, Select, Names, Tags, Natural, Hidden, MultiSelect)
 from MoinMoin.items import BaseChangeForm, Item, NonExistent
 from MoinMoin.items.content import content_registry
-from MoinMoin import config, user, util
+from MoinMoin import user, util
 from MoinMoin.constants.keys import *
+from MoinMoin.constants.itemtypes import ITEMTYPE_DEFAULT
+from MoinMoin.constants.chartypes import CHARS_UPPER, CHARS_LOWER
 from MoinMoin.util import crypto
 from MoinMoin.util.interwiki import url_for_item
-from MoinMoin.search import SearchForm, ValidSearch
-from MoinMoin.security.textcha import TextCha, TextChaizedForm, TextChaValid
-from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
+from MoinMoin.search import SearchForm
+from MoinMoin.security.textcha import TextCha, TextChaizedForm
 from MoinMoin.signalling import item_displayed, item_modified
 from MoinMoin.storage.middleware.protecting import AccessDenied
 
@@ -76,6 +77,7 @@
     item_name = app.cfg.item_root
     return redirect(url_for_item(item_name))
 
+
 @frontend.route('/robots.txt')
 def robots():
     return Response("""\
@@ -136,7 +138,7 @@
     refs = OptionalText.using(label='refs')
     tags = Tags.using(optional=True).using(label='tags')
     history = InlineCheckbox.using(label=L_('search also in non-current revisions'))
-    submit = Submit.using(default=L_('Lookup'))
+    submit_label = L_('Lookup')
 
 
 @frontend.route('/+lookup', methods=['GET', 'POST'])
@@ -164,7 +166,6 @@
     # TAGS might be there multiple times, thus we need multi:
     lookup_form = LookupForm.from_flat(request.values.items(multi=True))
     valid = lookup_form.validate()
-    lookup_form['submit'].set_default() # XXX from_flat() kills all values
     if valid:
         history = bool(request.values.get('history'))
         idx_name = ALL_REVS if history else LATEST_REVS
@@ -225,7 +226,7 @@
     with flaskg.storage.indexer.ix[LATEST_REVS].searcher() as searcher:
         # The search process should be as fast as possible so use
         # the indexer low-level documents instead of high-level Revisions.
-        doc = searcher.document(name_exact=item_name)
+        doc = searcher.document(**{NAME_EXACT: item_name})
         if not doc:
             return set()
         transcluded_names = set(doc[ITEMTRANSCLUSIONS])
@@ -234,12 +235,12 @@
             transcluded_names.update(transclusions)
         return transcluded_names
 
+
 @frontend.route('/+search/<itemname:item_name>', methods=['GET', 'POST'])
 @frontend.route('/+search', defaults=dict(item_name=u''), methods=['GET', 'POST'])
 def search(item_name):
     search_form = SearchForm.from_flat(request.values)
     valid = search_form.validate()
-    search_form['submit'].set_default() # XXX from_flat() kills all values
     query = search_form['q'].value
     if valid:
         history = bool(request.values.get('history'))
@@ -248,7 +249,7 @@
         q = qp.parse(query)
 
         _filter = None
-        if item_name: # Only search this item and subitems
+        if item_name:  # Only search this item and subitems
             prefix_name = item_name + u'/'
             terms = [Term(NAME_EXACT, item_name), Prefix(NAME_EXACT, prefix_name), ]
 
@@ -279,22 +280,15 @@
             flaskg.clock.start('search')
             results = searcher.search(q, filter=_filter, limit=100)
             flaskg.clock.stop('search')
-            # XXX if found that calling key_terms like you see below is 1000..10000x
-            # slower than the search itself, so we better don't do that right now.
-            key_terms_is_fast = False
-            if key_terms_is_fast:
-                flaskg.clock.start('search suggestions')
-                name_suggestions = u', '.join([word for word, score in results.key_terms(NAME, docs=20, numterms=10)])
-                content_suggestions = u', '.join([word for word, score in results.key_terms(CONTENT, docs=20, numterms=10)])
-                flaskg.clock.stop('search suggestions')
-            else:
-                name_suggestions = u''
-                content_suggestions = u''
+            flaskg.clock.start('search suggestions')
+            name_suggestions = [word for word, score in results.key_terms(NAME, docs=20, numterms=10)]
+            content_suggestions = [word for word, score in results.key_terms(CONTENT, docs=20, numterms=10)]
+            flaskg.clock.stop('search suggestions')
             flaskg.clock.start('search render')
             html = render_template('search.html',
                                    results=results,
-                                   name_suggestions=name_suggestions,
-                                   content_suggestions=content_suggestions,
+                                   name_suggestions=u', '.join(name_suggestions),
+                                   content_suggestions=u', '.join(content_suggestions),
                                    query=query,
                                    medium_search_form=search_form,
                                    item_name=item_name,
@@ -402,7 +396,7 @@
 @presenter('meta', add_trail=True)
 def show_item_meta(item):
     show_revision = request.view_args['rev'] != CURRENT
-    show_navigation = False # TODO
+    show_navigation = False  # TODO
     first_rev = None
     last_rev = None
     if show_navigation:
@@ -421,15 +415,11 @@
                            show_navigation=show_navigation,
                           )
 
+
 @frontend.route('/+content/+<rev>/<itemname:item_name>')
 @frontend.route('/+content/<itemname:item_name>', defaults=dict(rev=CURRENT))
 def content_item(item_name, rev):
     """ same as show_item, but we only show the content """
-    # first check whether we have a valid search query:
-    search_form = SearchForm.from_flat(request.values)
-    if search_form.validate():
-        return _search(search_form, item_name)
-    search_form['submit'].set_default() # XXX from_flat() kills all values
     item_displayed.send(app._get_current_object(),
                         item_name=item_name)
     try:
@@ -443,15 +433,18 @@
                            data_rendered=Markup(item.content._render_data()),
                            )
 
+
 @presenter('get')
 def get_item(item):
     return item.content.do_get()
 
+
 @presenter('download')
 def download_item(item):
     mimetype = request.values.get("mimetype")
     return item.content.do_get(force_attachment=True, mimetype=mimetype)
 
+
 @frontend.route('/+convert/<itemname:item_name>')
 def convert_item(item_name):
     """
@@ -474,7 +467,7 @@
     item_name_converted = item_name + 'converted'
     try:
         # TODO implement Content.create and use it here
-        converted_item = Item.create(item_name_converted, itemtype=u'default', contenttype=contenttype)
+        converted_item = Item.create(item_name_converted, itemtype=ITEMTYPE_DEFAULT, contenttype=contenttype)
     except AccessDenied:
         abort(403)
     return converted_item.content._convert(item.content.internal_representation())
@@ -489,7 +482,7 @@
     After successful POST, redirects to the page.
     """
     # XXX drawing applets don't send itemtype
-    itemtype = request.values.get('itemtype', u'default')
+    itemtype = request.values.get('itemtype', ITEMTYPE_DEFAULT)
     contenttype = request.values.get('contenttype')
     try:
         item = Item.create(item_name, itemtype=itemtype, contenttype=contenttype)
@@ -503,15 +496,19 @@
 class TargetChangeForm(BaseChangeForm):
     target = RequiredText.using(label=L_('Target')).with_properties(placeholder=L_("The name of the target item"))
 
+
 class RevertItemForm(BaseChangeForm):
     name = 'revert_item'
 
+
 class DeleteItemForm(BaseChangeForm):
     name = 'delete_item'
 
+
 class DestroyItemForm(BaseChangeForm):
     name = 'destroy_item'
 
+
 class RenameItemForm(TargetChangeForm):
     name = 'rename_item'
 
@@ -598,6 +595,7 @@
                            form=form,
                           )
 
+
 @frontend.route('/+ajaxdelete/<itemname:item_name>', methods=['POST'])
 @frontend.route('/+ajaxdelete', defaults=dict(item_name=''), methods=['POST'])
 def ajaxdelete(item_name):
@@ -623,6 +621,7 @@
 
     return jsonify(response)
 
+
 @frontend.route('/+ajaxdestroy/<itemname:item_name>', methods=['POST'])
 @frontend.route('/+ajaxdestroy', defaults=dict(item_name=''), methods=['POST'])
 def ajaxdestroy(item_name):
@@ -666,7 +665,7 @@
 def destroy_item(item_name, rev):
     if rev is None:
         # no revision given
-        _rev = CURRENT # for item creation
+        _rev = CURRENT  # for item creation
         destroy_item = True
     else:
         _rev = rev
@@ -706,7 +705,7 @@
     """
     data_file = request.files.get('data_file')
     subitem_name = data_file.filename
-    contenttype = data_file.content_type # guess by browser, based on file name
+    contenttype = data_file.content_type  # guess by browser, based on file name
     data = data_file.stream
     if item_name:
         subitem_prefix = item_name + u'/'
@@ -733,17 +732,20 @@
     contenttype_group_descriptions[g] = ', '.join([e.display_name for e in content_registry.groups[g]])
 contenttype_groups.append('unknown items')
 
-ContenttypeGroup = MultiSelect.of(Enum.using(valid_values=contenttype_groups).with_properties(descriptions=contenttype_group_descriptions)).using(optional=True)
+ContenttypeGroup = MultiSelect.of(Enum.using(valid_values=contenttype_groups).with_properties(
+                                  descriptions=contenttype_group_descriptions)).using(optional=True)
+
 
 class IndexForm(Form):
     contenttype = ContenttypeGroup
-    submit = Submit.using(default=L_('Filter'))
+    submit_label = L_('Filter')
+
 
 @frontend.route('/+index/', defaults=dict(item_name=''), methods=['GET', 'POST'])
 @frontend.route('/+index/<itemname:item_name>', methods=['GET', 'POST'])
 def index(item_name):
     try:
-        item = Item.create(item_name) # when item_name='', it gives toplevel index
+        item = Item.create(item_name)  # when item_name='', it gives toplevel index
     except AccessDenied:
         abort(403)
 
@@ -753,7 +755,6 @@
     # values, eg. calling items with multi=True. See Werkzeug documentation for
     # more.
     form = IndexForm.from_flat(request.args.items(multi=True))
-    form['submit'].set_default() # XXX from_flat() kills all values
     if not form['contenttype']:
         form['contenttype'].set(contenttype_groups)
 
@@ -857,7 +858,7 @@
     history = [dict((k, v) for k, v in rev.meta.iteritems() if k != CONTENT) for rev in revs]
     history_page = util.getPageContent(history, offset, results_per_page)
     return render_template('history.html',
-                           item_name=item_name, # XXX no item here
+                           item_name=item_name,  # XXX no item here
                            history_page=history_page,
                            bookmark_time=bookmark_time,
                           )
@@ -898,6 +899,7 @@
                            bookmark_time=bookmark_time,
                           )
 
+
 def _compute_item_sets():
     """
     compute sets of existing, linked, transcluded and no-revision item names
@@ -1000,8 +1002,8 @@
             return False
         if element['password1'].value != element['password2'].value:
             return self.note_error(element, state, 'passwords_mismatch_msg')
+        return True
 
-        return True
 
 class RegistrationForm(TextChaizedForm):
     """a simple user registration form"""
@@ -1012,7 +1014,7 @@
     password2 = RequiredPassword.with_properties(placeholder=L_("Repeat the same password"))
     email = YourEmail
     openid = YourOpenID.using(optional=True)
-    submit = Submit.using(default=L_('Register'))
+    submit_label = L_('Register')
 
     validators = [ValidRegistration()]
 
@@ -1025,6 +1027,7 @@
 
     openid = YourOpenID
 
+
 def _using_moin_auth():
     """Check if MoinAuth is being used for authentication.
 
@@ -1097,7 +1100,8 @@
                     if is_ok:
                         flash(_('Account verification required, please see the email we sent to your address.'), "info")
                     else:
-                        flash(_('An error occurred while sending the verification email: "%(message)s" Please contact an administrator to activate your account.',
+                        flash(_('An error occurred while sending the verification email: "%(message)s" '
+                                'Please contact an administrator to activate your account.',
                             message=msg), "error")
                 else:
                     flash(_('Account created, please log in now.'), "info")
@@ -1111,16 +1115,16 @@
 
 @frontend.route('/+verifyemail', methods=['GET'])
 def verifyemail():
-    u = None
+    u = token = None
     if 'username' in request.values and 'token' in request.values:
         u = user.User(auth_username=request.values['username'])
         token = request.values['token']
-    if u and u.disabled and u.validate_recovery_token(token):
+    if u and u.disabled and token and u.validate_recovery_token(token):
         u.profile[DISABLED] = False
         u.save()
         flash(_("Your account has been activated, you can log in now."), "info")
     else:
-        flash(_('Your token is invalid!'), "error")
+        flash(_('Your username and/or token is invalid!'), "error")
     return redirect(url_for('.show_root'))
 
 
@@ -1144,7 +1148,7 @@
 
     username = OptionalText.using(label=L_('Name')).with_properties(placeholder=L_("Your login name"))
     email = YourEmail.using(optional=True)
-    submit = Submit.using(default=L_('Recover password'))
+    submit_label = L_('Recover password')
 
     validators = [ValidLostPassword()]
 
@@ -1181,6 +1185,7 @@
                            form=form,
                           )
 
+
 class ValidPasswordRecovery(Validator):
     """Validator for a valid password recovery form
     """
@@ -1199,15 +1204,19 @@
 
         return True
 
+
 class PasswordRecoveryForm(Form):
     """a simple password recovery form"""
     name = 'recoverpass'
 
     username = RequiredText.using(label=L_('Name')).with_properties(placeholder=L_("Your login name"))
-    token = RequiredText.using(label=L_('Recovery token')).with_properties(placeholder=L_("The recovery token that has been sent to you"))
-    password1 = RequiredPassword.using(label=L_('New password')).with_properties(placeholder=L_("The login password you want to use"))
-    password2 = RequiredPassword.using(label=L_('New password (repeat)')).with_properties(placeholder=L_("Repeat the same password"))
-    submit = Submit.using(default=L_('Change password'))
+    token = RequiredText.using(label=L_('Recovery token')).with_properties(
+        placeholder=L_("The recovery token that has been sent to you"))
+    password1 = RequiredPassword.using(label=L_('New password')).with_properties(
+        placeholder=L_("The login password you want to use"))
+    password2 = RequiredPassword.using(label=L_('New password (repeat)')).with_properties(
+        placeholder=L_("Repeat the same password"))
+    submit_label = L_('Change password')
 
     validators = [ValidPasswordRecovery()]
 
@@ -1273,7 +1282,10 @@
     username = RequiredText.using(label=L_('Name'), optional=False).with_properties(autofocus=True)
     password = RequiredPassword
     openid = YourOpenID.using(optional=True)
-    submit = Submit.using(default=L_('Log in'))
+    # This field results in a login_submit field in the POST form, which is in
+    # turn looked for by setup_user() in app.py as marker for login requests.
+    submit = Hidden.using(default='1')
+    submit_label = L_('Log in')
 
     validators = [ValidLogin()]
 
@@ -1344,21 +1356,27 @@
     name = 'usersettings_password'
     validators = [ValidChangePass()]
 
-    password_current = RequiredPassword.using(label=L_('Current Password')).with_properties(placeholder=L_("Your current login password"))
-    password1 = RequiredPassword.using(label=L_('New password')).with_properties(placeholder=L_("The login password you want to use"))
-    password2 = RequiredPassword.using(label=L_('New password (repeat)')).with_properties(placeholder=L_("Repeat the same password"))
-    submit = Submit.using(default=L_('Change password'))
+    password_current = RequiredPassword.using(label=L_('Current Password')).with_properties(
+        placeholder=L_("Your current login password"))
+    password1 = RequiredPassword.using(label=L_('New password')).with_properties(
+        placeholder=L_("The login password you want to use"))
+    password2 = RequiredPassword.using(label=L_('New password (repeat)')).with_properties(
+        placeholder=L_("Repeat the same password"))
+    submit_label = L_('Change password')
+
 
 class UserSettingsNotificationForm(Form):
     name = 'usersettings_notification'
     email = YourEmail
-    submit = Submit.using(default=L_('Save'))
+    submit_label = L_('Save')
 
 
 class UserSettingsNavigationForm(Form):
     name = 'usersettings_navigation'
+    # XXX Flatland insists a form having at least one element
+    dummy = Hidden
     # TODO: find a good way to handle quicklinks here
-    submit = Submit.using(default=L_('Save'))
+    submit_label = L_('Save')
 
 
 class UserSettingsOptionsForm(Form):
@@ -1368,7 +1386,7 @@
     scroll_page_after_edit = Checkbox.using(label=L_('Scroll page after edit'))
     show_comments = Checkbox.using(label=L_('Show comment sections'))
     disabled = Checkbox.using(label=L_('Disable this account forever'))
-    submit = Submit.using(default=L_('Save'))
+    submit_label = L_('Save')
 
 
 @frontend.route('/+usersettings', methods=['GET', 'POST'])
@@ -1378,9 +1396,10 @@
 
     # these forms can't be global because we need app object, which is only available within a request:
     class UserSettingsPersonalForm(Form):
-        name = 'usersettings_personal' # "name" is duplicate
+        name = 'usersettings_personal'  # "name" is duplicate
         name = Names.using(label=L_('Names')).with_properties(placeholder=L_("The login names you want to use"))
-        display_name = OptionalText.using(label=L_('Display-Name')).with_properties(placeholder=L_("Your display name (informational)"))
+        display_name = OptionalText.using(label=L_('Display-Name')).with_properties(
+            placeholder=L_("Your display name (informational)"))
         openid = YourOpenID.using(optional=True)
         #timezones_keys = sorted(Locale('en').time_zones.keys())
         timezones_keys = [unicode(tz) for tz in pytz.common_timezones]
@@ -1390,18 +1409,22 @@
                                    key=lambda x: x[1])
         locales_keys = [l[0] for l in locales_available]
         locale = Select.using(label=L_('Locale')).with_properties(labels=dict(locales_available)).valued(*locales_keys)
-        submit = Submit.using(default=L_('Save'))
+        submit_label = L_('Save')
 
     class UserSettingsUIForm(Form):
         name = 'usersettings_ui'
         themes_available = sorted([(unicode(t.identifier), t.name) for t in get_themes_list()],
                                   key=lambda x: x[1])
         themes_keys = [t[0] for t in themes_available]
-        theme_name = Select.using(label=L_('Theme name')).with_properties(labels=dict(themes_available)).valued(*themes_keys)
-        css_url = URL.using(label=L_('User CSS URL'), optional=True).with_properties(placeholder=L_("Give the URL of your custom CSS (optional)"))
-        edit_rows = Natural.using(label=L_('Editor size')).with_properties(placeholder=L_("Editor textarea height (0=auto)"))
-        results_per_page = Natural.using(label=L_('History results per page')).with_properties(placeholder=L_("Number of results per page (0=no paging)"))
-        submit = Submit.using(default=L_('Save'))
+        theme_name = Select.using(label=L_('Theme name')).with_properties(
+            labels=dict(themes_available)).valued(*themes_keys)
+        css_url = URL.using(label=L_('User CSS URL'), optional=True).with_properties(
+            placeholder=L_("Give the URL of your custom CSS (optional)"))
+        edit_rows = Natural.using(label=L_('Editor size')).with_properties(
+            placeholder=L_("Editor textarea height (0=auto)"))
+        results_per_page = Natural.using(label=L_('History results per page')).with_properties(
+            placeholder=L_("Number of results per page (0=no paging)"))
+        submit_label = L_('Save')
 
     form_classes = dict(
         personal=UserSettingsPersonalForm,
@@ -1446,44 +1469,50 @@
                     response['flash'].append((_("Your password has been changed."), "info"))
                 else:
                     if part == 'personal':
-                        if form['openid'].value and form['openid'].value != flaskg.user.openid and user.search_users(openid=form['openid'].value):
+                        if (form['openid'].value and form['openid'].value != flaskg.user.openid and
+                            user.search_users(openid=form['openid'].value)):
                             # duplicate openid
                             response['flash'].append((_("This openid is already in use."), "error"))
                             success = False
                         if set(form['name'].value) != set(flaskg.user.name):
                             new_names = set(form['name'].value) - set(flaskg.user.name)
                             for name in new_names:
-                                if user.search_users(name_exact=name):
+                                if user.search_users(**{NAME_EXACT: name}):
                                     # duplicate name
-                                    response['flash'].append((_("The username %(name)r is already in use.", name=name), "error"))
+                                    response['flash'].append((_("The username %(name)r is already in use.", name=name),
+                                                              "error"))
                                     success = False
                     if part == 'notification':
                         if (form['email'].value != flaskg.user.email and
-                            user.search_users(email=form['email'].value) and app.cfg.user_email_unique):
+                            user.search_users(**{EMAIL: form['email'].value}) and app.cfg.user_email_unique):
                             # duplicate email
                             response['flash'].append((_('This email is already in use'), 'error'))
                             success = False
                     if success:
                         user_old_email = flaskg.user.email
                         d = dict(form.value)
-                        d.pop('submit')
                         for k, v in d.items():
                             flaskg.user.profile[k] = v
-                        if part == 'notification' and app.cfg.user_email_verification and form['email'].value != user_old_email:
+                        if (part == 'notification' and app.cfg.user_email_verification and
+                            form['email'].value != user_old_email):
                             # disable account
                             flaskg.user.profile[DISABLED] = True
                             # send verification mail
                             is_ok, msg = flaskg.user.mail_email_verification()
                             if is_ok:
                                 flaskg.user.logout_session()
-                                response['flash'].append((_('Your account has been disabled because you changed your email address. Please see the email we sent to your address to reactivate it.'), "info"))
+                                response['flash'].append((_('Your account has been disabled because you changed your '
+                                                            'email address. Please see the email we sent to your '
+                                                            'address to reactivate it.'), "info"))
                                 response['redirect'] = url_for('.show_root')
                             else:
                                 # sending the verification email didn't work. reset email change and alert the user.
                                 flaskg.user.profile[DISABLED] = False
                                 flaskg.user.profile[EMAIL] = user_old_email
                                 flaskg.user.save()
-                                response['flash'].append((_('Your email address was not changed because sending the verification email failed. Please try again later.'), "error"))
+                                response['flash'].append((_('Your email address was not changed because sending the '
+                                                            'verification email failed. Please try again later.'),
+                                                          "error"))
                         else:
                             flaskg.user.save()
 
@@ -1668,7 +1697,7 @@
                 item_names.append(name)
     return render_template("link_list_item_panel.html",
                            headline=_("Items with similar names to '%(item_name)s'", item_name=item_name),
-                           item_name=item_name, # XXX no item
+                           item_name=item_name,  # XXX no item
                            item_names=item_names)
 
 
@@ -1721,11 +1750,9 @@
     :returns: start, end, matches dict
     """
     if start_re is None:
-        start_re = re.compile(u'([{0}][{1}]+)'.format(config.chars_upper,
-                                                     config.chars_lower))
+        start_re = re.compile(u'([{0}][{1}]+)'.format(CHARS_UPPER, CHARS_LOWER))
     if end_re is None:
-        end_re = re.compile(u'([{0}][{1}]+)$'.format(config.chars_upper,
-                                                    config.chars_lower))
+        end_re = re.compile(u'([{0}][{1}]+)$'.format(CHARS_UPPER, CHARS_LOWER))
 
     # If we don't get results with wiki words matching, fall back to
     # simple first word and last word, using spaces.
@@ -1801,9 +1828,9 @@
     if not flaskg.storage[item_name]:
         abort(404, item_name)
     sitemap = NestedItemListBuilder().recurse_build([item_name])
-    del sitemap[0] # don't show current item name as sole toplevel list item
+    del sitemap[0]  # don't show current item name as sole toplevel list item
     return render_template('sitemap.html',
-                           item_name=item_name, # XXX no item
+                           item_name=item_name,  # XXX no item
                            sitemap=sitemap,
                           )
 
@@ -1812,7 +1839,7 @@
     def __init__(self):
         self.children = set()
         self.numnodes = 0
-        self.maxnodes = 35 # approx. max count of nodes, not strict
+        self.maxnodes = 35  # approx. max count of nodes, not strict
 
     def recurse_build(self, names):
         result = []
@@ -1871,10 +1898,11 @@
             scale = weight_max / 2
         else:
             scale = weight_max / (count_max - count_min)
+
         def cls(count):
             # return the css class for this tag
             weight = scale * (count - count_min)
-            return "weight{0}".format(int(weight)) # weight0, ..., weight9
+            return "weight{0}".format(int(weight))  # weight0, ..., weight9
         tags = [(cls(count), tag) for tag, count in tags_counts]
     else:
         tags = []
--- a/MoinMoin/apps/misc/views.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/apps/misc/views.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,12 +15,12 @@
 
 from MoinMoin.apps.misc import misc
 
-from MoinMoin.config import NAME, MTIME
+from MoinMoin.constants.keys import MTIME
 from MoinMoin.themes import render_template
-from MoinMoin import wikiutil
 
 SITEMAP_HAS_SYSTEM_ITEMS = True
 
+
 @misc.route('/sitemap')
 def sitemap():
     """
@@ -34,7 +34,7 @@
     for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname):
         name = rev.name
         mtime = rev.meta[MTIME]
-        if False: # was: wikiutil.isSystemItem(name)   XXX add back later, when we have that in the index
+        if False:  # was: wikiutil.isSystemItem(name)   XXX add back later, when we have that in the index
             if not SITEMAP_HAS_SYSTEM_ITEMS:
                 continue
             # system items are rather boring
--- a/MoinMoin/auth/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -177,21 +177,25 @@
         self.multistage = multistage
         self.redirect_to = redirect_to
 
+
 class ContinueLogin(LoginReturn):
     """ ContinueLogin - helper for auth method login that just continues """
     def __init__(self, user_obj, message=None):
         LoginReturn.__init__(self, user_obj, True, message=message)
 
+
 class CancelLogin(LoginReturn):
     """ CancelLogin - cancel login showing a message """
     def __init__(self, message):
         LoginReturn.__init__(self, None, False, message=message)
 
+
 class MultistageFormLogin(LoginReturn):
     """ MultistageFormLogin - require user to fill in another form """
     def __init__(self, multistage):
         LoginReturn.__init__(self, None, False, multistage=multistage)
 
+
 class MultistageRedirectLogin(LoginReturn):
     """ MultistageRedirectLogin - redirect user to another site before continuing login """
     def __init__(self, url):
@@ -202,22 +206,28 @@
     name = None
     login_inputs = []
     logout_possible = False
+
     def __init__(self, trusted=False, **kw):
         self.trusted = trusted
         if kw:
             raise TypeError("got unexpected arguments %r" % kw)
+
     def login(self, user_obj, **kw):
         return ContinueLogin(user_obj)
+
     def request(self, user_obj, **kw):
         return user_obj, True
+
     def logout(self, user_obj, **kw):
         if self.name and user_obj and user_obj.auth_method == self.name:
             logging.debug("{0}: logout - invalidating user {1!r}".format(self.name, user_obj.name))
             user_obj.valid = False
         return user_obj, True
+
     def login_hint(self):
         return None
 
+
 class MoinAuth(BaseAuth):
     """ handle login from moin login form """
     def __init__(self, **kw):
@@ -267,7 +277,7 @@
         Alternatively you can directly give a fixed user name (user_name)
         that will be considered as authenticated.
     """
-    name = 'given' # was 'http' in 1.8.x and before
+    name = 'given'  # was 'http' in 1.8.x and before
 
     def __init__(self,
                  env_var=None,  # environment variable we want to read (default: REMOTE_USER)
@@ -352,7 +362,7 @@
             u.create_or_update()
         if u and u.valid:
             logging.debug("returning valid user {0!r}".format(u))
-            return u, True # True to get other methods called, too
+            return u, True  # True to get other methods called, too
         else:
             logging.debug("returning {0!r}".format(user_obj))
             return user_obj, True
@@ -407,6 +417,7 @@
 
     return userobj
 
+
 def handle_logout(userobj):
     """ Logout the passed user from every configured authentication method. """
     if userobj is None:
@@ -419,6 +430,7 @@
             break
     return userobj
 
+
 def handle_request(userobj):
     """ Handle the per-request callbacks of the configured authentication methods. """
     for authmethod in app.cfg.auth:
@@ -427,6 +439,7 @@
             break
     return userobj
 
+
 def setup_from_session():
     userobj = None
     if 'user.itemid' in session:
--- a/MoinMoin/auth/_tests/test_auth.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/_tests/test_auth.py	Sat Feb 16 23:21:46 2013 +0100
@@ -5,12 +5,10 @@
 Test for auth.__init__
 """
 
-from flask import current_app as app
 from flask import g as flaskg
 
-import pytest
-
 from MoinMoin._tests import wikiconfig
+from MoinMoin.constants.misc import ANON
 from MoinMoin.auth import GivenAuth, handle_login, get_multistage_continuation_url
 from MoinMoin.user import create_user
 
@@ -60,7 +58,7 @@
     test_user1 = handle_login(flaskg.user, login_username='test_user', login_password='test_password', stage='moin')
     test_login_message = [u'Invalid username or password.']
     assert flaskg._login_messages == test_login_message
-    assert test_user1.name0 == u'anonymous'
+    assert test_user1.name0 == ANON
     assert not test_user1.valid
     # pop the message
     flaskg._login_messages.pop()
--- a/MoinMoin/auth/_tests/test_http.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/_tests/test_http.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,8 @@
 
 from MoinMoin.user import create_user
 from MoinMoin.auth.http import HTTPAuthMoin
-import pytest
+from MoinMoin.constants.misc import ANON
+
 
 class TestHTTPAuthMoin(object):
     """ Test: HTTPAuthMoin """
@@ -41,4 +42,4 @@
         flaskg.user.auth_method = 'invalid'
         test_user, bool_val = httpauthmoin_obj.request(flaskg.user)
         assert not test_user.valid
-        assert test_user.name0 == u'anonymous'
+        assert test_user.name0 == ANON
--- a/MoinMoin/auth/_tests/test_log.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/_tests/test_log.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,9 +8,11 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
+from flask import g as flaskg
+
 from MoinMoin.auth.log import AuthLog
-from flask import g as flaskg
-import pytest
+from MoinMoin.constants.misc import ANON
+
 
 class TestAuthLog(object):
     """ Test: TestAuthLog """
@@ -19,13 +21,13 @@
         result = authlog_obj.login(flaskg.user)
         assert result.continue_flag
         test_user_obj = result.user_obj
-        assert test_user_obj.name0 == u'anonymous'
+        assert test_user_obj.name0 == ANON
 
     def test_request(self):
         authlog_obj = AuthLog()
         result = authlog_obj.request(flaskg.user)
         test_user, bool_value = result
-        assert test_user.name0 == u'anonymous'
+        assert test_user.name0 == ANON
         assert not test_user.valid
         assert bool_value
 
@@ -33,6 +35,6 @@
         authlog_obj = AuthLog()
         result = authlog_obj.logout(flaskg.user)
         test_user, bool_value = result
-        assert test_user.name0 == u'anonymous'
+        assert test_user.name0 == ANON
         assert not test_user.valid
         assert bool_value
--- a/MoinMoin/auth/http.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/http.py	Sat Feb 16 23:21:46 2013 +0100
@@ -22,7 +22,7 @@
 
 from flask import request
 
-from MoinMoin import config, user
+from MoinMoin import user
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.auth import BaseAuth, GivenAuth
 
@@ -48,7 +48,8 @@
 
         auth = request.authorization
         if auth and auth.username and auth.password is not None:
-            logging.debug("http basic auth, received username: {0!r} password: {1!r}".format(auth.username, auth.password))
+            logging.debug("http basic auth, received username: {0!r} password: {1!r}".format(
+                auth.username, auth.password))
             u = user.User(name=auth.username.decode(self.coding),
                           password=auth.password.decode(self.coding),
                           auth_method=self.name, auth_attribs=[], trusted=self.trusted)
@@ -66,7 +67,7 @@
             u.create_or_update()
         if u and u.valid:
             logging.debug("returning valid user {0!r}".format(u))
-            return u, True # True to get other methods called, too
+            return u, True  # True to get other methods called, too
         else:
             logging.debug("returning {0!r}".format(user_obj))
             return user_obj, True
--- a/MoinMoin/auth/ldap_login.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/ldap_login.py	Sat Feb 16 23:21:46 2013 +0100
@@ -60,32 +60,32 @@
         bind_pw='',
         base_dn='',  # base DN we use for searching
                      #base_dn = 'ou=SOMEUNIT,dc=example,dc=org'
-        scope=ldap.SCOPE_SUBTREE, # scope of the search we do (2 == ldap.SCOPE_SUBTREE)
-        referrals=0, # LDAP REFERRALS (0 needed for AD)
+        scope=ldap.SCOPE_SUBTREE,  # scope of the search we do (2 == ldap.SCOPE_SUBTREE)
+        referrals=0,  # LDAP REFERRALS (0 needed for AD)
         search_filter='(uid=%(username)s)',  # ldap filter used for searching:
                                              #search_filter = '(sAMAccountName=%(username)s)' # (AD)
                                              #search_filter = '(uid=%(username)s)' # (OpenLDAP)
                                              # you can also do more complex filtering like:
                                              # "(&(cn=%(username)s)(memberOf=CN=WikiUsers,OU=Groups,DC=example,DC=org))"
         # some attribute names we use to extract information from LDAP:
-        givenname_attribute=None, # ('givenName') ldap attribute we get the first name from
-        surname_attribute=None, # ('sn') ldap attribute we get the family name from
-        displayname_attribute=None, # ('displayName') ldap attribute we get the display_name from
-        email_attribute=None, # ('mail') ldap attribute we get the email address from
-        email_callback=None, # called to make up email address
-        name_callback=None, # called to use a Wiki name different from the login name
-        coding='utf-8', # coding used for ldap queries and result values
-        timeout=10, # how long we wait for the ldap server [s]
-        start_tls=0, # 0 = No, 1 = Try, 2 = Required
+        givenname_attribute=None,  # ('givenName') ldap attribute we get the first name from
+        surname_attribute=None,  # ('sn') ldap attribute we get the family name from
+        displayname_attribute=None,  # ('displayName') ldap attribute we get the display_name from
+        email_attribute=None,  # ('mail') ldap attribute we get the email address from
+        email_callback=None,  # called to make up email address
+        name_callback=None,  # called to use a Wiki name different from the login name
+        coding='utf-8',  # coding used for ldap queries and result values
+        timeout=10,  # how long we wait for the ldap server [s]
+        start_tls=0,  # 0 = No, 1 = Try, 2 = Required
         tls_cacertdir=None,
         tls_cacertfile=None,
         tls_certfile=None,
         tls_keyfile=None,
-        tls_require_cert=0, # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
-        bind_once=False, # set to True to only do one bind - useful if configured to bind as the user on the first attempt
-        autocreate=False, # set to True if you want to autocreate user profiles
-        name='ldap', # use e.g. 'ldap_pdc' and 'ldap_bdc' (or 'ldap1' and 'ldap2') if you auth against 2 ldap servers
-        report_invalid_credentials=True, # whether to emit "invalid username or password" msg at login time or not
+        tls_require_cert=0,  # 0 == ldap.OPT_X_TLS_NEVER (needed for self-signed certs)
+        bind_once=False,  # set to True to only do one bind - useful if configured to bind as the user on first attempt
+        autocreate=False,  # set to True if you want to autocreate user profiles
+        name='ldap',  # use e.g. 'ldap_pdc' and 'ldap_bdc' (or 'ldap1' and 'ldap2') if you auth against 2 ldap servers
+        report_invalid_credentials=True,  # whether to emit "invalid username or password" msg at login time or not
         **kw
         ):
         super(LDAPAuth, self).__init__(**kw)
@@ -133,9 +133,10 @@
             try:
                 u = None
                 dn = None
+                server = self.server_uri
                 coding = self.coding
                 logging.debug("Setting misc. ldap options...")
-                ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) # ldap v2 is outdated
+                ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)  # ldap v2 is outdated
                 ldap.set_option(ldap.OPT_REFERRALS, self.referrals)
                 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
 
@@ -152,7 +153,6 @@
                         if value is not None:
                             ldap.set_option(option, value)
 
-                server = self.server_uri
                 logging.debug("Trying to initialize {0!r}.".format(server))
                 l = ldap.initialize(server)
                 logging.debug("Connected to LDAP server {0!r}.".format(server))
@@ -193,7 +193,8 @@
                 result_length = len(lusers)
                 if result_length != 1:
                     if result_length > 1:
-                        logging.warning("Search found more than one ({0}) matches for {1!r}.".format(result_length, filterstr))
+                        logging.warning("Search found more than one ({0}) matches for {1!r}.".format(
+                            result_length, filterstr))
                     if result_length == 0:
                         logging.debug("Search found no matches for {0!r}.".format(filterstr, ))
                     if self.report_invalid_credentials:
@@ -233,18 +234,22 @@
                     username = self.name_callback(ldap_dict)
 
                 if email:
-                    u = user.User(auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'email', 'mailto_author', ),
+                    u = user.User(auth_username=username, auth_method=self.name,
+                                  auth_attribs=('name', 'password', 'email', 'mailto_author', ),
                                   trusted=self.trusted)
                     u.email = email
                 else:
-                    u = user.User(auth_username=username, auth_method=self.name, auth_attribs=('name', 'password', 'mailto_author', ),
+                    u = user.User(auth_username=username, auth_method=self.name,
+                                  auth_attribs=('name', 'password', 'mailto_author', ),
                                   trusted=self.trusted)
                 u.name = username
                 u.display_name = display_name
-                logging.debug("creating user object with name {0!r} email {1!r} display name {2!r}".format(username, email, display_name))
+                logging.debug("creating user object with name {0!r} email {1!r} display name {2!r}".format(
+                    username, email, display_name))
 
             except ldap.INVALID_CREDENTIALS as err:
-                logging.debug("invalid credentials (wrong password?) for dn {0!r} (username: {1!r})".format(dn, username))
+                logging.debug("invalid credentials (wrong password?) for dn {0!r} (username: {1!r})".format(
+                    dn, username))
                 return CancelLogin(_("Invalid username or password."))
 
             if u and self.autocreate:
--- a/MoinMoin/auth/log.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/log.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,6 +14,7 @@
 
 from MoinMoin.auth import BaseAuth, ContinueLogin
 
+
 class AuthLog(BaseAuth):
     """ just log the call, do nothing else """
     name = "log"
--- a/MoinMoin/auth/openidrp.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/openidrp.py	Sat Feb 16 23:21:46 2013 +0100
@@ -20,7 +20,7 @@
 from flask import current_app as app
 from MoinMoin.auth import BaseAuth, get_multistage_continuation_url
 from MoinMoin.auth import ContinueLogin, CancelLogin, MultistageFormLogin, MultistageRedirectLogin
-from MoinMoin.config import ITEMID
+from MoinMoin.constants.keys import ITEMID
 from MoinMoin import user
 from MoinMoin.i18n import _, L_, N_
 
--- a/MoinMoin/auth/smb_mount.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/auth/smb_mount.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,6 +16,7 @@
 
 from MoinMoin.auth import BaseAuth, CancelLogin, ContinueLogin
 
+
 class SMBMount(BaseAuth):
     """ auth plugin for (un)mounting an smb share,
         this is a wrapper around mount.cifs -o <options> //server/share mountpoint
@@ -23,17 +24,17 @@
         See man mount.cifs for details.
     """
     def __init__(self,
-        server, # mount.cifs //server/share
-        share, # mount.cifs //server/share
-        mountpoint_fn, # function of username to determine the mountpoint, e.g.:
-                       # lambda username: u'/mnt/wiki/%s' % username
-        dir_user, # username to get the uid that is used for mount.cifs -o uid=... (e.g. 'www-data')
-        domain, # mount.cifs -o domain=...
-        dir_mode='0700', # mount.cifs -o dir_mode=...
-        file_mode='0600', # mount.cifs -o file_mode=...
-        iocharset='utf-8', # mount.cifs -o iocharset=... (try 'iso8859-1' if default does not work)
-        coding='utf-8', # encoding used for username/password/cmdline (try 'iso8859-1' if default does not work)
-        log='/dev/null', # logfile for mount.cifs output
+        server,  # mount.cifs //server/share
+        share,  # mount.cifs //server/share
+        mountpoint_fn,  # function of username to determine the mountpoint, e.g.:
+                        # lambda username: u'/mnt/wiki/%s' % username
+        dir_user,  # username to get the uid that is used for mount.cifs -o uid=... (e.g. 'www-data')
+        domain,  # mount.cifs -o domain=...
+        dir_mode='0700',  # mount.cifs -o dir_mode=...
+        file_mode='0600',  # mount.cifs -o file_mode=...
+        iocharset='utf-8',  # mount.cifs -o iocharset=... (try 'iso8859-1' if default does not work)
+        coding='utf-8',  # encoding used for username/password/cmdline (try 'iso8859-1' if default does not work)
+        log='/dev/null',  # logfile for mount.cifs output
         **kw
         ):
         super(SMBMount, self).__init__(**kw)
@@ -51,13 +52,16 @@
     def do_smb(self, username, password, login):
         logging.debug("login={0} logout={1}: got name={2!r}".format(login, not login, username))
 
-        import os, pwd, subprocess
+        import os
+        import pwd
+        import subprocess
         web_username = self.dir_user
-        web_uid = pwd.getpwnam(web_username)[2] # XXX better just use current uid?
+        web_uid = pwd.getpwnam(web_username)[2]  # XXX better just use current uid?
 
         mountpoint = self.mountpoint_fn(username)
         if login:
-            cmd = u"sudo mount -t cifs -o user=%(user)s,domain=%(domain)s,uid=%(uid)d,dir_mode=%(dir_mode)s,file_mode=%(file_mode)s,iocharset=%(iocharset)s //%(server)s/%(share)s %(mountpoint)s >>%(log)s 2>&1"
+            cmd = (u"sudo mount -t cifs -o user=%(user)s,domain=%(domain)s,uid=%(uid)d,dir_mode=%(dir_mode)s,file_mode="
+                   u"%(file_mode)s,iocharset=%(iocharset)s //%(server)s/%(share)s %(mountpoint)s >>%(log)s 2>&1")
         else:
             cmd = u"sudo umount %(mountpoint)s >>%(log)s 2>&1"
 
@@ -77,7 +81,7 @@
         if login:
             try:
                 if not os.path.exists(mountpoint):
-                    os.makedirs(mountpoint) # the dir containing the mountpoint must be writeable for us!
+                    os.makedirs(mountpoint)  # the dir containing the mountpoint must be writeable for us!
             except OSError:
                 pass
             env['PASSWD'] = password.encode(self.coding)
--- a/MoinMoin/config/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/config/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -1,13 +1,4 @@
-# Copyright: 2011 MoinMoin:ThomasWaldmann
+# Copyright: 2011-2013 MoinMoin:ThomasWaldmann
 # License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
 
-"""
-MoinMoin - configuration defaults and support code
-"""
-
-# provide compatibility for stuff not using MoinMoin.constants yet
-from MoinMoin.constants.rights import *
-from MoinMoin.constants.chartypes import *
-from MoinMoin.constants.contenttypes import *
-from MoinMoin.constants.keys import *
-from MoinMoin.constants.misc import *
+# Nothing to see here any more, please do direct imports from MoinMoin.constants.*
--- a/MoinMoin/config/default.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/config/default.py	Sat Feb 16 23:21:46 2013 +0100
@@ -20,7 +20,9 @@
 logging = log.getLogger(__name__)
 
 from MoinMoin.i18n import _, L_, N_
-from MoinMoin import config, error
+from MoinMoin import error
+from MoinMoin.constants.rights import ACL_RIGHTS_CONTENTS, ACL_RIGHTS_FUNCTIONS
+from MoinMoin.constants.keys import *
 from MoinMoin import datastruct
 from MoinMoin.auth import MoinAuth
 from MoinMoin.util import plugins
@@ -76,10 +78,10 @@
 
         plugins._loadPluginModule(self)
 
-        if self.user_defaults['timezone'] is None:
-            self.user_defaults['timezone'] = self.timezone_default
-        if self.user_defaults['theme_name'] is None:
-            self.user_defaults['theme_name'] = self.theme_default
+        if self.user_defaults[TIMEZONE] is None:
+            self.user_defaults[TIMEZONE] = self.timezone_default
+        if self.user_defaults[THEME_NAME] is None:
+            self.user_defaults[THEME_NAME] = self.theme_default
         # Note: do not assign user_defaults['locale'] = locale_default
         # to give browser language detection a chance.
         try:
@@ -113,22 +115,28 @@
         self.mail_enabled = self.mail_enabled and True or False
 
         if self.namespace_mapping is None:
-            raise error.ConfigurationError("No storage configuration specified! You need to define a namespace_mapping. "
-                                           "For further reference, please see HelpOnStorageConfiguration.")
+            raise error.ConfigurationError(
+                "No storage configuration specified! You need to define a namespace_mapping. "
+                "For further reference, please see HelpOnStorageConfiguration.")
 
         if self.backend_mapping is None:
-            raise error.ConfigurationError("No storage configuration specified! You need to define a backend_mapping. " +
-                                           "For further reference, please see HelpOnStorageConfiguration.")
+            raise error.ConfigurationError(
+                "No storage configuration specified! You need to define a backend_mapping. " +
+                "For further reference, please see HelpOnStorageConfiguration.")
 
         if self.acl_mapping is None:
-            raise error.ConfigurationError("No acl configuration specified! You need to define a acl_mapping. "
-                                           "For further reference, please see HelpOnStorageConfiguration.")
+            raise error.ConfigurationError(
+                "No acl configuration specified! You need to define a acl_mapping. "
+                "For further reference, please see HelpOnStorageConfiguration.")
 
         if self.secrets is None:  # admin did not setup a real secret
-            raise error.ConfigurationError("No secret configured! You need to set secrets = 'somelongsecretstring' in your wiki config.")
+            raise error.ConfigurationError(
+                "No secret configured! You need to set secrets = 'somelongsecretstring' in your wiki config.")
 
         if self.interwikiname is None:  # admin did not setup a real interwikiname
-            raise error.ConfigurationError("No interwikiname configured! You need to set interwikiname = u'YourUniqueStableInterwikiName' in your wiki config.")
+            raise error.ConfigurationError(
+                "No interwikiname configured! "
+                "You need to set interwikiname = u'YourUniqueStableInterwikiName' in your wiki config.")
 
         secret_key_names = ['security/ticket', ]
         if self.textchas:
@@ -137,8 +145,9 @@
         secret_min_length = 10
         if isinstance(self.secrets, str):
             if len(self.secrets) < secret_min_length:
-                raise error.ConfigurationError("The secrets = '...' wiki config setting is a way too short string (minimum length is {0} chars)!".format(
-                    secret_min_length))
+                raise error.ConfigurationError(
+                    "The secrets = '...' wiki config setting is a way too short string "
+                    "(minimum length is {0} chars)!".format(secret_min_length))
             # for lazy people: set all required secrets to same value
             secrets = {}
             for key in secret_key_names:
@@ -152,7 +161,8 @@
                 if len(secret) < secret_min_length:
                     raise ValueError
             except (KeyError, ValueError):
-                raise error.ConfigurationError("You must set a (at least {0} chars long) secret string for secrets['{1}']!".format(
+                raise error.ConfigurationError(
+                    "You must set a (at least {0} chars long) secret string for secrets['{1}']!".format(
                     secret_min_length, secret_key_name))
 
         from passlib.context import CryptContext
@@ -173,7 +183,7 @@
         unknown = ['"{0}"'.format(name) for name in dir(self)
                   if not name.startswith('_') and
                   name not in DefaultConfig.__dict__ and
-                  not isinstance(getattr(self, name), (type(sys), type(DefaultConfig)))]
+                  not isinstance(getattr(self, name), (type(re), type(DefaultConfig)))]
         if unknown:
             msg = """
 Unknown configuration options: {0}.
@@ -275,9 +285,9 @@
        username_lower in password_lower or password_lower in username_lower:
         return _("Password is too easy to guess (password contains name or name contains password).")
 
-    keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./", # US kbd
-                 ur"^1234567890ß´qwertzuiopü+asdfghjklöä#yxcvbnm,.-", # german kbd
-                ) # add more keyboards!
+    keyboards = (ur"`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./",  # US kbd
+                 ur"^1234567890ß´qwertzuiopü+asdfghjklöä#yxcvbnm,.-",  # german kbd
+                )  # TODO add more keyboards!
     for kbd in keyboards:
         rev_kbd = kbd[::-1]
         if password in kbd or password in rev_kbd or \
@@ -466,35 +476,35 @@
   # ==========================================================================
   'user': ('User Preferences', None, (
     ('user_defaults',
-      dict(
-        name=[],
-        display_name=None,
-        email=None,
-        openid=None,
-        css_url=None,
-        mailto_author=False,
-        edit_on_doubleclick=True,
-        scroll_page_after_edit=True,
-        show_comments=False,
-        want_trivial=False,
-        enc_password=u'',  # empty value == invalid hash
-        disabled=False,
-        bookmarks={},
-        quicklinks=[],
-        subscribed_items=[],
-        email_subscribed_events=[
+     {
+        NAME: [],
+        DISPLAY_NAME: None,
+        EMAIL: None,
+        OPENID: None,
+        CSS_URL: None,
+        MAILTO_AUTHOR: False,
+        EDIT_ON_DOUBLECLICK: True,
+        SCROLL_PAGE_AFTER_EDIT: True,
+        SHOW_COMMENTS: False,
+        WANT_TRIVIAL: False,
+        ENC_PASSWORD: u'',  # empty value == invalid hash
+        DISABLED: False,
+        BOOKMARKS: {},
+        QUICKLINKS: [],
+        SUBSCRIBED_ITEMS: [],
+        EMAIL_SUBSCRIBED_EVENTS: [
             # XXX PageChangedEvent.__name__
             # XXX PageRenamedEvent.__name__
             # XXX PageDeletedEvent.__name__
             # XXX PageCopiedEvent.__name__
             # XXX PageRevertedEvent.__name__
         ],
-        theme_name=None, # None -> use cfg.theme_default
-        edit_rows=0,
-        results_per_page=0,
-        locale=None, # None -> do browser language detection, otherwise just use this locale
-        timezone=None, # None -> use cfg.timezone_default
-      ),
+        THEME_NAME: None,  # None -> use cfg.theme_default
+        EDIT_ROWS: 0,
+        RESULTS_PER_PAGE: 0,
+        LOCALE: None,  # None -> do browser language detection, otherwise just use this locale
+        TIMEZONE: None,  # None -> use cfg.timezone_default
+     },
      'Default attributes of the user object'),
   )),
   # ==========================================================================
@@ -525,8 +535,8 @@
     ('refresh', None,
      "refresh = (minimum_delay_s, targets_allowed) enables use of `#refresh 5 PageName` processing instruction, targets_allowed must be either `'internal'` or `'external'`"),
 
-    ('siteid', 'MoinMoin', None), # XXX just default to some existing module name to
-                                  # make plugin loader etc. work for now
+    ('siteid', 'MoinMoin', None),  # XXX just default to some existing module name to
+                                   # make plugin loader etc. work for now
   )),
 }
 
@@ -559,9 +569,9 @@
     (
       ('functions', u'',
        'Access Control List for functions.'),
-      ('rights_contents', config.ACL_RIGHTS_CONTENTS,
+      ('rights_contents', ACL_RIGHTS_CONTENTS,
        'Valid tokens for right sides of content ACL entries.'),
-      ('rights_functions', config.ACL_RIGHTS_FUNCTIONS,
+      ('rights_functions', ACL_RIGHTS_FUNCTIONS,
        'Valid tokens for right sides of function ACL entries.'),
     )),
 
@@ -596,6 +606,7 @@
     )),
 }
 
+
 def _add_options_to_defconfig(opts, addgroup=True):
     for groupname in opts:
         group_short, group_doc, group_opts = opts[groupname]
--- a/MoinMoin/conftest.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/conftest.py	Sat Feb 16 23:21:46 2013 +0100
@@ -20,8 +20,8 @@
 
 # exclude some directories from py.test test discovery, pathes relative to this file
 collect_ignore = ['static',  # same
-                  '../wiki', # no tests there
-                  '../instance', # tw likes to use this for wiki data (non-revisioned)
+                  '../wiki',  # no tests there
+                  '../instance',  # tw likes to use this for wiki data (non-revisioned)
                  ]
 import atexit
 import os
@@ -32,8 +32,7 @@
 import py
 import MoinMoin.log
 
-""" Logging for tests to avoid useless output like timing information on stderr on test failures
-"""
+# Logging for tests to avoid useless output like timing information on stderr on test failures
 Moindir = py.path.local(__file__).dirname
 config_file = Moindir + '/_tests/test_logging.conf'
 MoinMoin.log.load_config(config_file)
@@ -50,10 +49,10 @@
         namespace_mapping=namespace_mapping,
         backend_mapping=backend_mapping,
         acl_mapping=acl_mapping,
-        create_storage=True, # create a fresh storage at each app start
-        destroy_storage=True, # kill all storage contents at app shutdown
-        create_index=True, # create a fresh index at each app start
-        destroy_index=True, # kill index contents at app shutdown
+        create_storage=True,  # create a fresh storage at each app start
+        destroy_storage=True,  # kill all storage contents at app shutdown
+        create_index=True,  # create a fresh index at each app start
+        destroy_index=True,  # kill index contents at app shutdown
     )
     app = create_app_ext(flask_config_dict=dict(SECRET_KEY='foobarfoobar'),
                          moin_config_class=given_config,
@@ -63,6 +62,7 @@
     before_wiki()
     return app, ctx
 
+
 def deinit_test_app(app, ctx):
     teardown_wiki('')
     ctx.pop()
@@ -74,6 +74,7 @@
 prev_ctx = None
 prev_cfg = None
 
+
 class MoinTestFunction(pytest.collect.Function):
     def setup(self):
         global prev_app, prev_ctx, prev_cfg
@@ -109,10 +110,12 @@
 def pytest_pycollect_makemodule(path, parent):
     return Module(path, parent=parent)
 
+
 def pytest_pycollect_makeitem(__multicall__, collector, name, obj):
     if collector.funcnamefilter(name) and inspect.isfunction(obj):
         return MoinTestFunction(name, parent=collector)
 
+
 def pytest_pyfunc_call(pyfuncitem):
     """hook to intercept generators and run them as a single test items"""
     if inspect.isgeneratorfunction(pyfuncitem.obj):
@@ -120,9 +123,11 @@
             kwarg = item[1:]
             item[0](*kwarg)
 
+
 def pytest_report_header(config):
     return "The tests here are implemented only for pytest-2"
 
+
 class Module(pytest.collect.Module):
     def run(self, *args, **kwargs):
         if coverage is not None:
--- a/MoinMoin/constants/chartypes.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/chartypes.py	Sat Feb 16 23:21:46 2013 +0100
@@ -1,8 +1,8 @@
-
-chars_upper = u"\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u00de\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189\u018a\u018b\u018e\u018f\u0190\u0191\u0193\u0194\u0196\u0197\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1\u01b2\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6\u01f7\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u0386\u0388\u0389\u038a\u038c\u038e\u038f\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03d2\u03d3\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u040d\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f8\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0531\u0532\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053a\u053b\u053c\u053d\u053e\u053f\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548\u0549\u054a\u054b\u054c\u054d\u054e\u054f\u0550\u0551\u0552\u0553\u0554\u0555\u0556\u10a0\u10a1\u10a2\u10a3\u10a4\u10a5\u10a6\u10a7\u10a8\u10a9\u10aa\u10ab\u10ac\u10ad\u10ae\u10af\u10b0\u10b1\u10b2\u10b3\u10b4\u10b5\u10b6\u10b7\u10b8\u10b9\u10ba\u10bb\u10bc\u10bd\u10be\u10bf\u10c0\u10c1\u10c2\u10c3\u10c4\u10c5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f28\u1f29\u1f2a\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u1f3d\u1f3e\u1f3f\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68\u1f69\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1fb8\u1fb9\u1fba\u1fbb\u1fc8\u1fc9\u1fca\u1fcb\u1fd8\u1fd9\u1fda\u1fdb\u1fe8\u1fe9\u1fea\u1feb\u1fec\u1ff8\u1ff9\u1ffa\u1ffb\u2102\u2107\u210b\u210c\u210d\u2110\u2111\u2112\u2115\u2119\u211a\u211b\u211c\u211d\u2124\u2126\u2128\u212a\u212b\u212c\u212d\u2130\u2131\u2133\u213e\u213f\u2145\uff21\uff22\uff23\uff24\uff25\uff26\uff27\uff28\uff29\uff2a\uff2b\uff2c\uff2d\uff2e\uff2f\uff30\uff31\uff32\uff33\uff34\uff35\uff36\uff37\uff38\uff39\uff3a"
 
-chars_lower = u"\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u00aa\u00b5\u00ba\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e\u017f\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199\u019a\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd\u01be\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233\u0250\u0251\u0252\u0253\u0254\u0255\u0256\u0257\u0258\u0259\u025a\u025b\u025c\u025d\u025e\u025f\u0260\u0261\u0262\u0263\u0264\u0265\u0266\u0267\u0268\u0269\u026a\u026b\u026c\u026d\u026e\u026f\u0270\u0271\u0272\u0273\u0274\u0275\u0276\u0277\u0278\u0279\u027a\u027b\u027c\u027d\u027e\u027f\u0280\u0281\u0282\u0283\u0284\u0285\u0286\u0287\u0288\u0289\u028a\u028b\u028c\u028d\u028e\u028f\u0290\u0291\u0292\u0293\u0294\u0295\u0296\u0297\u0298\u0299\u029a\u029b\u029c\u029d\u029e\u029f\u02a0\u02a1\u02a2\u02a3\u02a4\u02a5\u02a6\u02a7\u02a8\u02a9\u02aa\u02ab\u02ac\u02ad\u0390\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\u03d0\u03d1\u03d5\u03d6\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef\u03f0\u03f1\u03f2\u03f3\u03f5\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0450\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045d\u045e\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f9\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0561\u0562\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056a\u056b\u056c\u056d\u056e\u056f\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578\u0579\u057a\u057b\u057c\u057d\u057e\u057f\u0580\u0581\u0582\u0583\u0584\u0585\u0586\u0587\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95\u1e96\u1e97\u1e98\u1e99\u1e9a\u1e9b\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1f00\u1f01\u1f02\u1f03\u1f04\u1f05\u1f06\u1f07\u1f10\u1f11\u1f12\u1f13\u1f14\u1f15\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u1f30\u1f31\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f40\u1f41\u1f42\u1f43\u1f44\u1f45\u1f50\u1f51\u1f52\u1f53\u1f54\u1f55\u1f56\u1f57\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u1f67\u1f70\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u1f7c\u1f7d\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f90\u1f91\u1f92\u1f93\u1f94\u1f95\u1f96\u1f97\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u1fa6\u1fa7\u1fb0\u1fb1\u1fb2\u1fb3\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2\u1fc3\u1fc4\u1fc6\u1fc7\u1fd0\u1fd1\u1fd2\u1fd3\u1fd6\u1fd7\u1fe0\u1fe1\u1fe2\u1fe3\u1fe4\u1fe5\u1fe6\u1fe7\u1ff2\u1ff3\u1ff4\u1ff6\u1ff7\u2071\u207f\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213d\u2146\u2147\u2148\u2149\ufb00\ufb01\ufb02\ufb03\ufb04\ufb05\ufb06\ufb13\ufb14\ufb15\ufb16\ufb17\uff41\uff42\uff43\uff44\uff45\uff46\uff47\uff48\uff49\uff4a\uff4b\uff4c\uff4d\uff4e\uff4f\uff50\uff51\uff52\uff53\uff54\uff55\uff56\uff57\uff58\uff59\uff5a\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00b2\u00b3\u00b9\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc\u24fd\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u278a\u278b\u278c\u278d\u278e\u278f\u2790\u2791\u2792\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19"
+CHARS_UPPER = u"\u0041\u0042\u0043\u0044\u0045\u0046\u0047\u0048\u0049\u004a\u004b\u004c\u004d\u004e\u004f\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057\u0058\u0059\u005a\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d8\u00d9\u00da\u00db\u00dc\u00dd\u00de\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d\u0181\u0182\u0184\u0186\u0187\u0189\u018a\u018b\u018e\u018f\u0190\u0191\u0193\u0194\u0196\u0197\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1\u01b2\u01b3\u01b5\u01b7\u01b8\u01bc\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6\u01f7\u01f8\u01fa\u01fc\u01fe\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u0386\u0388\u0389\u038a\u038c\u038e\u038f\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03d2\u03d3\u03d4\u03d8\u03da\u03dc\u03de\u03e0\u03e2\u03e4\u03e6\u03e8\u03ea\u03ec\u03ee\u03f4\u0400\u0401\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b\u040c\u040d\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0460\u0462\u0464\u0466\u0468\u046a\u046c\u046e\u0470\u0472\u0474\u0476\u0478\u047a\u047c\u047e\u0480\u048a\u048c\u048e\u0490\u0492\u0494\u0496\u0498\u049a\u049c\u049e\u04a0\u04a2\u04a4\u04a6\u04a8\u04aa\u04ac\u04ae\u04b0\u04b2\u04b4\u04b6\u04b8\u04ba\u04bc\u04be\u04c0\u04c1\u04c3\u04c5\u04c7\u04c9\u04cb\u04cd\u04d0\u04d2\u04d4\u04d6\u04d8\u04da\u04dc\u04de\u04e0\u04e2\u04e4\u04e6\u04e8\u04ea\u04ec\u04ee\u04f0\u04f2\u04f4\u04f8\u0500\u0502\u0504\u0506\u0508\u050a\u050c\u050e\u0531\u0532\u0533\u0534\u0535\u0536\u0537\u0538\u0539\u053a\u053b\u053c\u053d\u053e\u053f\u0540\u0541\u0542\u0543\u0544\u0545\u0546\u0547\u0548\u0549\u054a\u054b\u054c\u054d\u054e\u054f\u0550\u0551\u0552\u0553\u0554\u0555\u0556\u10a0\u10a1\u10a2\u10a3\u10a4\u10a5\u10a6\u10a7\u10a8\u10a9\u10aa\u10ab\u10ac\u10ad\u10ae\u10af\u10b0\u10b1\u10b2\u10b3\u10b4\u10b5\u10b6\u10b7\u10b8\u10b9\u10ba\u10bb\u10bc\u10bd\u10be\u10bf\u10c0\u10c1\u10c2\u10c3\u10c4\u10c5\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1f08\u1f09\u1f0a\u1f0b\u1f0c\u1f0d\u1f0e\u1f0f\u1f18\u1f19\u1f1a\u1f1b\u1f1c\u1f1d\u1f28\u1f29\u1f2a\u1f2b\u1f2c\u1f2d\u1f2e\u1f2f\u1f38\u1f39\u1f3a\u1f3b\u1f3c\u1f3d\u1f3e\u1f3f\u1f48\u1f49\u1f4a\u1f4b\u1f4c\u1f4d\u1f59\u1f5b\u1f5d\u1f5f\u1f68\u1f69\u1f6a\u1f6b\u1f6c\u1f6d\u1f6e\u1f6f\u1fb8\u1fb9\u1fba\u1fbb\u1fc8\u1fc9\u1fca\u1fcb\u1fd8\u1fd9\u1fda\u1fdb\u1fe8\u1fe9\u1fea\u1feb\u1fec\u1ff8\u1ff9\u1ffa\u1ffb\u2102\u2107\u210b\u210c\u210d\u2110\u2111\u2112\u2115\u2119\u211a\u211b\u211c\u211d\u2124\u2126\u2128\u212a\u212b\u212c\u212d\u2130\u2131\u2133\u213e\u213f\u2145\uff21\uff22\uff23\uff24\uff25\uff26\uff27\uff28\uff29\uff2a\uff2b\uff2c\uff2d\uff2e\uff2f\uff30\uff31\uff32\uff33\uff34\uff35\uff36\uff37\uff38\uff39\uff3a"
 
-chars_digits = u"\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00b2\u00b3\u00b9\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc\u24fd\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u278a\u278b\u278c\u278d\u278e\u278f\u2790\u2791\u2792\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19"
+CHARS_LOWER = u"\u0061\u0062\u0063\u0064\u0065\u0066\u0067\u0068\u0069\u006a\u006b\u006c\u006d\u006e\u006f\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077\u0078\u0079\u007a\u00aa\u00b5\u00ba\u00df\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff\u0101\u0103\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117\u0119\u011b\u011d\u011f\u0121\u0123\u0125\u0127\u0129\u012b\u012d\u012f\u0131\u0133\u0135\u0137\u0138\u013a\u013c\u013e\u0140\u0142\u0144\u0146\u0148\u0149\u014b\u014d\u014f\u0151\u0153\u0155\u0157\u0159\u015b\u015d\u015f\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173\u0175\u0177\u017a\u017c\u017e\u017f\u0180\u0183\u0185\u0188\u018c\u018d\u0192\u0195\u0199\u019a\u019b\u019e\u01a1\u01a3\u01a5\u01a8\u01aa\u01ab\u01ad\u01b0\u01b4\u01b6\u01b9\u01ba\u01bd\u01be\u01bf\u01c6\u01c9\u01cc\u01ce\u01d0\u01d2\u01d4\u01d6\u01d8\u01da\u01dc\u01dd\u01df\u01e1\u01e3\u01e5\u01e7\u01e9\u01eb\u01ed\u01ef\u01f0\u01f3\u01f5\u01f9\u01fb\u01fd\u01ff\u0201\u0203\u0205\u0207\u0209\u020b\u020d\u020f\u0211\u0213\u0215\u0217\u0219\u021b\u021d\u021f\u0223\u0225\u0227\u0229\u022b\u022d\u022f\u0231\u0233\u0250\u0251\u0252\u0253\u0254\u0255\u0256\u0257\u0258\u0259\u025a\u025b\u025c\u025d\u025e\u025f\u0260\u0261\u0262\u0263\u0264\u0265\u0266\u0267\u0268\u0269\u026a\u026b\u026c\u026d\u026e\u026f\u0270\u0271\u0272\u0273\u0274\u0275\u0276\u0277\u0278\u0279\u027a\u027b\u027c\u027d\u027e\u027f\u0280\u0281\u0282\u0283\u0284\u0285\u0286\u0287\u0288\u0289\u028a\u028b\u028c\u028d\u028e\u028f\u0290\u0291\u0292\u0293\u0294\u0295\u0296\u0297\u0298\u0299\u029a\u029b\u029c\u029d\u029e\u029f\u02a0\u02a1\u02a2\u02a3\u02a4\u02a5\u02a6\u02a7\u02a8\u02a9\u02aa\u02ab\u02ac\u02ad\u0390\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\u03d0\u03d1\u03d5\u03d6\u03d7\u03d9\u03db\u03dd\u03df\u03e1\u03e3\u03e5\u03e7\u03e9\u03eb\u03ed\u03ef\u03f0\u03f1\u03f2\u03f3\u03f5\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0450\u0451\u0452\u0453\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045d\u045e\u045f\u0461\u0463\u0465\u0467\u0469\u046b\u046d\u046f\u0471\u0473\u0475\u0477\u0479\u047b\u047d\u047f\u0481\u048b\u048d\u048f\u0491\u0493\u0495\u0497\u0499\u049b\u049d\u049f\u04a1\u04a3\u04a5\u04a7\u04a9\u04ab\u04ad\u04af\u04b1\u04b3\u04b5\u04b7\u04b9\u04bb\u04bd\u04bf\u04c2\u04c4\u04c6\u04c8\u04ca\u04cc\u04ce\u04d1\u04d3\u04d5\u04d7\u04d9\u04db\u04dd\u04df\u04e1\u04e3\u04e5\u04e7\u04e9\u04eb\u04ed\u04ef\u04f1\u04f3\u04f5\u04f9\u0501\u0503\u0505\u0507\u0509\u050b\u050d\u050f\u0561\u0562\u0563\u0564\u0565\u0566\u0567\u0568\u0569\u056a\u056b\u056c\u056d\u056e\u056f\u0570\u0571\u0572\u0573\u0574\u0575\u0576\u0577\u0578\u0579\u057a\u057b\u057c\u057d\u057e\u057f\u0580\u0581\u0582\u0583\u0584\u0585\u0586\u0587\u1e01\u1e03\u1e05\u1e07\u1e09\u1e0b\u1e0d\u1e0f\u1e11\u1e13\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1e1f\u1e21\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e2d\u1e2f\u1e31\u1e33\u1e35\u1e37\u1e39\u1e3b\u1e3d\u1e3f\u1e41\u1e43\u1e45\u1e47\u1e49\u1e4b\u1e4d\u1e4f\u1e51\u1e53\u1e55\u1e57\u1e59\u1e5b\u1e5d\u1e5f\u1e61\u1e63\u1e65\u1e67\u1e69\u1e6b\u1e6d\u1e6f\u1e71\u1e73\u1e75\u1e77\u1e79\u1e7b\u1e7d\u1e7f\u1e81\u1e83\u1e85\u1e87\u1e89\u1e8b\u1e8d\u1e8f\u1e91\u1e93\u1e95\u1e96\u1e97\u1e98\u1e99\u1e9a\u1e9b\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7\u1ec9\u1ecb\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1\u1ef3\u1ef5\u1ef7\u1ef9\u1f00\u1f01\u1f02\u1f03\u1f04\u1f05\u1f06\u1f07\u1f10\u1f11\u1f12\u1f13\u1f14\u1f15\u1f20\u1f21\u1f22\u1f23\u1f24\u1f25\u1f26\u1f27\u1f30\u1f31\u1f32\u1f33\u1f34\u1f35\u1f36\u1f37\u1f40\u1f41\u1f42\u1f43\u1f44\u1f45\u1f50\u1f51\u1f52\u1f53\u1f54\u1f55\u1f56\u1f57\u1f60\u1f61\u1f62\u1f63\u1f64\u1f65\u1f66\u1f67\u1f70\u1f71\u1f72\u1f73\u1f74\u1f75\u1f76\u1f77\u1f78\u1f79\u1f7a\u1f7b\u1f7c\u1f7d\u1f80\u1f81\u1f82\u1f83\u1f84\u1f85\u1f86\u1f87\u1f90\u1f91\u1f92\u1f93\u1f94\u1f95\u1f96\u1f97\u1fa0\u1fa1\u1fa2\u1fa3\u1fa4\u1fa5\u1fa6\u1fa7\u1fb0\u1fb1\u1fb2\u1fb3\u1fb4\u1fb6\u1fb7\u1fbe\u1fc2\u1fc3\u1fc4\u1fc6\u1fc7\u1fd0\u1fd1\u1fd2\u1fd3\u1fd6\u1fd7\u1fe0\u1fe1\u1fe2\u1fe3\u1fe4\u1fe5\u1fe6\u1fe7\u1ff2\u1ff3\u1ff4\u1ff6\u1ff7\u2071\u207f\u210a\u210e\u210f\u2113\u212f\u2134\u2139\u213d\u2146\u2147\u2148\u2149\ufb00\ufb01\ufb02\ufb03\ufb04\ufb05\ufb06\ufb13\ufb14\ufb15\ufb16\ufb17\uff41\uff42\uff43\uff44\uff45\uff46\uff47\uff48\uff49\uff4a\uff4b\uff4c\uff4d\uff4e\uff4f\uff50\uff51\uff52\uff53\uff54\uff55\uff56\uff57\uff58\uff59\uff5a\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00b2\u00b3\u00b9\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc\u24fd\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u278a\u278b\u278c\u278d\u278e\u278f\u2790\u2791\u2792\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19"
 
-chars_spaces = u"\u0009\u000a\u000b\u000c\u000d\u001c\u001d\u001e\u001f\u0020\u0085\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000"
+CHARS_DIGITS = u"\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u00b2\u00b3\u00b9\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc\u24fd\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u278a\u278b\u278c\u278d\u278e\u278f\u2790\u2791\u2792\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19"
+
+CHARS_SPACES = u"\u0009\u000a\u000b\u000c\u000d\u001c\u001d\u001e\u001f\u0020\u0085\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000"
--- a/MoinMoin/constants/contenttypes.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/contenttypes.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,10 +8,10 @@
 # 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'
+CHARSET = 'utf-8'
 
 # Parser to use mimetype text
-parser_text_mimetype = ('plain', 'csv', 'rst', 'docbook', 'latex', 'tex', 'html', 'css',
+PARSER_TEXT_MIMETYPE = ('plain', 'csv', 'rst', 'docbook', 'latex', 'tex', 'html', 'css',
                        'xml', 'python', 'perl', 'php', 'ruby', 'javascript',
                        'cplusplus', 'java', 'pascal', 'diff', 'gettext', 'xslt', 'creole', )
 
@@ -27,3 +27,5 @@
 GROUP_VIDEO = 'video items'
 GROUP_DRAWING = 'drawing items'
 GROUP_OTHER = 'other items'
+
+DRAWING_EXTENSIONS = ['.tdraw', '.adraw', '.svg', '.png', '.jpg', '.jpeg', '.gif', ]
--- a/MoinMoin/constants/forms.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/forms.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,7 @@
 
 # Widget types
 
-WIDGET_TEXT = u'text' # single-line text
+WIDGET_TEXT = u'text'  # single-line text
 WIDGET_MULTILINE_TEXT = u'multiline_text'
 WIDGET_URL = u'url'
 WIDGET_EMAIL = u'email'
@@ -24,6 +24,7 @@
 WIDGET_HIDDEN = u'hidden'
 
 WIDGET_SELECT = u'select'
+WIDGET_SELECT_SUBMIT = u'select_submit'
 WIDGET_MULTI_SELECT = u'multi_select'
 
 WIDGET_READONLY_STRING_LIST = u'readonly_string_list'
--- a/MoinMoin/constants/keys.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/keys.py	Sat Feb 16 23:21:46 2013 +0100
@@ -53,7 +53,7 @@
 # data. meta[HASH_ALGORITHM] = hash(rev_data, HASH_ALGORITHM)
 # some backends may use this also for other purposes.
 HASH_ALGORITHM = 'sha1'
-HASH_LEN = 40 # length of hex str representation of hash value
+HASH_LEN = 40  # length of hex str representation of hash value
 
 # some field names for whoosh index schema / documents in index:
 NAME_EXACT = "name_exact"
@@ -88,6 +88,8 @@
 CSS_URL = "css_url"
 EDIT_ROWS = "edit_rows"
 RESULTS_PER_PAGE = "results_per_page"
+WANT_TRIVIAL = "want_trivial"
+EMAIL_SUBSCRIBED_EVENTS = "email_subscribed_events"
 DISABLED = "disabled"
 
 # in which backend is some revision stored?
--- a/MoinMoin/constants/misc.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/misc.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,9 +7,11 @@
 
 import re
 
+ANON = u'anonymous'
+
 # 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(
+ITEM_INVALID_CHARS_REGEX = re.compile(
     ur"""
     \u0000 | # NULL
 
@@ -23,7 +25,7 @@
     re.UNICODE | re.VERBOSE
     )
 
-clean_input_translation_map = {
+CLEAN_INPUT_TRANSLATION_MAP = {
     # these chars will be replaced by blanks
     ord(u'\t'): u' ',
     ord(u'\r'): u' ',
@@ -32,11 +34,11 @@
 for c in u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f' \
           '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f':
     # these chars will be removed
-    clean_input_translation_map[ord(c)] = None
+    CLEAN_INPUT_TRANSLATION_MAP[ord(c)] = None
 del c
 
 # Other stuff
-uri_schemes = ['http', 'https', 'ftp', 'file',
+URI_SCHEMES = ['http', 'https', 'ftp', 'file',
                'mailto', 'nntp', 'news',
                'ssh', 'telnet', 'irc', 'ircs', 'xmpp', 'mumble',
                'webcal', 'ed2k', 'apt', 'rootz',
--- a/MoinMoin/constants/tools/chartypes_create.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/constants/tools/chartypes_create.py	Sat Feb 16 23:21:46 2013 +0100
@@ -25,18 +25,18 @@
             space.append(str)
 
     chars_upper = u''.join(uppercase)
-    chars_lower = u''.join(lowercase+digits)
+    chars_lower = u''.join(lowercase + digits)
     chars_digits = u''.join(digits)
     chars_spaces = u''.join(space)
 
     print """
-chars_upper = u"%(chars_upper)s"
+CHARS_UPPER = u"%(chars_upper)s"
 
-chars_lower = u"%(chars_lower)s"
+CHARS_LOWER = u"%(chars_lower)s"
 
-chars_digits = u"%(chars_digits)s"
+CHARS_DIGITS = u"%(chars_digits)s"
 
-chars_spaces = u"%(chars_spaces)s"
+CHARS_SPACES = u"%(chars_spaces)s"
 
 
 """ % locals()
--- a/MoinMoin/converter/_args_wiki.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_args_wiki.py	Sat Feb 16 23:21:46 2013 +0100
@@ -32,6 +32,7 @@
 '''
 _parse_re = re.compile(_parse_rules, re.X)
 
+
 def parse(input):
     """
     Parse <input> for positional and keyword arguments, with value quoting and
@@ -57,6 +58,7 @@
 _unparse_rules = r'''^[-\w]+$'''
 _unparse_re = re.compile(_unparse_rules, re.X)
 
+
 def unparse(args):
     """
     Generate a argument string from a Argument instance <args>.
--- a/MoinMoin/converter/_table.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_table.py	Sat Feb 16 23:21:46 2013 +0100
@@ -13,6 +13,7 @@
 
 WORDBREAK_LEN = 30
 
+
 class TableMixin(object):
     """
     Mixin to support building a DOM table.
--- a/MoinMoin/converter/_tests/test__args_wiki.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test__args_wiki.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import pytest
-
 from MoinMoin.converter._args_wiki import *
 
 def test():
--- a/MoinMoin/converter/_tests/test__wiki_macro.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test__wiki_macro.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,6 @@
 """
 
 
-import pytest
 import re
 
 from MoinMoin.converter._args import Arguments
--- a/MoinMoin/converter/_tests/test_creole_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_creole_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import pytest
-
 import re
 
 from MoinMoin.util.tree import moin_page, xlink
--- a/MoinMoin/converter/_tests/test_docbook_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_docbook_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,6 +11,7 @@
 import StringIO
 
 import pytest
+
 try:
     from lxml import etree
 except:
--- a/MoinMoin/converter/_tests/test_docbook_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_docbook_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,6 +10,7 @@
 import StringIO
 
 import pytest
+
 try:
     from lxml import etree
 except:
--- a/MoinMoin/converter/_tests/test_include.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_include.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,11 +6,9 @@
 """
 
 
-import pytest
-
 from MoinMoin.converter.include import *
 from MoinMoin.items import Item
-from MoinMoin.config import CONTENTTYPE
+from MoinMoin.constants.keys import CONTENTTYPE
 from MoinMoin._tests import wikiconfig, update_item
 
 class TestInclude(object):
--- a/MoinMoin/converter/_tests/test_moinwiki_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_moinwiki_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,6 @@
 """
 
 
-import pytest
 import re
 
 from MoinMoin.converter.moinwiki_out import *
--- a/MoinMoin/converter/_tests/test_registry.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_registry.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import pytest
-
 from MoinMoin.util.mime import Type, type_moin_document, type_moin_wiki
 from MoinMoin.converter import default_registry
 from MoinMoin.converter.text_in import Converter as TextInConverter
--- a/MoinMoin/converter/_tests/test_rst_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_rst_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,6 @@
 """
 
 
-import pytest
 import re
 
 from MoinMoin.converter.rst_in import *
--- a/MoinMoin/converter/_tests/test_rst_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_tests/test_rst_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,6 @@
 """
 
 
-import pytest
 import re
 
 from MoinMoin.converter.rst_out import *
--- a/MoinMoin/converter/_util.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_util.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,14 +12,16 @@
 from flask import g as flaskg
 from emeraldtree import ElementTree as ET
 
-from MoinMoin.config import uri_schemes
+from MoinMoin.constants.misc import URI_SCHEMES
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.mime import Type
 from MoinMoin.util.tree import html, moin_page
 
+
 def allowed_uri_scheme(uri):
     parsed = Iri(uri)
-    return not parsed.scheme or parsed.scheme in uri_schemes
+    return not parsed.scheme or parsed.scheme in URI_SCHEMES
+
 
 def decode_data(data, contenttype=None):
     """
@@ -42,7 +44,8 @@
             coding = ct.parameters.get('charset', coding)
         data = data.decode(coding)
     if not isinstance(data, unicode):
-        raise TypeError("data must be rev or str (requires contenttype with charset) or unicode, but we got {0!r}".format(data))
+        raise TypeError("data must be rev or str (requires contenttype with charset) or unicode, "
+                        "but we got {0!r}".format(data))
     return data
 
 
@@ -119,7 +122,8 @@
         """
         if request.user_agent and flaskg.user.edit_on_doubleclick:
             # this is not py.test and user has option to edit on doubleclick
-            # TODO: move the 2 lines above and 2 related import statements outside of the converters (needed for standalone converter)
+            # TODO: move the 2 lines above and 2 related import statements outside of the converters
+            # (this is needed for a standalone converter)
             if self.last_lineno != self.iter_content.lineno:
                 # avoid adding same lineno to parent and multiple children or grand-children
                 elem.attrib[html.data_lineno] = self.iter_content.lineno
--- a/MoinMoin/converter/_wiki_macro.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/_wiki_macro.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,6 +16,7 @@
 from MoinMoin.util.mime import Type
 from MoinMoin.util.tree import moin_page, xinclude
 
+
 class ConverterMacro(object):
     def _BR_repl(self, args, text, context_block):
         if context_block:
@@ -42,8 +43,8 @@
             return text
 
         pagename = args[0]
-        heading = None # TODO
-        level = None # TODO
+        heading = None  # TODO
+        level = None  # TODO
         sort = 'sort' in args and args['sort']
         if sort and sort not in ('ascending', 'descending'):
             raise RuntimeError
--- a/MoinMoin/converter/archive_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/archive_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -27,6 +27,7 @@
     exception class used in case of trouble with opening/listing an archive
     """
 
+
 class ArchiveConverter(TableMixin):
     """
     Base class for archive converters, convert an archive to a DOM table
@@ -39,7 +40,8 @@
     def process_name(self, member_name):
         name = unicode(member_name, 'utf-8')
         attrib = {
-            xlink.href: Iri(scheme='wiki', authority='', path='/'+self.item_name, query=u'do=get&member={0}'.format(name)),
+            xlink.href: Iri(scheme='wiki', authority='', path='/' + self.item_name,
+                            query=u'do=get&member={0}'.format(name)),
         }
         return moin_page.a(attrib=attrib, children=[name, ])
 
@@ -113,7 +115,7 @@
                     # display only normal files, not directories
                     rows.append((
                         zinfo.file_size,
-                        datetime(*zinfo.date_time), # y,m,d,h,m,s
+                        datetime(*zinfo.date_time),  # y,m,d,h,m,s
                         zinfo.filename,
                     ))
             return rows
--- a/MoinMoin/converter/audio_video_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/audio_video_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -31,7 +31,8 @@
         item_name = rev.item.name
         attrib = {
             moin_page.type_: unicode(self.input_type),
-            xlink.href: Iri(scheme='wiki', authority='', path='/'+item_name, query='do=get&rev={0}'.format(rev.revid)),
+            xlink.href: Iri(scheme='wiki', authority='', path='/' + item_name,
+                            query='do=get&rev={0}'.format(rev.revid)),
         }
         obj = moin_page.object_(attrib=attrib, children=[u'Your Browser does not support HTML5 audio/video element.', ])
         body = moin_page.body(children=(obj, ))
--- a/MoinMoin/converter/creole_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/creole_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -27,7 +27,7 @@
 
 import re
 
-from MoinMoin import config
+from MoinMoin.constants.misc import URI_SCHEMES
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import moin_page, xlink, xinclude
 
@@ -330,9 +330,9 @@
         """Handle all kinds of links."""
 
         if link_page is not None:
-            att = 'attachment:' # moin 1.9 needed this for an attached file
+            att = 'attachment:'  # moin 1.9 needed this for an attached file
             if link_page.startswith(att):
-                link_page = '/' + link_page[len(att):] # now we have a subitem
+                link_page = '/' + link_page[len(att):]  # now we have a subitem
             target = unicode(Iri(scheme='wiki.local', path=link_page))
             text = link_page
         else:
@@ -406,9 +406,9 @@
         """Handles objects included in the page."""
 
         if object_page is not None:
-            att = 'attachment:' # moin 1.9 needed this for an attached file
+            att = 'attachment:'  # moin 1.9 needed this for an attached file
             if object_page.startswith(att):
-                object_page = '/' + object_page[len(att):] # now we have a subitem
+                object_page = '/' + object_page[len(att):]  # now we have a subitem
             target = Iri(scheme='wiki.local', path=object_page)
             text = object_page
 
@@ -436,7 +436,7 @@
             )
             ($ | (?=\s | [,.:;!?()] (\s | $)))
         )
-    """ % dict(uri_schemes='|'.join(config.uri_schemes))
+    """ % dict(uri_schemes='|'.join(URI_SCHEMES))
 
     def inline_url_repl(self, stack, url, url_target, escaped_url=None):
         """Handle raw urls in text."""
--- a/MoinMoin/converter/docbook_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/docbook_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -32,6 +32,7 @@
 class NameSpaceError(Exception):
     pass
 
+
 class Converter(object):
     """
     Converter application/docbook+xml -> x.moin.document
@@ -43,7 +44,7 @@
 
     # DocBook elements which are completely ignored by our converter
     # We even do not process children of these elements
-    ignored_tags = set([# Info elements
+    ignored_tags = set([  # Info elements
                        'abstract', 'artpagenums', 'annotation',
                        'artpagenums', 'author', 'authorgroup',
                        'authorinitials', 'bibliocoverage', 'biblioid',
@@ -383,15 +384,15 @@
         for child in element:
             if isinstance(child, ET.Element):
                 if child.tag.name in self.media_tags:
-                    #XXX: Check the spec to be sure that object tag have only one child.
-                    #TODO: Better way to do it
+                    # XXX: Check the spec to be sure that object tag have only one child.
+                    # TODO: Better way to do it
                     prefered_format, data_tag, mimetype = self.media_tags[child.tag.name]
                     object_element = child
                     for grand_child in child:
                         if isinstance(grand_child, ET.Element):
                             object_data.append(grand_child)
                 if child.tag.name == 'caption':
-                    caption = self.do_children(child, depth+1)[0]
+                    caption = self.do_children(child, depth + 1)[0]
                 if child.tag.name == 'textobject':
                     text_object = child
         return self.visit_data_element(object_element, depth, object_data,
@@ -410,7 +411,7 @@
             if not text_object:
                 return
             else:
-                children = self.do_children(child, depth+1)[0]
+                children = self.do_children(child, depth + 1)[0]
                 return self.new(moin_page.p, attrib={},
                                 children=children)
         # We try to determine the best object to show
@@ -430,7 +431,7 @@
         # If we could not find any suitable object, we return
         # the text replacement.
         if not object_to_show:
-            children = self.do_children(child, depth+1)[0]
+            children = self.do_children(child, depth + 1)[0]
             return self.new(moin_page.p, attrib={},
                             children=children)
 
@@ -488,9 +489,9 @@
         for child in element:
             if isinstance(child, ET.Element):
                 if child.tag.name == "attribution":
-                    source = self.do_children(child, depth+1)
+                    source = self.do_children(child, depth + 1)
                 else:
-                    children.extend(self.do_children(child, depth+1))
+                    children.extend(self.do_children(child, depth + 1))
             else:
                 children.append(child)
         attrib = {}
@@ -555,7 +556,7 @@
             #XXX: Improve error
             raise SyntaxError("para child missing for formalpara element")
 
-        children = self.do_children(para_element, depth+1)[0]
+        children = self.do_children(para_element, depth + 1)[0]
         attrib = {}
         attrib[html('title')] = title_element[0]
         return self.new(moin_page.p, attrib=attrib, children=children)
@@ -980,7 +981,7 @@
         href = element.get(docbook.url)
         # Since it is an element of DocBook v.4,
         # The namespace does not always work, so we will try to retrive the attribute whatever
-        if not(href):
+        if not href:
             for key, value in element.attrib.iteritems():
                 if key.name == 'url' and allowed_uri_scheme(value):
                     href = value
--- a/MoinMoin/converter/docbook_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/docbook_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -335,7 +335,7 @@
                     if child.tag.name == 'note-body':
                         body = self.do_children(child)
         # We process note only with note-body child
-        if not(body):
+        if not body:
             return
 
         body = self.new(docbook.simpara, attrib={}, children=body)
@@ -441,7 +441,7 @@
         for item in element:
             if item.tag.uri == moin_page and item.tag.name == 'body':
                 c = self.do_children(item)
-                if not(c):
+                if not c:
                     self.section_children = sorted(self.section_children.items(),
                                                    reverse=True)
                     section = None
--- a/MoinMoin/converter/everything.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/everything.py	Sat Feb 16 23:21:46 2013 +0100
@@ -25,7 +25,8 @@
     def __call__(self, rev, contenttype=None, arguments=None):
         item_name = rev.item.name
         attrib = {
-            xlink.href: Iri(scheme='wiki', authority='', path='/'+item_name, query='do=get&rev={0}'.format(rev.revid)),
+            xlink.href: Iri(scheme='wiki', authority='', path='/' + item_name,
+                            query='do=get&rev={0}'.format(rev.revid)),
         }
         a = moin_page.a(attrib=attrib, children=[u"Download {0}.".format(item_name)])
         body = moin_page.body(children=(a, ))
--- a/MoinMoin/converter/html_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/html_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -42,7 +42,7 @@
     list_tags = set(['ul', 'dir', 'ol'])
 
     # HTML tags which can be convert without attributes in a different DOM tag
-    simple_tags = {# Emphasis
+    simple_tags = {  # Emphasis
                    'em': moin_page.emphasis, 'i': moin_page.emphasis,
                    # Strong
                    'b': moin_page.strong, 'strong': moin_page.strong,
@@ -480,7 +480,7 @@
         # of <dt><dd>
         for child in element:
             # We need one dt tag, and one dd tag, a have a pair
-            if (child.tag.name == 'dt' or child.tag.name == 'dd'):
+            if child.tag.name == 'dt' or child.tag.name == 'dd':
                 number_pair = number_pair + 1
 
             # The following code is similar to do_children method
@@ -494,7 +494,7 @@
             else:
                 pair.append(r)
 
-            if (number_pair == 2):
+            if number_pair == 2:
                 # We have two elements of the pair
                 # So we can put it into a <list-item> element
                 list_item_element = ET.Element(moin_page.list_item,
--- a/MoinMoin/converter/html_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/html_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -34,6 +34,7 @@
         return re.sub(r'\+get/\+[0-9a-fA-F]+/', '', href)
     return href
 
+
 def mark_item_as_transclusion(elem, href):
     """
     Return elem after adding a "moin-transclusion" class and a "data-href" attribute with
@@ -86,7 +87,7 @@
     visit_style = Attribute('style')
     visit_title = Attribute('title')
     visit_id = Attribute('id')
-    visit_type = Attribute('type') # IE8 needs <object... type="image/svg+xml" ...> to display svg images
+    visit_type = Attribute('type')  # IE8 needs <object... type="image/svg+xml" ...> to display svg images
 
     def __init__(self, element):
         self.element = element
@@ -371,7 +372,7 @@
 
         if obj_type == "img":
             # Images have alt text
-            alt = ''.join(unicode(e) for e in elem) # XXX handle non-text e
+            alt = ''.join(unicode(e) for e in elem)  # XXX handle non-text e
             if alt:
                 attrib[html.alt] = alt
             new_elem = html.img(attrib=attrib)
@@ -401,7 +402,8 @@
 
                     if item[0].tag.name in ('object', 'a'):
                         # png, jpg, gif are objects here, will be changed to img when they are processed
-                        # transclusion is a single inline element "My pet {{bird.jpg}} flys." or "[[SomePage|{{Logo.png}}]]"
+                        # transclusion is a single inline element "My pet {{bird.jpg}} flys." or
+                        # "[[SomePage|{{Logo.png}}]]"
                         return self.new_copy(html.span, item, attribs)
 
                     elif item[0].tag.name == 'p':
@@ -725,11 +727,15 @@
         prefixed_id = '%s-%s' % (self._id.get_id('note-placement'), id)
 
         elem_ref = ET.XML("""
-<html:sup xmlns:html="{0}" html:id="note-{1}-ref" html:class="moin-footnote"><html:a html:href="#note-{2}">{3}</html:a></html:sup>
+<html:sup xmlns:html="{0}" html:id="note-{1}-ref" html:class="moin-footnote">
+<html:a html:href="#note-{2}">{3}</html:a>
+</html:sup>
 """.format(html, prefixed_id, prefixed_id, id))
 
         elem_note = ET.XML("""
-<html:p xmlns:html="{0}" html:id="note-{1}"><html:sup><html:a html:href="#note-{2}-ref">{3}</html:a></html:sup></html:p>
+<html:p xmlns:html="{0}" html:id="note-{1}">
+<html:sup><html:a html:href="#note-{2}-ref">{3}</html:a></html:sup>
+</html:p>
 """.format(html, prefixed_id, prefixed_id, id))
 
         elem_note.extend(body)
--- a/MoinMoin/converter/image_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/image_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -29,7 +29,8 @@
         item_name = rev.item.name
         attrib = {
             moin_page.type_: unicode(self.input_type),
-            xlink.href: Iri(scheme='wiki', authority='', path='/'+item_name, query='do=get&rev={0}'.format(rev.revid)),
+            xlink.href: Iri(scheme='wiki', authority='', path='/' + item_name,
+                            query='do=get&rev={0}'.format(rev.revid)),
         }
         obj = moin_page.object_(attrib=attrib, children=[item_name, ])
         body = moin_page.body(children=(obj, ))
--- a/MoinMoin/converter/include.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/include.py	Sat Feb 16 23:21:46 2013 +0100
@@ -85,7 +85,9 @@
 from __future__ import absolute_import, division
 
 from emeraldtree import ElementTree as ET
-import re, types, copy
+import re
+import types
+import copy
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
@@ -95,7 +97,7 @@
 
 from whoosh.query import Term, And, Wildcard
 
-from MoinMoin.config import NAME, NAME_EXACT, WIKINAME
+from MoinMoin.constants.keys import NAME, NAME_EXACT, WIKINAME
 from MoinMoin.items import Item
 from MoinMoin.util.mime import type_moin_document
 from MoinMoin.util.iri import Iri, IriPath
@@ -106,14 +108,14 @@
 # elements generated by moin wiki markup that cannot have block children
 NO_BLOCK_CHILDREN = [
         'p',
-        'span', # /*comment*/, ~+big+~, ~-small-~ via classes comment, moin-big, moin-small
-        'emphasis', # ''italic''
-        'strong', # '''bold'''
-        'del', # --(stroke)--
-        'ins', # __underline__
-        # 'sub', # ,,subscript,, # no markup allowed within subscripts
-        # 'sup', # ^superscript^ # no markup allowed within superscripts
-        'a', # [[SomeItem|{{logo.png}}]]
+        'span',  # /*comment*/, ~+big+~, ~-small-~ via classes comment, moin-big, moin-small
+        'emphasis',  # ''italic''
+        'strong',  # '''bold'''
+        'del',  # --(stroke)--
+        'ins',  # __underline__
+        # 'sub',  # ,,subscript,, # no markup allowed within subscripts
+        # 'sup',  # ^superscript^ # no markup allowed within superscripts
+        'a',  # [[SomeItem|{{logo.png}}]]
         ]
 
 
@@ -181,6 +183,7 @@
                 data = None
             self.append(self.Entry(''.join(name), None))
 
+
 class Converter(object):
     tag_a = moin_page.a
     tag_div = moin_page.div
@@ -198,7 +201,8 @@
             return cls()
 
     def recurse(self, elem, page_href):
-        # on first call, elem.tag.name=='page'. Descendants (body, div, p, include, page, etc.) are processed by recursing through DOM
+        # on first call, elem.tag.name=='page'.
+        # Descendants (body, div, p, include, page, etc.) are processed by recursing through DOM
 
         # stack is used to detect transclusion loops
         page_href_new = elem.get(self.tag_page_href)
@@ -215,7 +219,8 @@
         try:
             if elem.tag == self.tag_xi_include:
                 # we have already recursed several levels and found a transclusion: "{{SomePage}}" or similar
-                # process the transclusion and add it to the DOM.  Subsequent recursions will traverse through the transclusion's elements.
+                # process the transclusion and add it to the DOM.  Subsequent recursions will traverse through
+                # the transclusion's elements.
                 href = elem.get(self.tag_xi_href)
                 xpointer = elem.get(self.tag_xi_xpointer)
 
@@ -352,7 +357,8 @@
                 #  end of processing for transclusion; the "result" will get inserted into the DOM below
                 return result
 
-            # Traverse the DOM by calling self.recurse with each child of the current elem.  Starting elem.tag.name=='page'.
+            # Traverse the DOM by calling self.recurse with each child of the current elem.
+            # Starting elem.tag.name=='page'.
             container = []
             i = 0
             while i < len(elem):
@@ -370,7 +376,8 @@
                                 # the transcluded item is empty, insert an empty span into DOM
                                 attrib = Attributes(ret).convert()
                                 elem[i] = ET.Element(moin_page.span, attrib=attrib)
-                            elif isinstance(body[0], ET.Node) and (len(body) > 1 or body[0].tag.name not in ('p', 'object', 'a')):
+                            elif (isinstance(body[0], ET.Node) and
+                                  (len(body) > 1 or body[0].tag.name not in ('p', 'object', 'a'))):
                                 # Complex case: "some text {{BlockItem}} more text" or "\n{{BlockItem}}\n" where
                                 # the BlockItem body contains multiple p's, a table, preformatted text, etc.
                                 # These block elements cannot be made a child of the current elem, so we create
@@ -379,30 +386,34 @@
                                 before = copy.deepcopy(elem)
                                 after = copy.deepcopy(elem)
                                 before[:] = elem[0:i]
-                                after[:] = elem[i+1:]
+                                after[:] = elem[i + 1:]
                                 if len(before):
                                     # there are siblings before transclude, save them in container
                                     container.append(before)
                                 new_trans_ptr = len(container)
-                                # get attributes from page node; we expect {class: "moin-transclusion"; data-href: "http://some.org/somepage"}
+                                # get attributes from page node;
+                                # we expect {class: "moin-transclusion"; data-href: "http://some.org/somepage"}
                                 attrib = Attributes(ret).convert()
                                 # make new div node to hold transclusion, copy children, and save in container
                                 div = ET.Element(moin_page.div, attrib=attrib, children=body[:])
-                                container.append(div) # new_trans_ptr is index to this
+                                container.append(div)  # new_trans_ptr is index to this
                                 if len(after):
                                     container.append(after)
                                 if elem.tag.name == 'a':
-                                    # invalid input [[MyPage|{{BlockItem}}]], best option is to retain A-tag and fail html validation
+                                    # invalid input [[MyPage|{{BlockItem}}]],
+                                    # best option is to retain A-tag and fail html validation
                                     # TODO: error may not be obvious to user - add error message
                                     elem[i] = div
                                 else:
-                                    # move up 1 level in recursion where elem becomes the child and is usually replaced by container
+                                    # move up 1 level in recursion where elem becomes the child and
+                                    # is usually replaced by container
                                     return [container, new_trans_ptr]
                             else:
                                 # default action for odd things like circular transclusion error messages
                                 elem[i] = ret
                         elif isinstance(ret, types.ListType):
-                            # a container has been returned. Note: there are two places where a container may be returned
+                            # a container has been returned.
+                            # Note: there are two places where a container may be returned
                             ret_container, trans_ptr = ret
                             # trans_ptr points to the transclusion within ret_container.
                             # Here the transclusion will always contain a block level element
@@ -413,25 +424,29 @@
                                 before = copy.deepcopy(elem)
                                 after = copy.deepcopy(elem)
                                 before[:] = elem[0:i] + ret_container[0:trans_ptr]
-                                after[:] = ret_container[trans_ptr+1:] + elem[i+1:]
+                                after[:] = ret_container[trans_ptr + 1:] + elem[i + 1:]
                                 if len(before):
                                     container.append(before)
                                 new_trans_ptr = len(container)
                                 # child may have classes like "comment" that must be added to transcluded element
                                 classes = child.attrib.get(moin_page.class_, '').split()
-                                classes += ret_container[trans_ptr].attrib.get(html.class_, '').split() # this must be html, not moin_page
-                                ret_container[trans_ptr].attrib[html.class_] = ' '.join(classes) # this must be html, not moin_page
-                                container.append(ret_container[trans_ptr]) # the transclusion
+                                # this must be html, not moin_page:
+                                classes += ret_container[trans_ptr].attrib.get(html.class_, '').split()
+                                # this must be html, not moin_page:
+                                ret_container[trans_ptr].attrib[html.class_] = ' '.join(classes)
+                                container.append(ret_container[trans_ptr])  # the transclusion
                                 if len(after):
                                     container.append(after)
                                 return [container, new_trans_ptr]
                             else:
-                                # elem is a block element, replace child element with the container generated in lower recursion
-                                elem[i:i+1] = ret_container # elem[i] is the child
+                                # elem is a block element,
+                                # replace child element with the container generated in lower recursion
+                                elem[i:i + 1] = ret_container  # elem[i] is the child
                                 # avoid duplicate recursion over nodes already processed
-                                i += len(ret_container) -1
+                                i += len(ret_container) - 1
                         else:
-                            # default action for any ret not fitting special cases above, e.g. tranclusion is within a table cell
+                            # default action for any ret not fitting special cases above,
+                            # e.g. tranclusion is within a table cell
                             elem[i] = ret
                 # we are finished with this child, advance to next sibling
                 i += 1
--- a/MoinMoin/converter/link.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/link.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,7 +14,7 @@
 from flask import g as flaskg
 
 from MoinMoin.util.interwiki import is_known_wiki, url_for_item
-from MoinMoin.util.iri import Iri, IriPath
+from MoinMoin.util.iri import Iri
 from MoinMoin.util.mime import Type, type_moin_document
 from MoinMoin.util.tree import moin_page, xlink, xinclude
 from MoinMoin.wikiutil import AbsItemName
@@ -53,7 +53,7 @@
         """
         Traverses the tree and handles each element appropriately
         """
-        new_page_href=elem.get(__tag_page_href)
+        new_page_href = elem.get(__tag_page_href)
         if new_page_href:
             page = Iri(new_page_href)
 
@@ -129,10 +129,10 @@
                     k, v = kv, ''
                 if k == 'do':
                     do = v
-                    continue # we remove do=xxx from qs
+                    continue  # we remove do=xxx from qs
                 if k == 'rev':
                     rev = v
-                    continue # we remove rev=n from qs
+                    continue  # we remove rev=n from qs
                 result.append(u'{0}={1}'.format(k, v))
         if result:
             query = separator.join(result)
--- a/MoinMoin/converter/macro.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/macro.py	Sat Feb 16 23:21:46 2013 +0100
@@ -22,7 +22,7 @@
 from MoinMoin.converter._args import Arguments
 from MoinMoin.util import iri
 from MoinMoin.util.mime import type_moin_document, Type
-from MoinMoin.util.tree import html, moin_page
+from MoinMoin.util.tree import moin_page
 from MoinMoin.util.plugins import PluginMissingError
 
 
--- a/MoinMoin/converter/markdown_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/markdown_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -25,6 +25,7 @@
 from markdown import Markdown
 import markdown.util as md_util
 
+
 def postproc_text(markdown, text):
     """
     Removes HTML or XML character references and entities from a text string.
@@ -58,10 +59,11 @@
                 text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
             except KeyError:
                 pass
-        return text # leave as is
+        return text  # leave as is
 
     return re.sub("&#?\w+;", fixup, text)
 
+
 class Converter(object):
     # {{{ html conversion
 
@@ -72,7 +74,7 @@
     list_tags = set(['ul', 'dir', 'ol'])
 
     # HTML tags which can be convert without attributes in a different DOM tag
-    simple_tags = {# Emphasis
+    simple_tags = {  # Emphasis
                    'em': moin_page.emphasis, 'i': moin_page.emphasis,
                    # Strong
                    'b': moin_page.strong, 'strong': moin_page.strong,
--- a/MoinMoin/converter/mediawiki_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/mediawiki_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -19,7 +19,8 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import CHARSET
+from MoinMoin.constants.misc import URI_SCHEMES
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import html, moin_page, xlink
 
@@ -335,7 +336,7 @@
                 # TODO: definition list doesn't work,
                 #       if definition of the term on the next line
                 splited_text = text.split(':')
-                list_definition_text=splited_text.pop(0)
+                list_definition_text = splited_text.pop(0)
                 text = ':'.join(splited_text)
 
                 self.parse_inline(list_definition_text, new_stack, self.inline_re)
@@ -482,7 +483,8 @@
         )
     """
 
-    def inline_footnote_repl(self, stack, footnote, footnote_begin=None, footnote_text=None, footnote_end=None, footnote_start=None):
+    def inline_footnote_repl(self, stack, footnote,
+                             footnote_begin=None, footnote_text=None, footnote_end=None, footnote_start=None):
         #stack.top_check('emphasis'):
         if footnote_begin is not None:
             stack.push(moin_page.note(attrib={moin_page.note_class: 'footnote'}))
@@ -591,7 +593,7 @@
             \s*
             \]
         )
-    """ % dict(uri_schemes='|'.join(config.uri_schemes))
+    """ % dict(uri_schemes='|'.join(URI_SCHEMES))
 
     def parse_args(self, input):
         """
@@ -635,7 +637,7 @@
         parsed_args = self.parse_args(link_args[1:])
         query = None
         if parsed_args.keyword:
-            query = url_encode(parsed_args.keyword, charset=config.charset, encode_keys=True)
+            query = url_encode(parsed_args.keyword, charset=CHARSET, encode_keys=True)
         # Take the last of positional parameters as link_text(caption)
         if parsed_args.positional:
             link_text = parsed_args.positional.pop()
@@ -654,7 +656,7 @@
                     if 'do' not in args:
                         # by default, we want the item's get url for transclusion of raw data:
                         args['do'] = 'get'
-                    query = url_encode(args, charset=config.charset, encode_keys=True)
+                    query = url_encode(args, charset=CHARSET, encode_keys=True)
                     target = Iri(scheme='wiki.local', path=object_item, query=query, fragment=None)
                     text = object_item
                 else:
@@ -923,7 +925,8 @@
                                     close_tag = self.Preprocessor_tag()
                                     while tag_name != close_tag.tag_name:
                                         close_tag = tags.pop()
-                                        tmp_line = '<{0}>{1}{2}</{3}>'.format(close_tag.tag, ''.join(close_tag.text), tmp_line, close_tag.tag_name)
+                                        tmp_line = '<{0}>{1}{2}</{3}>'.format(
+                                            close_tag.tag, ''.join(close_tag.text), tmp_line, close_tag.tag_name)
                                         if not len(tags):
                                             post_line.append(tmp_line)
                                         else:
--- a/MoinMoin/converter/moinwiki19_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/moinwiki19_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,10 +16,12 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import config, wikiutil
+from MoinMoin import wikiutil
+from MoinMoin.constants.misc import URI_SCHEMES
+from MoinMoin.constants.chartypes import CHARS_LOWER, CHARS_UPPER
 from MoinMoin.util.interwiki import is_known_wiki
 from MoinMoin.util.iri import Iri
-from MoinMoin.util.tree import html, moin_page, xlink
+from MoinMoin.util.tree import moin_page, xlink
 
 from .moinwiki_in import Converter
 
@@ -42,7 +44,7 @@
           )
           \:
           (?P<freelink_interwiki_page>
-           (?=\S*[%(u)s%(l)s0..9]\S* )  # make sure there is something non-blank with at least one alphanum letter following
+           (?=\S*[%(u)s%(l)s0..9]\S* )  # make sure there is something non-blank with at >= 1 alphanum letter following
            [^\s"\'}\]|:,.\)?!]+  # we take all until we hit some blank or punctuation char ...
           )
           |
@@ -74,8 +76,8 @@
           $  # ... or end of line
          )
     """ % {
-        'u': config.chars_upper,
-        'l': config.chars_lower,
+        'u': CHARS_UPPER,
+        'l': CHARS_LOWER,
         'child': re.escape(wikiutil.CHILD_PREFIX),
         'parent': re.escape(wikiutil.PARENT_PREFIX),
     }
@@ -143,7 +145,7 @@
                 )
             )
         )
-    """ % dict(uri_schemes='|'.join(config.uri_schemes))
+    """ % dict(uri_schemes='|'.join(URI_SCHEMES))
 
     def inline_url_repl(self, stack, url, url_target):
         url = Iri(url_target)
--- a/MoinMoin/converter/moinwiki_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/moinwiki_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -18,9 +18,10 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import CHARSET
+from MoinMoin.constants.misc import URI_SCHEMES
 from MoinMoin.util.iri import Iri
-from MoinMoin.util.tree import html, moin_page, xlink, xinclude
+from MoinMoin.util.tree import moin_page, xlink, xinclude
 from MoinMoin.util.interwiki import is_known_wiki
 from MoinMoin.i18n import _
 
@@ -694,7 +695,7 @@
             )?
             \]\]
         )
-    """ % dict(uri_schemes='|'.join(config.uri_schemes))
+    """ % dict(uri_schemes='|'.join(URI_SCHEMES))
 
     def inline_link_repl(self, stack, link, link_url=None, link_item=None,
             link_text=None, link_args=None,
@@ -717,14 +718,14 @@
                 # assume local language uses ":" inside of words, set link_item and continue
                 link_item = '{0}:{1}'.format(link_interwiki_site, link_interwiki_item)
         if link_args:
-            link_args = parse_arguments(link_args) # XXX needs different parsing
-            query = url_encode(link_args.keyword, charset=config.charset, encode_keys=True)
+            link_args = parse_arguments(link_args)  # XXX needs different parsing
+            query = url_encode(link_args.keyword, charset=CHARSET, encode_keys=True)
         else:
             query = None
         if link_item is not None:
-            att = 'attachment:' # moin 1.9 needed this for an attached file
+            att = 'attachment:'  # moin 1.9 needed this for an attached file
             if link_item.startswith(att):
-                link_item = '/' + link_item[len(att):] # now we have a subitem
+                link_item = '/' + link_item[len(att):]  # now we have a subitem
             if '#' in link_item:
                 path, fragment = link_item.rsplit('#', 1)
             else:
@@ -829,14 +830,14 @@
                            object_text=None, object_args=None):
         """Handles objects included in the page."""
         if object_args:
-            args = parse_arguments(object_args).keyword # XXX needs different parsing
+            args = parse_arguments(object_args).keyword  # XXX needs different parsing
         else:
             args = {}
         if object_item is not None:
-            query = url_encode(args, charset=config.charset, encode_keys=True)
-            att = 'attachment:' # moin 1.9 needed this for an attached file
+            query = url_encode(args, charset=CHARSET, encode_keys=True)
+            att = 'attachment:'  # moin 1.9 needed this for an attached file
             if object_item.startswith(att):
-                object_item = '/' + object_item[len(att):] # now we have a subitem
+                object_item = '/' + object_item[len(att):]  # now we have a subitem
             target = Iri(scheme='wiki.local', path=object_item, query=query, fragment=None)
             text = object_item
 
@@ -949,7 +950,8 @@
                     cell_markup = cell_markup.split('<')[1]
                     msg1 = _('Error:')
                     msg2 = _('is invalid within')
-                    cell_text = '[ {0} "{1}" {2} <{3}>&nbsp;]<<BR>>{4}'.format(msg1, error, msg2, cell_markup, cell_text)
+                    cell_text = '[ {0} "{1}" {2} <{3}>&nbsp;]<<BR>>{4}'.format(
+                        msg1, error, msg2, cell_markup, cell_text)
                     if no_errors:
                         add_attr_to_style(element.attrib, 'background-color: pink; color: black;')
                     no_errors = False
--- a/MoinMoin/converter/moinwiki_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/moinwiki_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -29,8 +29,8 @@
     a_open = u'[['
     a_separator = u'|'
     a_close = u']]'
-    verbatim_open = u'{' # * 3
-    verbatim_close = u'}'# * 3
+    verbatim_open = u'{'  # * 3
+    verbatim_close = u'}'  # * 3
     monospace = u'`'
     strong = u"'''"
     emphasis = u"''"
@@ -182,7 +182,7 @@
         args = u''
         if len(href) > 1:
             # With normal
-            args = u','.join([u'&'+s for s in findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$|)', href[1])])
+            args = u','.join([u'&' + s for s in findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$|)', href[1])])
         href = href[0].split(u'wiki.local:')[-1]
         args = u','.join(s for s in [args, params] if s)
 
@@ -204,7 +204,8 @@
         for s in findall(r'}+', text):
             if max_subpage_lvl <= len(s):
                 max_subpage_lvl = len(s) + 1
-        ret = u'{0}\n{1}\n{2}\n'.format(Moinwiki.verbatim_open * max_subpage_lvl, text, Moinwiki.verbatim_close * max_subpage_lvl)
+        ret = u'{0}\n{1}\n{2}\n'.format(
+            Moinwiki.verbatim_open * max_subpage_lvl, text, Moinwiki.verbatim_close * max_subpage_lvl)
         return ret
 
     def open_moinpage_code(self, elem):
@@ -268,7 +269,8 @@
         if self.list_item_labels[-1] == u'' or self.list_item_labels[-1] == Moinwiki.definition_list_marker:
             self.list_item_labels[-1] = Moinwiki.definition_list_marker
             self.list_item_label = self.list_item_labels[-1] + u' '
-            ret = u' ' * (len(u''.join(self.list_item_labels[:-1])) + len(self.list_item_labels[:-1]))# self.list_level
+            ret = u' ' * (len(u''.join(self.list_item_labels[:-1])) +
+                          len(self.list_item_labels[:-1]))  # self.list_level
             if self.last_closed:
                 ret = u'\n{0}'.format(ret)
         childrens_output = self.open_children(elem)
@@ -278,7 +280,8 @@
         ret = u''
         if self.last_closed:
             ret = u'\n'
-        ret += u' ' * (len(u''.join(self.list_item_labels[:-1])) + len(self.list_item_labels[:-1])) + self.list_item_label
+        ret += u' ' * (len(u''.join(self.list_item_labels[:-1])) +
+                       len(self.list_item_labels[:-1])) + self.list_item_label
         return ret + self.open_children(elem)
 
     def open_moinpage_note(self, elem):
@@ -300,7 +303,7 @@
         href = href.split(u'?')
         args = u''
         if len(href) > 1:
-            args =u' '.join([s for s in findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$)', href[1]) if s[:3] != u'do='])
+            args = u' '.join([s for s in findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$)', href[1]) if s[:3] != u'do='])
         href = href[0].split(u'wiki.local:')[-1]
         # TODO: add '|' to Moinwiki class and rewrite this using % formatting
         ret = Moinwiki.object_open
@@ -354,7 +357,10 @@
             for s in findall(r'}+', childrens_output):
                 if max_subpage_lvl <= len(s):
                     max_subpage_lvl = len(s) + 1
-            return u'{0}{1}{2}{3}\n'.format(Moinwiki.verbatim_open * max_subpage_lvl, ret, childrens_output, Moinwiki.verbatim_close * max_subpage_lvl)
+            return u'{0}{1}{2}{3}\n'.format(
+                Moinwiki.verbatim_open * max_subpage_lvl,
+                ret, childrens_output,
+                Moinwiki.verbatim_close * max_subpage_lvl)
 
         self.status.append('text')
         childrens_output = self.open_children(elem)
@@ -377,7 +383,9 @@
         if len(type) == 2:
             if type[0] == "x-moin/macro":
                 if len(elem) and iter(elem).next().tag.name == "arguments":
-                    return u"<<{0}({1})>>\n".format(type[1].split(u'=')[1], u','.join([u''.join(c.itertext()) for c in iter(elem).next() if c.tag.name == u"argument"]))
+                    return u"<<{0}({1})>>\n".format(
+                        type[1].split(u'=')[1],
+                        u','.join([u''.join(c.itertext()) for c in iter(elem).next() if c.tag.name == u"argument"]))
                 else:
                     return u"<<{0}()>>\n".format(type[1].split(u'=')[1])
             elif type[0] == "x-moin/format":
@@ -406,7 +414,7 @@
         if hr_class:
             try:
                 height = int(hr_class.split(hr_class_prefix)[1]) - 1
-                if (0 <= height <= 5):
+                if 0 <= height <= 5:
                     hr_ending = (u'-' * height) + hr_ending
             except:
                 raise ElementException('page:separator has invalid class {0}'.format(hr_class))
@@ -502,7 +510,7 @@
         if table_cellstyle:
             attrib.append(u'style="{0}"'.format(table_cellstyle))
         if number_rows_spanned:
-            attrib.append(u'|'+unicode(number_rows_spanned))
+            attrib.append(u'|' + unicode(number_rows_spanned))
 
         attrib = u' '.join(attrib)
 
--- a/MoinMoin/converter/nonexistent_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/nonexistent_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -27,7 +27,7 @@
     def __call__(self, rev, contenttype=None, arguments=None):
         item_name = rev.item.name
         attrib = {
-            xlink.href: Iri(scheme='wiki', authority='', path='/'+item_name, query='do=modify'),
+            xlink.href: Iri(scheme='wiki', authority='', path='/' + item_name, query='do=modify'),
         }
         a = moin_page.a(attrib=attrib, children=[_("%(item_name)s does not exist. Create it?", item_name=item_name)])
         body = moin_page.body(children=(a, ))
--- a/MoinMoin/converter/pdf_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/pdf_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -20,7 +20,8 @@
 
 
 LAPARAMS = LAParams(
-    # value is specified not as an actual length, but as a proportion of the length to the size of each character in question.
+    # value is specified not as an actual length, but as a proportion of the length to the
+    # size of each character in question.
     # two text chunks whose distance is closer than the char_margin is considered
     # continuous and get grouped into one.
     char_margin=0.3,
--- a/MoinMoin/converter/pygments_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/pygments_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -97,7 +97,8 @@
             """
             if lexer is None and contenttype is not None:
                 ct = Type(contenttype)
-                mimetype = '{0}/{1}'.format(ct.type, ct.subtype) # pygments can't process parameters (like e.g. ...;charset=utf-8)
+                # pygments can't process parameters (like e.g. ...;charset=utf-8):
+                mimetype = '{0}/{1}'.format(ct.type, ct.subtype)
                 try:
                     lexer = pygments.lexers.get_lexer_for_mimetype(mimetype)
                 except pygments.util.ClassNotFound:
@@ -121,7 +122,7 @@
 else:
     # we have no Pygments, minimal Converter replacement, so highlight view does not crash
     class Converter(object):
-        def __init__(self, lexer=None, mimetype=None):
+        def __init__(self, lexer=None, contenttype=None):
             pass
 
         def __call__(self, content, arguments=None):
--- a/MoinMoin/converter/rst_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/rst_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -235,10 +235,10 @@
         new_element = moin_page.table_cell()
         if 'morerows' in node.attributes:
             new_element.set(moin_page.number_rows_spanned,
-                            repr(int(node['morerows'])+1))
+                            repr(int(node['morerows']) + 1))
         if 'morecols' in node.attributes:
             new_element.set(moin_page.number_cols_spanned,
-                            repr(int(node['morecols'])+1))
+                            repr(int(node['morecols']) + 1))
         self.open_moin_page_node(new_element)
 
     def depart_entry(self, node):
@@ -400,7 +400,9 @@
             for name, value in named_args:
                 args.append(moin_page.argument(attrib={moin_page.name: name}, children=[value]))
             arguments = moin_page.arguments(children=args)
-            self.open_moin_page_node(moin_page.part(children=[arguments], attrib={moin_page.content_type: "x-moin/format;name={0}".format(parser.split(' ')[0])}))
+            self.open_moin_page_node(moin_page.part(children=[arguments],
+                                                    attrib={moin_page.content_type:
+                                                                "x-moin/format;name={0}".format(parser.split(' ')[0])}))
         else:
             self.open_moin_page_node(moin_page.blockcode())
 
@@ -430,7 +432,7 @@
 
     def visit_reference(self, node):
         refuri = node.get('refuri', u'')
-        if refuri.startswith(u'<<') and refuri.endswith(u'>>'): # moin macro
+        if refuri.startswith(u'<<') and refuri.endswith(u'>>'):  # moin macro
             macro_name = refuri[2:-2].split(u'(')[0]
             if macro_name == u"TableOfContents":
                 arguments = refuri[2:-2].split(u'(')[1][:-1].split(u',')
@@ -624,8 +626,8 @@
     visitor_attributes = []
 
     def translate(self):
-        self.visitor = visitor = NodeVisitor(self.document)
-        self.document.walkabout(visitor)
+        self.visitor = visitor = NodeVisitor()
+        walkabout(self.document, visitor)
         self.output = visitor.tree()
 
 
@@ -761,12 +763,21 @@
             try:
                 docutils_tree = core.publish_doctree(source=input)
             except utils.SystemMessage as inst:
-                string_numb = re.match(re.compile(r'<string>\:([0-9]*)\:\s*\(.*?\)\s*(.*)', re.X | re.U | re.M | re.S), str(inst))
+                string_numb = re.match(re.compile(r'<string>\:([0-9]*)\:\s*\(.*?\)\s*(.*)',
+                                                  re.X | re.U | re.M | re.S), str(inst))
                 if string_numb:
                     str_num = string_numb.group(1)
                     input = input.split('\n')
                     if str_num:
-                        input = ['.. error::\n ::\n\n  Parse error on line number {0}:\n\n  {1}\n\n  Go back and try fix that.\n\n'.format(str_num, string_numb.group(2).replace('\n', '\n  '))]
+                        input = [('.. error::\n'
+                                  ' ::\n'
+                                  '\n'
+                                  '  Parse error on line number {0}:\n'
+                                  '\n'
+                                  '  {1}\n'
+                                  '\n'
+                                  '  Go back and try fix that.\n'
+                                  '\n').format(str_num, string_numb.group(2).replace('\n', '\n  '))]
                         continue
                 else:
                     input = ['.. error::\n ::\n\n  {0}\n\n'.format(str(inst).replace('\n', '\n  '))]
--- a/MoinMoin/converter/rst_out.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/rst_out.py	Sat Feb 16 23:21:46 2013 +0100
@@ -65,7 +65,7 @@
         self.j = 0
         self.table.append(row)
         if self.i > 0:
-            if len(self.table[-2]) > (self.j):
+            if len(self.table[-2]) > self.j:
                 self.add_cell(self.table[-2][self.j][0],
                                 self.table[-2][self.j][1] - 1, Cell(''))
         return row
@@ -92,8 +92,8 @@
         if cs < 1 or rs < 1:
             return
         self.table[-1].append((cs, rs, cell))
-        for i in range(cs-1):
-            self.table[-1].append((cs-i-1, rs, Cell('')))
+        for i in range(cs - 1):
+            self.table[-1].append((cs - i - 1, rs, Cell('')))
         self.j += cs
         if self.i > 0:
             if len(self.table[-2]) > self.j:
@@ -166,7 +166,7 @@
             line = [u'+']
             row = self.table[0]
             for col in range(len(cols)):
-                line.append(u'-'*cols[col])
+                line.append(u'-' * cols[col])
                 if self.table[0][col][0] > 1:
                     line.append(u'-')
                 else:
@@ -192,11 +192,11 @@
                 line = [u'+']
                 for col in range(len(cols)):
                     if self.table[row][col][1] > 1:
-                        line.append(u' '*cols[col])
+                        line.append(u' ' * cols[col])
                     elif row == self.header_count - 1:
-                        line.append(u'='*cols[col])
+                        line.append(u'=' * cols[col])
                     else:
-                        line.append(u'-'*cols[col])
+                        line.append(u'-' * cols[col])
                     if self.table[row][col][0] > 1:
                         if row + 1 < len(rows)\
                                 and self.table[row + 1][col][0] > 1\
@@ -334,7 +334,8 @@
                         childrens_output.append(u'\n\n')
                 elif self.status[-1] == "list":
                     child =\
-                        re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' '*(len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), child)
+                        re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' ' *
+                            (len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), child)
                     if self.last_closed == "p":
                         childrens_output.append(u'\n'
                                 + u' '
@@ -346,7 +347,8 @@
                         childrens_output.append(u'\n')
                 elif self.status[-2] == "list":
                     child =\
-                        re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' '*(len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), child)
+                        re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' ' *
+                            (len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), child)
                 childrens_output.append(child)
                 self.last_closed = 'text'
         self.delete_newlines = delete_newlines
@@ -408,7 +410,8 @@
                 if i:
                     self.output[-1] = self.output[-1][:i]
             """
-        return u"::\n\n  {0}{1}\n\n".format(u' ' * (len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), text)
+        return u"::\n\n  {0}{1}\n\n".format(u' ' *
+                    (len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), text)
 
     def open_moinpage_code(self, elem):
         ret = u"{0}{1}{2}".format(ReST.monospace, u''.join(elem.itertext()), ReST.monospace)
@@ -510,8 +513,7 @@
         href = href.split(u'?')
         args = u''
         if len(href) > 1:
-            args =[s for s in re.findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$)',
-                                            href[1]) if s[:3] != u'do=']
+            args = [s for s in re.findall(r'(?:^|;|,|&|)(\w+=\w+)(?:,|&|$)', href[1]) if s[:3] != u'do=']
         href = href[0]
         alt = elem.get(moin_page.alt, u'')
         if not alt:
@@ -520,7 +522,8 @@
             ret = u'|{0}|'.format(alt)
         args_text = u''
         if args:
-            args_text = u"\n  {0}".format(u'\n  '.join(u':{0}: {1}'.format(arg.split(u'=')[0], arg.split(u'=')[1]) for arg in args))
+            args_text = u"\n  {0}".format(u'\n  '.join(u':{0}: {1}'.format(
+                arg.split(u'=')[0], arg.split(u'=')[1]) for arg in args))
         self.objects.append(u".. {0} image:: {1}{2}".format(ret, href, args_text))
         return ret
 
@@ -586,7 +589,8 @@
         if len(type) == 2:
             if type[0] == u"x-moin/macro":
                 if len(elem) and iter(elem).next().tag.name == "arguments":
-                    alt = u"<<{0}({1})>>".format(type[1].split(u'=')[1], u','.join([u''.join(c.itertext()) for c in iter(elem).next() if c.tag.name == "argument"]))
+                    alt = u"<<{0}({1})>>".format(type[1].split(u'=')[1], u','.join(
+                            [u''.join(c.itertext()) for c in iter(elem).next() if c.tag.name == "argument"]))
                 else:
                     alt = u"<<{0}()>>".format(type[1].split(u'=')[1])
 
@@ -656,7 +660,8 @@
         table = repr(self.tablec)
         if self.status[-1] == "list":
             table =\
-                re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' '*(len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), u"\n" + table)
+                re.sub(r"\n(.)", lambda m: u"\n{0}{1}".format(u' ' *
+                        (len(u''.join(self.list_item_labels)) + len(self.list_item_labels)), m.group(1)), u"\n" + table)
             return table + ReST.p
         return table + ReST.linebreak
 
--- a/MoinMoin/converter/smiley.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/smiley.py	Sat Feb 16 23:21:46 2013 +0100
@@ -64,7 +64,7 @@
     ($|(?=\s))  # we require either ending of line or some space after a smiley
 """ % {'smiley': u'|'.join([re.escape(s) for s in smileys])}
 
-    smiley_re = re.compile(smiley_rule, re.UNICODE|re.VERBOSE)
+    smiley_re = re.compile(smiley_rule, re.UNICODE | re.VERBOSE)
 
     # We do not process any smiley conversion within these elements.
     tags_to_ignore = set(['code', 'blockcode', ])
--- a/MoinMoin/converter/xml_in.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/converter/xml_in.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,7 +14,8 @@
 
 from ._util import decode_data
 
-RX_STRIPXML = re.compile(u"<[^>]*?>", re.U|re.DOTALL|re.MULTILINE)
+RX_STRIPXML = re.compile(u"<[^>]*?>", re.U | re.DOTALL | re.MULTILINE)
+
 
 def strip_xml(text):
     text = RX_STRIPXML.sub(u" ", text)
--- a/MoinMoin/datastruct/backends/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -209,7 +209,8 @@
         else:
             groups = flaskg.groups
             for group_name in self.member_groups:
-                if group_name not in processed_groups and group_name in groups and groups[group_name].__contains__(member, processed_groups):
+                if (group_name not in processed_groups and group_name in groups and
+                        groups[group_name].__contains__(member, processed_groups)):
                     return True
 
         return False
@@ -250,7 +251,8 @@
                     yield group_name
 
     def __repr__(self):
-        return "<{0!r} name={1!r} members={2!r} member_groups={3!r}>".format(self.__class__, self.name, self.members, self.member_groups)
+        return "<{0!r} name={1!r} members={2!r} member_groups={3!r}>".format(
+            self.__class__, self.name, self.members, self.member_groups)
 
 
 class BaseDict(object, DictMixin):
--- a/MoinMoin/datastruct/backends/_tests/test_composite_groups.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/_tests/test_composite_groups.py	Sat Feb 16 23:21:46 2013 +0100
@@ -13,7 +13,6 @@
 from MoinMoin.datastruct.backends._tests import GroupsBackendTest
 from MoinMoin.datastruct import ConfigGroups, CompositeGroups, GroupDoesNotExistError
 from MoinMoin._tests import wikiconfig
-from MoinMoin import security
 
 
 class TestCompositeGroupsBackend(GroupsBackendTest):
--- a/MoinMoin/datastruct/backends/_tests/test_lazy_config_groups.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/_tests/test_lazy_config_groups.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,7 +8,7 @@
 
 from MoinMoin.datastruct.backends._tests import GroupsBackendTest
 from MoinMoin.datastruct.backends.config_lazy_groups import ConfigLazyGroups
-from MoinMoin.datastruct import ConfigGroups, CompositeGroups, GroupDoesNotExistError
+from MoinMoin.datastruct import ConfigGroups, CompositeGroups
 from MoinMoin._tests import wikiconfig
 
 
--- a/MoinMoin/datastruct/backends/_tests/test_wiki_dicts.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/_tests/test_wiki_dicts.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,7 @@
 
 from MoinMoin.datastruct.backends._tests import DictsBackendTest
 from MoinMoin.datastruct.backends import wiki_dicts
-from MoinMoin.config import SOMEDICT
+from MoinMoin.constants.keys import SOMEDICT
 from MoinMoin._tests import become_trusted, update_item
 DATA = "This is a dict item."
 
--- a/MoinMoin/datastruct/backends/_tests/test_wiki_groups.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/_tests/test_wiki_groups.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,7 +17,7 @@
 
 from MoinMoin.datastruct.backends._tests import GroupsBackendTest
 from MoinMoin.datastruct import GroupDoesNotExistError
-from MoinMoin.config import NAME, USERGROUP
+from MoinMoin.constants.keys import NAME, USERGROUP
 from MoinMoin.security import AccessControlList
 from MoinMoin.user import User
 from MoinMoin._tests import become_trusted, create_random_string_list, update_item
--- a/MoinMoin/datastruct/backends/wiki_dicts.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/wiki_dicts.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,7 @@
 
 from flask import g as flaskg
 
-from MoinMoin.config import CURRENT, SOMEDICT
+from MoinMoin.constants.keys import CURRENT, SOMEDICT
 from MoinMoin.datastruct.backends import BaseDict, BaseDictsBackend, DictDoesNotExistError
 
 
--- a/MoinMoin/datastruct/backends/wiki_groups.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/datastruct/backends/wiki_groups.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,7 +16,7 @@
 
 from flask import g as flaskg
 
-from MoinMoin.config import CURRENT, USERGROUP
+from MoinMoin.constants.keys import CURRENT, USERGROUP
 from MoinMoin.datastruct.backends import GreedyGroup, BaseGroupsBackend, GroupDoesNotExistError
 
 
--- a/MoinMoin/error.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/error.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,8 @@
 
 import sys
 
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import CHARSET
+
 
 class Error(Exception):
     """ Base class for moin moin errors
@@ -20,11 +21,11 @@
 
     Standard errors work safely only with strings using ascii or
     unicode. This class can be used safely with both strings using
-    config.charset and unicode.
+    CHARSET and unicode.
 
     You can init this class with either unicode or string using
-    config.charset encoding. On output, the class will convert the string
-    to unicode or the unicode to string, using config.charset.
+    CHARSET encoding. On output, the class will convert the string
+    to unicode or the unicode to string, using CHARSET.
 
     When you want to render an error, use unicode() or str() as needed.
     """
@@ -33,21 +34,21 @@
         """ Initialize an error, decode if needed
 
         :param message: unicode, str or object that support __unicode__
-            and __str__. __str__ should use config.charset.
+            and __str__. __str__ should use CHARSET.
         """
         self.message = message
 
     def __unicode__(self):
         """ Return unicode error message """
         if isinstance(self.message, str):
-            return unicode(self.message, config.charset)
+            return unicode(self.message, CHARSET)
         else:
             return unicode(self.message)
 
     def __str__(self):
         """ Return encoded message """
         if isinstance(self.message, unicode):
-            return self.message.encode(config.charset)
+            return self.message.encode(CHARSET)
         else:
             return str(self.message)
 
@@ -94,14 +95,17 @@
                 break
         return all
 
+
 class FatalError(CompositeError):
     """ Base class for fatal error we can't handle
 
     Do not use this class but its more specific sub classes.
     """
 
+
 class ConfigurationError(FatalError):
     """ Raise when fatal misconfiguration is found """
 
+
 class InternalError(FatalError):
     """ Raise when internal fatal error is found """
--- a/MoinMoin/forms.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/forms.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,10 +9,12 @@
 """
 
 
-import re, datetime
+import re
+import datetime
 import json
 
-from flatland import Element, Form, String, Integer, Boolean, Enum, Dict, JoinedString, List, Array, DateTime as _DateTime
+from flatland import (Element, Form, String, Integer, Boolean, Enum, Dict, JoinedString, List, Array,
+                      DateTime as _DateTime)
 from flatland.util import class_cloner, Unspecified
 from flatland.validation import Validator, Present, IsEmail, ValueBetween, URLValidator, Converted, ValueAtLeast
 from flatland.exc import AdaptationError
@@ -22,7 +24,6 @@
 from MoinMoin.constants.forms import *
 from MoinMoin.constants.keys import ITEMID, NAME
 from MoinMoin.i18n import _, L_, N_
-from MoinMoin.security.textcha import TextCha, TextChaizedForm, TextChaValid
 from MoinMoin.util.forms import FileStorage
 
 
@@ -47,7 +48,7 @@
     def validate(self, element, state):
         try:
             json.loads(element.value)
-        except: # catch ANY exception that happens due to unserializing
+        except:  # catch ANY exception that happens due to unserializing
             return self.note_error(element, state, 'invalid_json_msg')
         return True
 
@@ -59,7 +60,8 @@
 
 YourOpenID = OpenID.with_properties(placeholder=L_("Your OpenID address"))
 
-Email = String.using(label=L_('E-Mail')).with_properties(widget=WIDGET_EMAIL, placeholder=L_("E-Mail address")).validated_by(IsEmail())
+Email = String.using(label=L_('E-Mail')).with_properties(widget=WIDGET_EMAIL,
+                                                         placeholder=L_("E-Mail address")).validated_by(IsEmail())
 
 YourEmail = Email.with_properties(placeholder=L_("Your E-Mail address"))
 
@@ -73,6 +75,15 @@
 
 Select = Enum.with_properties(widget=WIDGET_SELECT)
 
+# SelectSubmit is like Select in that it is rendered as a group of controls
+# with different (predefined) `value`s for the same `name`. But the controls are
+# submit buttons instead of radio buttons.
+#
+# This is used to present the user several "OK" buttons with slightly different
+# semantics, like "Update" and "Update and Close" on a ticket page, or
+# "Save as Draft" and "Publish" when editing a blog entry.
+SelectSubmit = Enum.with_properties(widget=WIDGET_SELECT_SUBMIT)
+
 
 # Need a better name to capture the behavior
 class MyJoinedString(JoinedString):
@@ -88,9 +99,11 @@
     def u(self):
         return self.separator.join(child.u for child in self)
 
-Tags = MyJoinedString.of(String).with_properties(widget=WIDGET_TEXT).using(label=L_('Tags'), optional=True, separator=', ', separator_regex=re.compile(r'\s*,\s*'))
+Tags = MyJoinedString.of(String).with_properties(widget=WIDGET_TEXT).using(label=L_('Tags'), optional=True,
+                                                            separator=', ', separator_regex=re.compile(r'\s*,\s*'))
 
-Names = MyJoinedString.of(String).with_properties(widget=WIDGET_TEXT).using(label=L_('Names'), optional=True, separator=', ', separator_regex=re.compile(r'\s*,\s*'))
+Names = MyJoinedString.of(String).with_properties(widget=WIDGET_TEXT).using(label=L_('Names'), optional=True,
+                                                            separator=', ', separator_regex=re.compile(r'\s*,\s*'))
 
 Search = Text.using(default=u'', optional=True).with_properties(widget=WIDGET_SEARCH, placeholder=L_("Search Query"))
 
@@ -138,13 +151,12 @@
             dt = utctimestamp(dt)
         return dt
 
-DateTime = (DateTimeUNIX.with_properties(widget=WIDGET_DATETIME, placeholder=_("YYYY-MM-DD HH:MM:SS (example: 2013-12-31 23:59:59)"))
+DateTime = (DateTimeUNIX.with_properties(widget=WIDGET_DATETIME,
+                                         placeholder=_("YYYY-MM-DD HH:MM:SS (example: 2013-12-31 23:59:59)"))
             .validated_by(Converted(incorrect=L_("Please use the following format: YYYY-MM-DD HH:MM:SS"))))
 
 File = FileStorage.with_properties(widget=WIDGET_FILE)
 
-Submit = String.using(default=L_('OK'), optional=True).with_properties(widget=WIDGET_SUBMIT, class_=CLASS_BUTTON)
-
 Hidden = String.using(optional=True).with_properties(widget=WIDGET_HIDDEN)
 
 # optional=True is needed to get rid of the "required field" indicator on the UI (usually an asterisk)
@@ -166,6 +178,7 @@
             return self.note_error(element, state, 'invalid_reference_msg')
         return True
 
+
 class Reference(Select.with_properties(empty_label=L_(u'(None)')).validated_by(ValidReference())):
     """
     A metadata property that points to another item selected out of the
--- a/MoinMoin/i18n/_tests/test_i18n.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/i18n/_tests/test_i18n.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,6 @@
 """
 
 from MoinMoin.i18n import get_locale, get_timezone
-import pytest
 
 from MoinMoin.i18n import _, L_, N_
 
--- a/MoinMoin/items/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -38,20 +38,19 @@
 from MoinMoin.security.textcha import TextCha, TextChaizedForm
 from MoinMoin.signalling import item_modified
 from MoinMoin.storage.middleware.protecting import AccessDenied
-from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
 from MoinMoin.i18n import L_
 from MoinMoin.themes import render_template
 from MoinMoin.util.mime import Type
 from MoinMoin.util.interwiki import url_for_item
 from MoinMoin.util.registry import RegistryBase
 from MoinMoin.util.clock import timed
-from MoinMoin.forms import RequiredText, OptionalText, JSON, Tags, Submit
+from MoinMoin.forms import RequiredText, OptionalText, JSON, Tags
 from MoinMoin.constants.keys import (
     NAME, NAME_OLD, NAME_EXACT, WIKINAME, MTIME, SYSITEM_VERSION, ITEMTYPE,
     CONTENTTYPE, SIZE, ACTION, ADDRESS, HOSTNAME, USERID, COMMENT,
     HASH_ALGORITHM, ITEMID, REVID, DATAID, CURRENT, PARENTID
     )
-from MoinMoin.constants.contenttypes import charset, CONTENTTYPE_NONEXISTENT
+from MoinMoin.constants.contenttypes import CHARSET, CONTENTTYPE_NONEXISTENT
 from MoinMoin.constants.itemtypes import (
     ITEMTYPE_NONEXISTENT, ITEMTYPE_USERPROFILE, ITEMTYPE_DEFAULT,
     )
@@ -92,8 +91,10 @@
 
 item_registry = RegistryItem()
 
+
 def register(cls):
-    item_registry.register(RegistryItem.Entry(cls._factory, cls.itemtype, cls.display_name, cls.description, cls.order), cls.shown)
+    item_registry.register(RegistryItem.Entry(cls._factory, cls.itemtype, cls.display_name, cls.description, cls.order),
+                           cls.shown)
     return cls
 
 
@@ -115,8 +116,10 @@
     """ if we have no stored Item, we use this dummy """
     def __init__(self, name):
         self.name = name
+
     def list_revisions(self):
-        return [] # same as an empty Item
+        return []  # same as an empty Item
+
     def destroy_all_revisions(self):
         return True
 
@@ -141,12 +144,12 @@
     :itemtype and :contenttype are used when creating a DummyRev, where
     metadata is not available from the storage.
     """
-    if 1: # try:
+    if 1:  # try:
         if item is None:
             item = flaskg.storage[name]
         else:
             name = item.name
-    if not item: # except NoSuchItemError:
+    if not item:  # except NoSuchItemError:
         logging.debug("No such item: {0!r}".format(name))
         item = DummyItem(name)
         rev = DummyRev(item, itemtype, contenttype)
@@ -155,11 +158,11 @@
         logging.debug("Got item: {0!r}".format(name))
         try:
             rev = item.get_revision(rev_id)
-        except KeyError: # NoSuchRevisionError:
+        except KeyError:  # NoSuchRevisionError:
             try:
-                rev = item.get_revision(CURRENT) # fall back to current revision
+                rev = item.get_revision(CURRENT)  # fall back to current revision
                 # XXX add some message about invalid revision
-            except KeyError: # NoSuchRevisionError:
+            except KeyError:  # NoSuchRevisionError:
                 logging.debug("Item {0!r} has no revisions.".format(name))
                 rev = DummyRev(item, itemtype, contenttype)
                 logging.debug("Item {0!r}, created dummy revision with contenttype {1!r}".format(name, contenttype))
@@ -169,7 +172,7 @@
 
 class BaseChangeForm(TextChaizedForm):
     comment = OptionalText.using(label=L_('Comment')).with_properties(placeholder=L_("Comment about your change"))
-    submit = Submit
+    submit_label = L_('OK')
 
 
 class BaseMetaForm(Form):
@@ -183,8 +186,18 @@
 
 
 class BaseModifyForm(BaseChangeForm):
+    """
+    This class is abstract and only defines two factory methods; see
+    Item._ModifyForm for the implementation.
+    """
     @classmethod
     def from_item(cls, item):
+        """
+        Construct an instance from :item.
+
+        This class method is not supposed to be overriden; subclasses should
+        overrride the _load method instead.
+        """
         form = cls.from_defaults()
         TextCha(form).amend_form()
         form._load(item)
@@ -192,6 +205,13 @@
 
     @classmethod
     def from_request(cls, request):
+        """
+        Construct an instance from :request.
+
+        Since the mapping from HTTP form (unlike from an Item instance) to
+        Flatland Form is straightforward, there should be rarely any need to
+        override this class method.
+        """
         form = cls.from_flat(request.form.items() + request.files.items())
         TextCha(form).amend_form()
         return form
@@ -199,6 +219,7 @@
 
 UNKNOWN_ITEM_GROUP = "unknown items"
 
+
 def _build_contenttype_query(groups):
     """
     Build a Whoosh query from a list of contenttype groups.
@@ -215,6 +236,7 @@
 
 MixedIndexEntry = namedtuple('MixedIndexEntry', 'relname meta hassubitems')
 
+
 class Item(object):
     """ Highlevel (not storage) Item, wraps around a storage Revision"""
     # placeholder values for registry entry properties
@@ -248,7 +270,7 @@
         property.
         """
         rev = get_storage_revision(name, itemtype, contenttype, rev_id, item)
-        contenttype = rev.meta.get(CONTENTTYPE) or contenttype # use contenttype in case our metadata does not provide CONTENTTYPE
+        contenttype = rev.meta.get(CONTENTTYPE) or contenttype
         logging.debug("Item {0!r}, got contenttype {1!r} from revision meta".format(name, contenttype))
         #logging.debug("Item %r, rev meta dict: %r" % (name, dict(rev.meta)))
 
@@ -256,7 +278,7 @@
         # content_registry.get yet, have to patch it later.
         content = Content.create(contenttype)
 
-        itemtype = rev.meta.get(ITEMTYPE) or itemtype or u'default'
+        itemtype = rev.meta.get(ITEMTYPE) or itemtype or ITEMTYPE_DEFAULT
         logging.debug("Item {0!r}, got itemtype {1!r} from revision meta".format(name, itemtype))
 
         item = item_registry.get(itemtype, name, rev=rev, content=content)
@@ -285,7 +307,7 @@
 
     def meta_filter(self, meta):
         """ kill metadata entries that we set automatically when saving """
-        kill_keys = [# shall not get copied from old rev to new rev
+        kill_keys = [  # shall not get copied from old rev to new rev
             SYSITEM_VERSION,
             NAME_OLD,
             # are automatically implanted when saving
@@ -338,7 +360,8 @@
                     else:  # rename
                         child_newname = new_prefix + child_oldname[old_prefixlen:]
                     item = Item.create(child_oldname)
-                    item._save(item.meta, item.content.data, name=child_newname, action=action, comment=comment, delete=delete)
+                    item._save(item.meta, item.content.data,
+                               name=child_newname, action=action, comment=comment, delete=delete)
 
     def rename(self, name, comment=u''):
         """
@@ -372,12 +395,23 @@
         return self._save(meta, data, contenttype_guessed=contenttype_guessed, comment=comment)
 
     class _ModifyForm(BaseModifyForm):
-        """Base class for ModifyForm of Item subclasses."""
+        """
+        ModifyForm (the form used on +modify view), sans the content part.
+        Combined dynamically with the ModifyForm of the Content subclass in
+        Contentful.ModifyForm.
+
+        Subclasses of Contentful should generally override this instead of
+        ModifyForm.
+        """
         meta_form = BaseMetaForm
         extra_meta_text = JSON.using(label=L_("Extra MetaData (JSON)")).with_properties(rows=ROWS_META, cols=COLS)
         meta_template = 'modify_meta.html'
 
         def _load(self, item):
+            """
+            Load metadata and data from :item into :self. Used by
+            BaseModifyForm.from_item.
+            """
             meta = item.prepare_meta_for_modify(item.meta)
             # Default value of `policy` argument of Flatland.Dict.set's is
             # 'strict', which causes KeyError to be thrown when meta contains
@@ -390,6 +424,15 @@
             self['content_form']._load(item.content)
 
         def _dump(self, item):
+            """
+            Dump useful data out of :self. :item contains the old item and
+            should not be the primary data source; but it can be useful in case
+            the data in :self is not sufficient.
+
+            :returns: a tuple (meta, data, contenttype_guessed, comment),
+                      suitable as arguments of the same names to pass to
+                      item.modify
+            """
             meta = self['meta_form'].value.copy()
             meta.update(item.meta_text_to_dict(self['extra_meta_text'].value))
             data, contenttype_guessed = self['content_form']._dump(item.content)
@@ -413,12 +456,12 @@
             currentrev = storage_item.get_revision(CURRENT)
             rev_id = currentrev.revid
             contenttype_current = currentrev.meta.get(CONTENTTYPE)
-        except KeyError: # XXX was: NoSuchRevisionError:
+        except KeyError:  # XXX was: NoSuchRevisionError:
             currentrev = None
             rev_id = None
             contenttype_current = None
 
-        meta = dict(meta) # we may get a read-only dict-like, copy it
+        meta = dict(meta)  # we may get a read-only dict-like, copy it
 
         # we store the previous (if different) and current item name into revision metadata
         # this is useful for rename history and backends that use item uids internally
@@ -428,7 +471,7 @@
         if oldname:
             if not isinstance(oldname, list):
                 oldname = [oldname]
-            if delete or name not in oldname: # this is a delete or rename
+            if delete or name not in oldname:  # this is a delete or rename
                 meta[NAME_OLD] = oldname[:]
                 try:
                     oldname.remove(self.name)
@@ -456,7 +499,7 @@
                 data = ''
 
         if isinstance(data, unicode):
-            data = data.encode(charset) # XXX wrong! if contenttype gives a coding, we MUST use THAT.
+            data = data.encode(CHARSET)  # XXX wrong! if contenttype gives a coding, we MUST use THAT.
 
         if isinstance(data, str):
             data = StringIO(data)
@@ -634,8 +677,8 @@
 
     def do_show(self, revid):
         show_revision = revid != CURRENT
-        show_navigation = False # TODO
-        first_rev = last_rev = None # TODO
+        show_navigation = False  # TODO
+        first_rev = last_rev = None  # TODO
         return render_template(self.show_template,
                                item=self, item_name=self.name,
                                rev=self.rev,
--- a/MoinMoin/items/_tests/test_Blog.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/_tests/test_Blog.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,8 @@
 
 from MoinMoin._tests import become_trusted, update_item
 from MoinMoin.items import Item
-from MoinMoin.config import CONTENTTYPE, ITEMTYPE, PTIME, ACL, TAGS
+from MoinMoin.constants.keys import CONTENTTYPE, ITEMTYPE, PTIME, ACL, TAGS
+from MoinMoin.constants.misc import ANON
 from MoinMoin.items.blog import ITEMTYPE_BLOG, ITEMTYPE_BLOG_ENTRY
 from MoinMoin.items.blog import Blog, BlogEntry
 
@@ -122,10 +123,10 @@
             item._save(self.entry_meta, entry['data'], comment=self.comment)
         # publish the first three entries with specific ACLs
         # we are an "anonymous" user
-        self._publish_entry(self.entries[0], ptime=1000, acl=u"anonymous:read")
-        self._publish_entry(self.entries[1], ptime=3000, acl=u"anonymous:read")
+        self._publish_entry(self.entries[0], ptime=1000, acl=u"%s:read" % ANON)
+        self._publish_entry(self.entries[1], ptime=3000, acl=u"%s:read" % ANON)
         # specify no rights on the 3rd entry
-        self._publish_entry(self.entries[2], ptime=2000, acl=u"anonymous:")
+        self._publish_entry(self.entries[2], ptime=2000, acl=u"%s:" % ANON)
         # the blog is not empty and the 3rd entry is not displayed
         exclude_data_tokens = [self.NO_ENTRIES_MSG, self.entries[2]['data'], ]
         ordered_data = [self.data,
--- a/MoinMoin/items/_tests/test_Content.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/_tests/test_Content.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,7 +9,6 @@
 
 import pytest
 
-from flask import g as flaskg
 from flask import Markup
 
 from werkzeug import escape
@@ -19,7 +18,8 @@
 from MoinMoin._tests import become_trusted, update_item
 from MoinMoin.items import Item
 from MoinMoin.items.content import Content, ApplicationXTar, Binary, Text, Image, TransformableBitmapImage, MarkupItem
-from MoinMoin.config import CONTENTTYPE, ADDRESS, COMMENT, HOSTNAME, USERID, ACTION
+from MoinMoin.constants.keys import CONTENTTYPE, TAGS
+from MoinMoin.constants.itemtypes import ITEMTYPE_DEFAULT
 
 
 class TestContent(object):
@@ -40,21 +40,21 @@
         item_name1 = u'Template_Item1'
         item1 = Item.create(item_name1)
         contenttype1 = u'text/plain'
-        meta = {CONTENTTYPE: contenttype1, 'tags': ['template']}
+        meta = {CONTENTTYPE: contenttype1, TAGS: ['template']}
         item1._save(meta)
         item1 = Item.create(item_name1)
 
         item_name2 = u'Template_Item2'
         item2 = Item.create(item_name2)
         contenttype1 = u'text/plain'
-        meta = {CONTENTTYPE: contenttype1, 'tags': ['template']}
+        meta = {CONTENTTYPE: contenttype1, TAGS: ['template']}
         item2._save(meta)
         item2 = Item.create(item_name2)
 
         item_name3 = u'Template_Item3'
         item3 = Item.create(item_name3)
         contenttype2 = u'image/png'
-        meta = {CONTENTTYPE: contenttype2, 'tags': ['template']}
+        meta = {CONTENTTYPE: contenttype2, TAGS: ['template']}
         item3._save(meta)
         item3 = Item.create(item_name3)
         # two items of same content type
@@ -74,14 +74,14 @@
         creates a container and tests the content saved to the container
         """
         item_name = u'ContainerItem1'
-        item = Item.create(item_name, itemtype=u'default', contenttype=u'application/x-tar')
+        item = Item.create(item_name, itemtype=ITEMTYPE_DEFAULT, contenttype=u'application/x-tar')
         filecontent = 'abcdefghij'
         content_length = len(filecontent)
         members = set(['example1.txt', 'example2.txt'])
         item.content.put_member('example1.txt', filecontent, content_length, expected_members=members)
         item.content.put_member('example2.txt', filecontent, content_length, expected_members=members)
 
-        item = Item.create(item_name, itemtype=u'default', contenttype=u'application/x-tar')
+        item = Item.create(item_name, itemtype=ITEMTYPE_DEFAULT, contenttype=u'application/x-tar')
         tf_names = set(item.content.list_members())
         assert tf_names == members
         assert item.content.get_member('example1.txt').read() == filecontent
@@ -91,7 +91,7 @@
         creates two revisions of a container item
         """
         item_name = u'ContainerItem2'
-        item = Item.create(item_name, itemtype=u'default', contenttype=u'application/x-tar')
+        item = Item.create(item_name, itemtype=ITEMTYPE_DEFAULT, contenttype=u'application/x-tar')
         filecontent = 'abcdefghij'
         content_length = len(filecontent)
         members = set(['example1.txt'])
@@ -108,7 +108,7 @@
 
     def test_put_member(self):
         item_name = u'Zip_file'
-        item = Item.create(item_name, itemtype=u'default', contenttype='application/zip')
+        item = Item.create(item_name, itemtype=ITEMTYPE_DEFAULT, contenttype='application/zip')
         filecontent = 'test_contents'
         content_length = len(filecontent)
         members = set(['example1.txt', 'example2.txt'])
@@ -175,7 +175,7 @@
 
     def test_data_conversion(self):
         item_name = u'Text_Item'
-        item = Item.create(item_name, u'default', u'text/plain')
+        item = Item.create(item_name, ITEMTYPE_DEFAULT, u'text/plain')
         test_text = u'This \n is \n a \n Test'
         # test for data_internal_to_form
         result = Text.data_internal_to_form(item.content, test_text)
--- a/MoinMoin/items/_tests/test_Item.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/_tests/test_Item.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,17 +8,13 @@
 
 import pytest
 
-from flask import g as flaskg
-from flask import Markup
-
 from werkzeug import escape
 
-from MoinMoin.util import diff_html
-
 from MoinMoin._tests import become_trusted, update_item
 from MoinMoin.items import Item, NonExistent, IndexEntry, MixedIndexEntry
-from MoinMoin.items.content import Binary, Text, Image, TransformableBitmapImage, MarkupItem
-from MoinMoin.constants.keys import ITEMTYPE, CONTENTTYPE, NAME, ADDRESS, COMMENT, HOSTNAME, USERID, ACTION
+from MoinMoin.constants.keys import ITEMTYPE, CONTENTTYPE, NAME, NAME_OLD, COMMENT, ACTION, ADDRESS
+from MoinMoin.constants.contenttypes import CONTENTTYPE_NONEXISTENT
+from MoinMoin.constants.itemtypes import ITEMTYPE_NONEXISTENT
 
 
 def build_index(basename, relnames):
@@ -45,8 +41,8 @@
         assert isinstance(item, NonExistent)
         meta, data = item.meta, item.content.data
         assert meta == {
-                ITEMTYPE: u'nonexistent',
-                CONTENTTYPE: u'application/x-nonexistent',
+                ITEMTYPE: ITEMTYPE_NONEXISTENT,
+                CONTENTTYPE: CONTENTTYPE_NONEXISTENT,
                 NAME: u'DoesNotExist',
                 }
         assert data == ''
@@ -131,7 +127,7 @@
     def test_meta_filter(self):
         name = u'Test_item'
         contenttype = u'text/plain;charset=utf-8'
-        meta = {'test_key': 'test_val', CONTENTTYPE: contenttype, NAME: [u'test_name'], 'address': u'1.2.3.4'}
+        meta = {'test_key': 'test_val', CONTENTTYPE: contenttype, NAME: [u'test_name'], ADDRESS: u'1.2.3.4'}
         item = Item.create(name)
         result = Item.meta_filter(item, meta)
         # keys like NAME, ITEMID, REVID, DATAID are filtered
@@ -188,19 +184,19 @@
         # item and its contents before renaming
         item = Item.create(name)
         assert item.name == u'Test_Item'
-        assert item.meta['comment'] == u'saved it'
+        assert item.meta[COMMENT] == u'saved it'
         new_name = u'Test_new_Item'
         item.rename(new_name, comment=u'renamed')
         # item at original name and its contents after renaming
         item = Item.create(name)
         assert item.name == u'Test_Item'
         # this should be a fresh, new item, NOT the stuff we renamed:
-        assert item.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         # item at new name and its contents after renaming
         item = Item.create(new_name)
         assert item.name == u'Test_new_Item'
-        assert item.meta['name_old'] == [u'Test_Item']
-        assert item.meta['comment'] == u'renamed'
+        assert item.meta[NAME_OLD] == [u'Test_Item']
+        assert item.meta[COMMENT] == u'renamed'
         assert item.content.data == u'test_data'
 
     def test_rename_acts_only_in_active_name_in_case_there_are_several_names(self):
@@ -234,7 +230,7 @@
         assert item1.rev.revid == item2.rev.revid == item3.rev.revid
 
         item4 = Item.create(u'Second')
-        assert item4.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item4.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
 
     def test_rename_recursion(self):
         update_item(u'Page', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Page 1')
@@ -247,31 +243,31 @@
         # items at original name and its contents after renaming
         item = Item.create(u'Page')
         assert item.name == u'Page'
-        assert item.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         item = Item.create(u'Page/Child')
         assert item.name == u'Page/Child'
-        assert item.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         item = Item.create(u'Page/Child/Another')
         assert item.name == u'Page/Child/Another'
-        assert item.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
 
         # item at new name and its contents after renaming
         item = Item.create(u'Renamed_Page')
         assert item.name == u'Renamed_Page'
-        assert item.meta['name_old'] == [u'Page']
-        assert item.meta['comment'] == u'renamed'
+        assert item.meta[NAME_OLD] == [u'Page']
+        assert item.meta[COMMENT] == u'renamed'
         assert item.content.data == u'Page 1'
 
         item = Item.create(u'Renamed_Page/Child')
         assert item.name == u'Renamed_Page/Child'
-        assert item.meta['name_old'] == [u'Page/Child']
-        assert item.meta['comment'] == u'renamed'
+        assert item.meta[NAME_OLD] == [u'Page/Child']
+        assert item.meta[COMMENT] == u'renamed'
         assert item.content.data == u'this is child'
 
         item = Item.create(u'Renamed_Page/Child/Another')
         assert item.name == u'Renamed_Page/Child/Another'
-        assert item.meta['name_old'] == [u'Page/Child/Another']
-        assert item.meta['comment'] == u'renamed'
+        assert item.meta[NAME_OLD] == [u'Page/Child/Another']
+        assert item.meta[COMMENT] == u'renamed'
         assert item.content.data == u'another child'
 
     def test_rename_recursion_with_multiple_names_and_children(self):
@@ -293,12 +289,12 @@
 
         item.rename(u'Renamed', comment=u'renamed')
 
-        assert Item.create(u'Page/Child').meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert Item.create(u'Page/Child').meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         assert Item.create(u'Renamed/Child').content.data == u'Child of Page'
-        assert Item.create(u'Page/Second').meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert Item.create(u'Page/Second').meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         assert Item.create(u'Renamed/Second').content.data == u'Both'
         assert Item.create(u'Another').content.data == u'Both'
-        assert Item.create(u'Page/Second/Child').meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert Item.create(u'Page/Second/Child').meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
         assert Item.create(u'Renamed/Second/Child').content.data == u'Child of Second'
         assert Item.create(u'Other/Child2').content.data == u'Child of Other'
         assert Item.create(u'Another/Child').content.data == u'Child of Another'
@@ -314,13 +310,13 @@
         # item and its contents before deleting
         item = Item.create(name)
         assert item.name == u'Test_Item2'
-        assert item.meta['comment'] == u'saved it'
+        assert item.meta[COMMENT] == u'saved it'
         item.delete(u'deleted')
         # item and its contents after deletion
         item = Item.create(name)
         assert item.name == u'Test_Item2'
         # this should be a fresh, new item, NOT the stuff we deleted:
-        assert item.meta[CONTENTTYPE] == 'application/x-nonexistent'
+        assert item.meta[CONTENTTYPE] == CONTENTTYPE_NONEXISTENT
 
     def test_revert(self):
         name = u'Test_Item'
@@ -333,7 +329,7 @@
         item = Item.create(name)
         item.revert(u'revert')
         item = Item.create(name)
-        assert item.meta['action'] == u'REVERT'
+        assert item.meta[ACTION] == u'REVERT'
 
     def test_modify(self):
         name = u'Test_Item'
--- a/MoinMoin/items/blog.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/blog.py	Sat Feb 16 23:21:46 2013 +0100
@@ -32,11 +32,13 @@
     supertags = (Tags.using(label=L_('Supertags (Categories)'))
                  .with_properties(placeholder=L_("Ordered comma separated list of tags")))
 
+
 class BlogEntryMetaForm(BaseMetaForm):
     summary = (OptionalText.using(label=L_("Title"))
                .with_properties(placeholder=L_("One-line title of the blog entry")))
     ptime = DateTime.using(label=L_('Publication time (UTC)'), optional=True)
 
+
 @register
 class Blog(Default):
     itemtype = ITEMTYPE_BLOG
@@ -89,6 +91,7 @@
                                tag=tag,
                               )
 
+
 @register
 class BlogEntry(Default):
     itemtype = ITEMTYPE_BLOG_ENTRY
--- a/MoinMoin/items/content.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/content.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,7 +17,9 @@
     Each class in this module corresponds to a contenttype value.
 """
 
-import os, re, base64
+import os
+import re
+import base64
 import tarfile
 import zipfile
 import tempfile
@@ -43,12 +45,12 @@
     from PIL import Image as PILImage
     from PIL.ImageChops import difference as PILdiff
 except ImportError:
-    PIL = None
+    PIL = PILImage = PILdiff = None
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import wikiutil, config
+from MoinMoin import wikiutil
 from MoinMoin.i18n import _, L_
 from MoinMoin.themes import render_template
 from MoinMoin.storage.error import StorageError
@@ -63,11 +65,9 @@
 from MoinMoin.forms import File
 from MoinMoin.constants.contenttypes import (
     GROUP_MARKUP_TEXT, GROUP_OTHER_TEXT, GROUP_IMAGE, GROUP_AUDIO, GROUP_VIDEO,
-    GROUP_DRAWING, GROUP_OTHER, CONTENTTYPE_NONEXISTENT,
+    GROUP_DRAWING, GROUP_OTHER, CONTENTTYPE_NONEXISTENT, CHARSET
     )
-from MoinMoin.constants.keys import (
-    NAME, NAME_EXACT, WIKINAME, CONTENTTYPE, SIZE, TAGS, HASH_ALGORITHM
-    )
+from MoinMoin.constants.keys import NAME_EXACT, WIKINAME, CONTENTTYPE, SIZE, TAGS, HASH_ALGORITHM
 
 
 COLS = 80
@@ -75,7 +75,8 @@
 
 
 class RegistryContent(RegistryBase):
-    class Entry(namedtuple('Entry', 'factory content_type default_contenttype_params display_name ingroup_order priority')):
+    class Entry(namedtuple('Entry',
+                           'factory content_type default_contenttype_params display_name ingroup_order priority')):
         def __call__(self, content_type, *args, **kw):
             if self.content_type.issupertype(Type(content_type)):
                 return self.factory(content_type, *args, **kw)
@@ -116,8 +117,11 @@
     GROUP_OTHER
 ])
 
+
 def register(cls):
-    content_registry.register(RegistryContent.Entry(cls._factory, Type(cls.contenttype), cls.default_contenttype_params, cls.display_name, cls.ingroup_order, RegistryContent.PRIORITY_MIDDLE), cls.group)
+    content_registry.register(RegistryContent.Entry(cls._factory, Type(cls.contenttype),
+                                                    cls.default_contenttype_params, cls.display_name,
+                                                    cls.ingroup_order, RegistryContent.PRIORITY_MIDDLE), cls.group)
     return cls
 
 
@@ -170,7 +174,7 @@
         return self.item.name
 
     def get_data(self):
-        return '' # TODO create a better method for binary stuff
+        return ''  # TODO create a better method for binary stuff
     data = property(fget=get_data)
 
     @timed('conv_in_dom')
@@ -245,7 +249,8 @@
             # we really want to make sure that invalid data or a malfunctioning
             # converter does not crash the item view (otherwise a user might
             # not be able to fix it from the UI).
-            import time, uuid
+            import time
+            import uuid
             error_id = uuid.uuid4()
             logging.exception("An exception happened in _render_data (error_id = %s ):" % error_id)
             rendered_data = render_template('crash.html',
@@ -304,6 +309,10 @@
     data = property(fget=get_data)
 
     class ModifyForm(Form):
+        """
+        The content part of the ModifyForm of an Item subclass. See also the
+        doc of Item._ModifyForm.
+        """
         template = 'modify_binary.html'
         help = """\
 There is no help, you're doomed!
@@ -318,7 +327,7 @@
             if data_file:
                 data = data_file.stream
                 # this is likely a guess by the browser, based on the filename
-                contenttype_guessed = data_file.content_type # comes from form multipart data
+                contenttype_guessed = data_file.content_type  # comes from form multipart data
                 return data, contenttype_guessed
             else:
                 return None, None
@@ -344,7 +353,7 @@
 
     def do_get(self, force_attachment=False, mimetype=None):
         hash = self.rev.meta.get(HASH_ALGORITHM)
-        if is_resource_modified(request.environ, hash): # use hash as etag
+        if is_resource_modified(request.environ, hash):  # use hash as etag
             return self._do_get_modified(hash, force_attachment=force_attachment, mimetype=mimetype)
         else:
             return Response(status=304)
@@ -354,7 +363,7 @@
         return self._do_get(hash, member, force_attachment=force_attachment, mimetype=mimetype)
 
     def _do_get(self, hash, member=None, force_attachment=False, mimetype=None):
-        if member: # content = file contained within a archive item revision
+        if member:  # content = file contained within a archive item revision
             path, filename = os.path.split(member)
             mt = MimeType(filename=filename)
             content_length = None
@@ -362,7 +371,7 @@
             # force attachment download, so it uses attachment_filename
             # otherwise it will use the itemname from the URL for saving
             force_attachment = True
-        else: # content = item revision
+        else:  # content = item revision
             rev = self.rev
             filename = rev.item.name
             try:
@@ -381,7 +390,7 @@
         return send_file(file=file_to_send,
                          mimetype=content_type,
                          as_attachment=as_attachment, attachment_filename=filename,
-                         cache_timeout=10, # wiki data can change rapidly
+                         cache_timeout=10,  # wiki data can change rapidly
                          add_etags=True, etag=hash, conditional=True)
 
 
@@ -447,7 +456,7 @@
         if isinstance(content, str):
             if content_length is None:
                 content_length = len(content)
-            content = StringIO(content) # we need a file obj
+            content = StringIO(content)  # we need a file obj
         elif not hasattr(content, 'read'):
             logging.error("unsupported content object: {0!r}".format(content))
             raise StorageError("unsupported content object: {0!r}".format(content))
@@ -638,12 +647,12 @@
         try:
             # if we have EXIF data, we can transpose (e.g. rotate left),
             # so the rendered image is correctly oriented:
-            transpose_op = transpose_op or 1 # or self.exif['Orientation']
+            transpose_op = transpose_op or 1  # or self.exif['Orientation']
         except KeyError:
-            transpose_op = 1 # no change
+            transpose_op = 1  # no change
 
         if size is not None:
-            image = image.copy() # create copy first as thumbnail works in-place
+            image = image.copy()  # create copy first as thumbnail works in-place
             image.thumbnail(size, PILImage.ANTIALIAS)
 
         transpose_func = {
@@ -728,7 +737,7 @@
         c = app.cache.get(cid)
         if c is None:
             if PIL is None:
-                abort(404) # TODO render user friendly error image
+                abort(404)  # TODO render user friendly error image
 
             content_type = newrev.meta[CONTENTTYPE]
             if content_type == 'image/jpeg':
@@ -754,7 +763,7 @@
                 app.cache.set(cid, (headers, data))
             except (IOError, ValueError) as err:
                 logging.exception("error during PILdiff: {0}".format(err.message))
-                abort(404) # TODO render user friendly error image
+                abort(404)  # TODO render user friendly error image
         else:
             # XXX TODO check ACL behaviour
             headers, data = c
@@ -826,11 +835,11 @@
 
     def data_internal_to_storage(self, text):
         """ convert data from memory format to storage format """
-        return text.replace(u'\n', u'\r\n').encode(config.charset)
+        return text.replace(u'\n', u'\r\n').encode(CHARSET)
 
     def data_storage_to_internal(self, data):
         """ convert data from storage format to memory format """
-        return data.decode(config.charset).replace(u'\r\n', u'\n')
+        return data.decode(CHARSET).replace(u'\r\n', u'\n')
 
     def _get_data_diff_html(self, oldrev, newrev, template):
         from MoinMoin.util.diff_html import diff
@@ -981,7 +990,7 @@
         return send_file(file=file_to_send,
                          mimetype=content_type,
                          as_attachment=as_attachment, attachment_filename=None,
-                         cache_timeout=10, # wiki data can change rapidly
+                         cache_timeout=10,  # wiki data can change rapidly
                          add_etags=False, etag=None, conditional=True)
 
 
@@ -1074,10 +1083,10 @@
         filecontent = file_upload.stream
         content_length = None
         if ext in ['.svg', '.draw', ]:  # handle AWD (svg) and TWD (draw)
-            filecontent = filecontent.read() # read file completely into memory
+            filecontent = filecontent.read()  # read file completely into memory
             filecontent = filecontent.replace("\r", "")
         elif ext == '.map':
-            filecontent = filecontent.read() # read file completely into memory
+            filecontent = filecontent.read()  # read file completely into memory
             filecontent = filecontent.strip()
         elif ext == '.png':
             #content_length = file_upload.content_length
@@ -1124,11 +1133,12 @@
     class ModifyForm(Draw.ModifyForm):
         template = "modify_anywikidraw.html"
         help = ""
+
         def _load(self, item):
             super(AnyWikiDraw.ModifyForm, self)._load(item)
             try:
                 drawing_exists = 'drawing.svg' in item.list_members()
-            except tarfile.TarError: # item doesn't exist yet
+            except tarfile.TarError:  # item doesn't exist yet
                 drawing_exists = False
             self.drawing_exists = drawing_exists
 
--- a/MoinMoin/items/ticket.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/items/ticket.py	Sat Feb 16 23:21:46 2013 +0100
@@ -19,7 +19,8 @@
 
 from MoinMoin.i18n import L_
 from MoinMoin.themes import render_template
-from MoinMoin.forms import Form, OptionalText, OptionalMultilineText, Submit, SmallNatural, Tags, Reference, BackReference
+from MoinMoin.forms import (Form, OptionalText, OptionalMultilineText, SmallNatural, Tags,
+                            Reference, BackReference)
 from MoinMoin.storage.middleware.protecting import AccessDenied
 from MoinMoin.constants.keys import ITEMTYPE, CONTENTTYPE, ITEMID, CURRENT
 from MoinMoin.constants.contenttypes import CONTENTTYPE_USER
@@ -36,6 +37,7 @@
 OptionalTicketReference = Reference.to(TICKET_QUERY).using(optional=True)
 OptionalUserReference = Reference.to(USER_QUERY).using(optional=True).with_properties(empty_label='(Nobody)')
 
+
 class TicketMetaForm(Form):
     summary = OptionalText.using(label=L_("Summary")).with_properties(placeholder=L_("One-line summary of the item"))
     effort = Rating.using(label=L_("Effort"))
@@ -47,6 +49,7 @@
     superseded_by = OptionalTicketReference.using(label=L_("Superseded By"))
     depends_on = OptionalTicketReference.using(label=L_("Depends On"))
 
+
 class TicketBackRefForm(Form):
     supersedes = BackReference.using(label=L_("Supersedes"))
     required_by = BackReference.using(label=L_("Required By"))
@@ -58,11 +61,12 @@
         self['required_by'].set(Term('depends_on', id_))
         self['subscribers'].set(Term('subscribed_items', id_))
 
+
 class TicketForm(BaseModifyForm):
     meta = TicketMetaForm
     backrefs = TicketBackRefForm
     message = OptionalMultilineText.using(label=L_("Message")).with_properties(rows=8, cols=80)
-    submit = Submit.using(default=L_("Update ticket"))
+    submit_label = L_("Update ticket")
 
     def _load(self, item):
         meta = item.prepare_meta_for_modify(item.meta)
@@ -103,6 +107,8 @@
             return self.do_modify()
 
     def do_modify(self):
+        is_new = isinstance(self.content, NonExistentContent)
+
         if request.method in ['GET', 'HEAD']:
             form = TicketForm.from_item(self)
         elif request.method == 'POST':
@@ -115,10 +121,7 @@
                     CONTENTTYPE: 'text/x.moin.wiki;charset=utf-8',
                 })
 
-                if isinstance(self.content, NonExistentContent):
-                    data = u''
-                else:
-                    data = self.content.data_storage_to_internal(self.content.data)
+                data = u'' if is_new else self.content.data_storage_to_internal(self.content.data)
                 message = form['message'].value
                 if message:
                     data += message_markup(message)
@@ -129,13 +132,11 @@
                     abort(403)
                 else:
                     return redirect(url_for('.show_item', item_name=self.name))
-        if isinstance(self.content, NonExistentContent):
-            is_new = True
+        if is_new:
             # XXX suppress the "foo doesn't exist. Create it?" dummy content
             data_rendered = None
-            form['submit'] = L_('Submit ticket')
+            form.submit_label = L_('Submit ticket')
         else:
-            is_new = False
             data_rendered = Markup(self.content._render_data())
 
         return render_template(self.modify_template,
--- a/MoinMoin/log.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/log.py	Sat Feb 16 23:21:46 2013 +0100
@@ -108,8 +108,8 @@
     # for warnings, we just want to use the logging system, not stderr or other files
     msg = "{0}:{1}: {2}: {3}".format(filename, lineno, category.__name__, message)
     logger = getLogger(__name__)
-    logger.warning(msg) # Note: the warning will look like coming from here,
-                        # but msg contains info about where it really comes from
+    logger.warning(msg)  # Note: the warning will look like coming from here,
+                         # but msg contains info about where it really comes from
 
 
 def load_config(conf_fname=None):
@@ -125,7 +125,7 @@
             l = getLogger(__name__)
             l.info('using logging configuration read from "{0}"'.format(conf_fname))
             warnings.showwarning = _log_warning
-        except Exception as err: # XXX be more precise
+        except Exception as err:  # XXX be more precise
             err_msg = str(err)
     if not configured:
         # load builtin fallback logging config
@@ -151,6 +151,6 @@
         load_config()
     logger = logging.getLogger(name)
     for levelnumber, levelname in logging._levelNames.items():
-        if isinstance(levelnumber, int): # that list has also the reverse mapping...
+        if isinstance(levelnumber, int):  # that list has also the reverse mapping...
             setattr(logger, levelname, levelnumber)
     return logger
--- a/MoinMoin/macro/Anchor.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/Anchor.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,6 +9,7 @@
 from MoinMoin.util.tree import moin_page
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class Macro(MacroInlineBase):
     def macro(self, content, arguments, page_url, alternative):
         if not arguments:
--- a/MoinMoin/macro/Date.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/Date.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,11 +10,11 @@
 import time
 from datetime import datetime
 
-from flask import g as flaskg
 from flask.ext.babel import format_date
 
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class MacroDateTimeBase(MacroInlineBase):
     def parse_time(self, args):
         """ parse a time specification argument for usage by Date and DateTime macro
@@ -30,8 +30,8 @@
             try:
                 year, month, day = int(args[0:4]), int(args[5:7]), int(args[8:10])
                 hour, minute, second = int(args[11:13]), int(args[14:16]), int(args[17:19])
-                tz = args[19:] # +HHMM, -HHMM or Z or nothing (then we assume Z)
-                tzoffset = 0 # we assume UTC no matter if there is a Z
+                tz = args[19:]  # +HHMM, -HHMM or Z or nothing (then we assume Z)
+                tzoffset = 0  # we assume UTC no matter if there is a Z
                 if tz:
                     sign = tz[0]
                     if sign in '+-':
@@ -47,7 +47,7 @@
             try:
                 tm = time.mktime(tm) - time.timezone - tzoffset
             except (OverflowError, ValueError):
-                tm = 0 # incorrect, but we avoid an ugly backtrace
+                tm = 0  # incorrect, but we avoid an ugly backtrace
         else:
             # try raw seconds since epoch in UTC
             try:
@@ -56,10 +56,11 @@
                 raise ValueError("Bad timestamp {0!r}: {1}".format(args, err))
         return tm
 
+
 class Macro(MacroDateTimeBase):
     def macro(self, content, arguments, page_url, alternative):
         if arguments is None:
-            tm = time.time() # always UTC
+            tm = time.time()  # always UTC
         else:
             # XXX looks like args are split at ':' -> <Arguments([u'2010-12-31T23', u'59', u'00'], {})>
             stamp = arguments[0]
--- a/MoinMoin/macro/DateTime.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/DateTime.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,15 +9,15 @@
 import time
 from datetime import datetime
 
-from flask import g as flaskg
 from flask.ext.babel import format_datetime
 
 from MoinMoin.macro.Date import MacroDateTimeBase
 
+
 class Macro(MacroDateTimeBase):
     def macro(self, content, arguments, page_url, alternative):
         if arguments is None:
-            tm = time.time() # always UTC
+            tm = time.time()  # always UTC
         else:
             stamp = arguments[0]
             tm = self.parse_time(stamp)
--- a/MoinMoin/macro/GetText.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/GetText.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,6 +15,7 @@
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class Macro(MacroInlineBase):
     """ Return a translation of args, or args as is """
     def macro(self, content, arguments, page_url, alternative):
--- a/MoinMoin/macro/GetVal.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/GetVal.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,6 +10,7 @@
 
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class Macro(MacroInlineBase):
     def macro(self, content, arguments, page_url, alternative):
         try:
--- a/MoinMoin/macro/MailTo.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/MailTo.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,6 +12,7 @@
 from MoinMoin.util.tree import moin_page, xlink
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class Macro(MacroInlineBase):
     def macro(self, content, arguments, page_url, alternative):
         # TODO new arg parsing is not compatible, splits at blanks
--- a/MoinMoin/macro/PagenameList.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/PagenameList.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,6 +14,7 @@
 
 from MoinMoin.macro._base import MacroPageLinkListBase
 
+
 class Macro(MacroPageLinkListBase):
     def macro(self, content, arguments, page_url, alternative):
         # needle=u'', regex=False
--- a/MoinMoin/macro/RandomItem.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/RandomItem.py	Sat Feb 16 23:21:46 2013 +0100
@@ -58,5 +58,5 @@
             result.append(moin_page.a(attrib={xlink.href: link}, children=[name]))
             result.append(", ")
 
-        del result[-1] # kill last comma
+        del result[-1]  # kill last comma
         return result
--- a/MoinMoin/macro/Verbatim.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/Verbatim.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,6 +8,7 @@
 
 from MoinMoin.macro._base import MacroInlineBase
 
+
 class Macro(MacroInlineBase):
     def macro(self, text=u''):
         return text
--- a/MoinMoin/macro/_base.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/_base.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,6 +9,7 @@
 from MoinMoin.util import iri
 from MoinMoin.util.tree import moin_page, xlink
 
+
 class MacroBase(object):
     """
     Macro base class.
@@ -23,6 +24,7 @@
     def __call__(self, content, arguments, page_url, alternative, context_block):
         raise NotImplementedError
 
+
 class MacroBlockBase(MacroBase):
     """
     Macro base class for block element macros.
@@ -38,6 +40,7 @@
     def macro(self, content, arguments, page_url, alternative):
         raise NotImplementedError
 
+
 class MacroInlineBase(MacroBase):
     """
     Macro base class for inline element macros.
@@ -50,6 +53,7 @@
             return moin_page.p(children=(ret, ))
         return ret
 
+
 class MacroInlineOnlyBase(MacroBase):
     """
     Macro base class for strict inline element macros.
@@ -61,6 +65,7 @@
         if not context_block:
             return self.macro(content, arguments, page_url, alternative)
 
+
 class MacroPageLinkListBase(MacroBlockBase):
     def create_pagelink_list(self, pagenames, ordered=False):
         """ creates an ET with a list of pagelinks from a list of pagenames """
@@ -74,6 +79,7 @@
             page_list.append(item)
         return page_list
 
+
 class MacroNumberPageLinkListBase(MacroBlockBase):
     def create_number_pagelink_list(self, num_pagenames, ordered=False):
         """ creates an ET with a list of pagelinks from a list of pagenames """
@@ -88,6 +94,7 @@
             num_page_list.append(item)
         return num_page_list
 
+
 class MacroDefinitionListBase(MacroBlockBase):
     def create_definition_list(self, items):
         """ creates an ET with a definition list made from items """
--- a/MoinMoin/macro/_tests/test_GetText.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/_tests/test_GetText.py	Sat Feb 16 23:21:46 2013 +0100
@@ -5,7 +5,6 @@
 Test for macro.GetText
 """
 
-import pytest
 from MoinMoin.converter._args import Arguments
 from MoinMoin.macro.GetText import *
 
--- a/MoinMoin/macro/_tests/test_GetVal.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/macro/_tests/test_GetVal.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,7 +8,7 @@
 from flask import g as flaskg
 
 from MoinMoin.macro.GetVal import *
-from MoinMoin.config import SOMEDICT
+from MoinMoin.constants.keys import SOMEDICT
 from MoinMoin._tests import become_trusted, update_item
 from MoinMoin.conftest import init_test_app, deinit_test_app
 from MoinMoin._tests import wikiconfig
--- a/MoinMoin/mail/_tests/test_sendmail.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/mail/_tests/test_sendmail.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,7 @@
 from email.Charset import Charset, QP
 from email.Header import Header
 from MoinMoin.mail import sendmail
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import CHARSET
 
 
 class TestdecodeSpamSafeEmail(object):
@@ -77,14 +77,14 @@
     name-addr   =   [display-name] angle-addr
     angle-addr  =   [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
     """
-    charset = Charset(config.charset)
+    charset = Charset(CHARSET)
     charset.header_encoding = QP
     charset.body_encoding = QP
 
     def testSimpleAddress(self):
         """ mail.sendmail: encode simple address: local@domain """
         address = u'local@domain'
-        expected = address.encode(config.charset)
+        expected = address.encode(CHARSET)
         assert sendmail.encodeAddress(address, self.charset) == expected
 
     def testComposite(self):
--- a/MoinMoin/mail/sendmail.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/mail/sendmail.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,7 +8,8 @@
 """
 
 
-import os, re
+import os
+import re
 from email.Header import Header
 
 from MoinMoin import log
@@ -16,7 +17,7 @@
 
 from flask import current_app as app
 
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import CHARSET
 from MoinMoin.i18n import _, L_, N_
 
 _transdict = {"AT": "@", "DOT": ".", "DASH": "-"}
@@ -45,7 +46,7 @@
         try:
             str(phrase)  # is it pure ascii?
         except UnicodeEncodeError:
-            phrase = phrase.encode(config.charset)
+            phrase = phrase.encode(CHARSET)
             phrase = Header(phrase, charset)
         blanks = match.group('blanks')
         addr = match.group('addr')
@@ -79,14 +80,16 @@
     :rtype: tuple
     :returns: (is_ok, Description of error or OK message)
     """
-    import smtplib, socket
+    import smtplib
+    import socket
     from email.Message import Message
     from email.Charset import Charset, QP
     from email.Utils import formatdate, make_msgid
 
     cfg = app.cfg
     if not cfg.mail_enabled:
-        return (0, _("Contact administrator: cannot send password recovery e-mail because mail configuration is incomplete."))
+        return (0, _("Contact administrator: cannot send password recovery e-mail "
+                     "because mail configuration is incomplete."))
     mail_from = mail_from or cfg.mail_from
 
     logging.debug("send mail, from: {0!r}, subj: {1!r}".format(mail_from, subject))
@@ -95,17 +98,17 @@
     if not to and not cc and not bcc:
         return (1, _("No recipients, nothing to do"))
 
-    subject = subject.encode(config.charset)
+    subject = subject.encode(CHARSET)
 
     # Create a text/plain body using CRLF (see RFC2822)
     text = text.replace(u'\n', u'\r\n')
-    text = text.encode(config.charset)
+    text = text.encode(CHARSET)
 
-    # Create a message using config.charset and quoted printable
+    # Create a message using CHARSET and quoted printable
     # encoding, which should be supported better by mail clients.
     # TODO: check if its really works better for major mail clients
     msg = Message()
-    charset = Charset(config.charset)
+    charset = Charset(CHARSET)
     charset.header_encoding = QP
     charset.body_encoding = QP
     msg.set_charset(charset)
@@ -145,7 +148,7 @@
             try:
                 #server.set_debuglevel(1)
                 if cfg.mail_username is not None and cfg.mail_password is not None:
-                    try: # try to do tls
+                    try:  # try to do TLS
                         server.ehlo()
                         if server.has_extn('starttls'):
                             server.starttls()
@@ -213,6 +216,7 @@
 
     return address
 
+
 def decodeSpamSafeEmail(address):
     """ Decode obfuscated email address to standard email address
 
--- a/MoinMoin/script/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -18,8 +18,10 @@
 
     manager = Manager(create_app)
     manager.add_option('-c', '--config', dest='config', required=False, default=wiki_config)
-    manager.add_option('-i', '--index-create', action='store_true', dest='create_index', required=False, default=False)
-    manager.add_option('-s', '--storage-create', action='store_true', dest='create_storage', required=False, default=False)
+    manager.add_option('-i', '--index-create', action='store_true', dest='create_index',
+                       required=False, default=False)
+    manager.add_option('-s', '--storage-create', action='store_true', dest='create_storage',
+                       required=False, default=False)
     manager.add_command("moin", Server(host='127.0.0.1', port=8080))
 
     from MoinMoin.script.maint import index
--- a/MoinMoin/script/account/create.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/account/create.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,8 +7,6 @@
 """
 
 
-from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
 from MoinMoin import user
--- a/MoinMoin/script/account/disable.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/account/disable.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,8 +7,6 @@
 """
 
 
-from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
 from MoinMoin import user
@@ -42,12 +40,12 @@
             return
 
         print " {0:<20} {1:!r<25} {2:<35}".format(u.itemid, u.name, u.email),
-        if not u.disabled: # only disable once
+        if not u.disabled:  # only disable once
             u.disabled = 1
             u.name = u"{0}-{1}".format(u.name, u.id)
             if u.email:
                 u.email = u"{0}-{1}".format(u.email, u.id)
-            u.subscribed_items = [] # avoid using email
+            u.subscribed_items = []  # avoid using email
             u.save()
             print "- disabled."
         else:
--- a/MoinMoin/script/account/resetpw.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/account/resetpw.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,8 +8,6 @@
 """
 
 
-from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
 from MoinMoin.constants.keys import ITEMID, NAME, NAME_EXACT, EMAIL
@@ -20,9 +18,11 @@
 class Fault(Exception):
     """something went wrong"""
 
+
 class NoSuchUser(Fault):
     """raised if no such user exists"""
 
+
 class MailFailed(Fault):
     """raised if e-mail sending failed"""
 
--- a/MoinMoin/script/maint/index.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/index.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,14 +7,12 @@
 
 
 from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin.config import LATEST_REVS, ALL_REVS
-from MoinMoin.storage.middleware.indexing import ALL_REVS, LATEST_REVS
+from MoinMoin.constants.keys import LATEST_REVS, ALL_REVS
 
 
 class IndexCreate(Command):
--- a/MoinMoin/script/maint/modified_systemitems.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/modified_systemitems.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,7 +12,8 @@
 from flask import current_app as app
 from flask.ext.script import Command
 
-from MoinMoin.config import IS_SYSITEM, SYSITEM_VERSION
+from MoinMoin.constants.keys import IS_SYSITEM, SYSITEM_VERSION
+
 
 class Modified_SystemItems(Command):
     description = 'This command can be used to list system items that has been edited in this wiki.'
--- a/MoinMoin/script/maint/modify_item.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/modify_item.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,10 +9,9 @@
 import json
 
 from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
-from MoinMoin.config import CURRENT, ITEMID, REVID, DATAID, SIZE, HASH_ALGORITHM
+from MoinMoin.constants.keys import CURRENT, ITEMID, REVID, DATAID, SIZE, HASH_ALGORITHM
 
 
 class GetItem(Command):
@@ -55,7 +54,7 @@
             meta = mf.read()
         meta = meta.decode('utf-8')
         meta = json.loads(meta)
-        to_kill = [SIZE, HASH_ALGORITHM, # gets re-computed automatically
+        to_kill = [SIZE, HASH_ALGORITHM,  # gets re-computed automatically
                    DATAID,
                   ]
         for key in to_kill:
--- a/MoinMoin/script/maint/moinshell.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/moinshell.py	Sat Feb 16 23:21:46 2013 +0100
@@ -2,14 +2,12 @@
 
 import code
 
-from flask import Flask, _request_ctx_stack
 from flask import current_app as app
 from flask import g as flaskg
 from flask.ext.script import Command, Option
 
-from MoinMoin import user
 from MoinMoin.app import before_wiki
-from MoinMoin.util.clock import Clock
+
 
 class MoinShell(Command):
     """
@@ -46,7 +44,7 @@
                 Option('--no-ipython',
                        action="store_true",
                        dest='no_ipython',
-                       default=not(self.use_ipython)), )
+                       default=not self.use_ipython), )
 
     def get_context(self):
         """
--- a/MoinMoin/script/maint/reduce_revisions.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/reduce_revisions.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,7 +16,7 @@
 
 from whoosh.query import Every
 
-from MoinMoin.config import NAME, NAME_EXACT, REVID
+from MoinMoin.constants.keys import NAME, NAME_EXACT, REVID
 
 
 class Reduce_Revisions(Command):
--- a/MoinMoin/script/maint/serialization.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/serialization.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,7 +8,6 @@
 import sys
 
 from flask import current_app as app
-from flask import g as flaskg
 from flask.ext.script import Command, Option
 
 from MoinMoin.storage.middleware.serialization import serialize, deserialize
@@ -16,6 +15,7 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
+
 def open_file(filename, mode):
     if filename is None:
         # Guess the IO stream from the mode:
@@ -28,7 +28,8 @@
 
         # On Windows force the stream to be in binary mode if it's needed.
         if sys.platform == "win32" and "b" in mode:
-            import os, msvcrt
+            import os
+            import msvcrt
             msvcrt.setmode(stream.fileno(), os.O_BINARY)
 
         f = stream
@@ -36,6 +37,7 @@
         f = open(filename, mode)
     return f
 
+
 class Serialize(Command):
     description = 'Serialize the backend into a file.'
 
--- a/MoinMoin/script/maint/set_meta.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/maint/set_meta.py	Sat Feb 16 23:21:46 2013 +0100
@@ -19,7 +19,7 @@
 
 from whoosh.query import Every
 
-from MoinMoin.config import NAME, NAME_EXACT
+from MoinMoin.constants.keys import NAME, NAME_EXACT
 from MoinMoin.script import fatal
 
 
@@ -49,7 +49,7 @@
 
         if query:
             qp = app.storage.query_parser([NAME_EXACT, ])
-            q = qp.parse(query_text)
+            q = qp.parse(query)
         else:
             q = Every()
 
--- a/MoinMoin/script/migration/moin19/_utils19.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/migration/moin19/_utils19.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,7 @@
 
 import re
 
-from MoinMoin.config import NAME, ACL, CONTENTTYPE, MTIME, LANGUAGE
+from MoinMoin.constants.keys import NAME, ACL, CONTENTTYPE, MTIME, LANGUAGE
 
 CHARSET = 'utf-8'
 
--- a/MoinMoin/script/migration/moin19/import19.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/script/migration/moin19/import19.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,7 +14,6 @@
 """
 
 
-import sys
 import os
 import re
 import codecs
@@ -30,18 +29,14 @@
 from ._utils19 import quoteWikinameFS, unquoteWikiname, split_body
 from ._logfile19 import LogFile
 
-from MoinMoin.config import ACL, CONTENTTYPE, NAME, NAME_OLD, REVERTED_TO, \
-                            ACTION, ADDRESS, HOSTNAME, USERID, MTIME, EXTRA, COMMENT, \
-                            IS_SYSITEM, SYSITEM_VERSION, \
-                            TAGS, SIZE, HASH_ALGORITHM, \
-                            ITEMID, REVID, DATAID, CONTENTTYPE_USER
+from MoinMoin.constants.keys import *
+from MoinMoin.constants.contenttypes import CONTENTTYPE_USER
 
-UID_OLD = 'old_user_id' # dynamic field *_id, so we don't have to change schema
+UID_OLD = 'old_user_id'  # dynamic field *_id, so we don't have to change schema
 
 from MoinMoin.storage.error import NoSuchRevisionError
 from MoinMoin.util.mimetype import MimeType
 from MoinMoin.util.crypto import make_uuid
-from MoinMoin.storage.middleware.serialization import serialize_rev
 from MoinMoin import security
 
 
@@ -77,9 +72,9 @@
 
     def run(self, data_dir=None):
         indexer = app.storage
-        backend = indexer.backend # backend without indexing
+        backend = indexer.backend  # backend without indexing
         print "Users..."
-        for rev in UserBackend(os.path.join(data_dir, 'user')): # assumes user/ below data_dir
+        for rev in UserBackend(os.path.join(data_dir, 'user')):  # assumes user/ below data_dir
             backend.store(rev.meta, rev.data)
 
         print "Pages/Attachments..."
@@ -90,7 +85,8 @@
         indexer.rebuild()
 
         print "Fix userids..."
-        userid_map = dict([(rev.meta[UID_OLD], rev.meta[ITEMID]) for rev in indexer.documents(contenttype=CONTENTTYPE_USER)])
+        userid_map = dict([(rev.meta[UID_OLD], rev.meta[ITEMID])
+                           for rev in indexer.documents(contenttype=CONTENTTYPE_USER)])
         for mountpoint, revid in backend:
             meta, data = backend.retrieve(mountpoint, revid)
             if USERID in meta:
@@ -102,7 +98,7 @@
                     del meta[USERID]
                 backend.store(meta, data)
             elif meta.get(CONTENTTYPE) == CONTENTTYPE_USER:
-                meta.pop(UID_OLD, None) # not needed any more
+                meta.pop(UID_OLD, None)  # not needed any more
                 backend.store(meta, data)
 
         print "Rebuilding the index..."
@@ -171,11 +167,11 @@
             self.current = int(f.read().strip())
         editlogpath = os.path.join(self.path, 'edit-log')
         self.editlog = EditLog(editlogpath)
-        self.acl = None # TODO
+        self.acl = None  # TODO
         self.itemid = make_uuid()
         if backend.deleted_mode == DELETED_MODE_KILL:
             revpath = os.path.join(self.path, 'revisions', '{0:08d}'.format(self.current))
-            PageRevision(self, self.current, revpath) # will raise exception if killing is requested
+            PageRevision(self, self.current, revpath)  # will raise exception if killing is requested
 
     def iter_revisions(self):
         revisionspath = os.path.join(self.path, 'revisions')
@@ -200,7 +196,8 @@
         for fname in fnames:
             attachname = fname.decode('utf-8')
             try:
-                yield AttachmentRevision(self.name, attachname, os.path.join(attachmentspath, fname), self.editlog, self.acl)
+                yield AttachmentRevision(self.name, attachname, os.path.join(attachmentspath, fname),
+                                         self.editlog, self.acl)
             except Exception as err:
                 logging.exception("AttachmentRevision {0!r}/{1!r} raised exception:".format(self.name, attachname))
 
@@ -223,13 +220,13 @@
                 raise KillRequested('deleted_mode wants killing/ignoring')
             # handle deleted revisions (for all revnos with 0<=revno<=current) here
             # we prepare some values for the case we don't find a better value in edit-log:
-            meta = {MTIME: -1, # fake, will get 0 in the end
-                    NAME: item_name, # will get overwritten with name from edit-log
-                                     # if we have an entry there
+            meta = {MTIME: -1,  # fake, will get 0 in the end
+                    NAME: item_name,  # will get overwritten with name from edit-log
+                                      # if we have an entry there
                    }
             try:
-                revpath = os.path.join(item.path, 'revisions', '{0:08d}'.format(revno-1))
-                previous_meta = PageRevision(item, revno-1, revpath).meta
+                revpath = os.path.join(item.path, 'revisions', '{0:08d}'.format(revno - 1))
+                previous_meta = PageRevision(item, revno - 1, revpath).meta
                 # if this page revision is deleted, we have no on-page metadata.
                 # but some metadata is required, thus we have to copy it from the
                 # (non-deleted) revision revno-1:
@@ -237,24 +234,25 @@
                     if key in previous_meta:
                         meta[key] = previous_meta[key]
             except NoSuchRevisionError:
-                pass # should not happen
-            meta[MTIME] += 1 # it is now either 0 or prev rev mtime + 1
+                pass  # should not happen
+            meta[MTIME] += 1  # it is now either 0 or prev rev mtime + 1
             data = u''
             try:
                 editlog_data = editlog.find_rev(revno)
             except KeyError:
                 if 0 <= revno <= item._fs_current:
-                    editlog_data = { # make something up
+                    editlog_data = {  # make something up
                         ACTION: u'SAVE/DELETE',
                     }
                 else:
-                    raise NoSuchRevisionError('Item {0!r} has no revision {1} (not even a deleted one)!'.format(item.name, revno))
+                    raise NoSuchRevisionError('Item {0!r} has no revision {1} (not even a deleted one)!'.format(
+                                              item.name, revno))
         else:
             try:
                 editlog_data = editlog.find_rev(revno)
             except KeyError:
                 if 1 <= revno <= item.current:
-                    editlog_data = { # make something up
+                    editlog_data = {  # make something up
                         NAME: item.name,
                         MTIME: int(os.path.getmtime(path)),
                         ACTION: u'SAVE',
@@ -329,7 +327,7 @@
         try:
             meta = editlog.find_attach(attach_name)
         except KeyError:
-            meta = { # make something up
+            meta = {  # make something up
                 MTIME: int(os.path.getmtime(attpath)),
                 ACTION: u'SAVE',
             }
@@ -361,14 +359,14 @@
         keys = (MTIME, '__rev', ACTION, NAME, ADDRESS, HOSTNAME, USERID, EXTRA, COMMENT)
         result = dict(zip(keys, fields))
         # do some conversions/cleanups/fallbacks:
-        result[MTIME] = int(long(result[MTIME] or 0) / 1000000) # convert usecs to secs
-        result['__rev'] = int(result['__rev']) - 1 # old storage is 1-based, we want 0-based
+        result[MTIME] = int(long(result[MTIME] or 0) / 1000000)  # convert usecs to secs
+        result['__rev'] = int(result['__rev']) - 1  # old storage is 1-based, we want 0-based
         result[NAME] = unquoteWikiname(result[NAME])
         action = result[ACTION]
         extra = result[EXTRA]
         if extra:
             if action.startswith('ATT'):
-                result[NAME] += u'/' + extra # append filename to pagename
+                result[NAME] += u'/' + extra  # append filename to pagename
                 # keep EXTRA for find_attach
             elif action == 'SAVE/RENAME':
                 if extra:
@@ -395,7 +393,7 @@
             self.to_begin()
             raise KeyError
         del meta['__rev']
-        meta = dict([(k, v) for k, v in meta.items() if v]) # remove keys with empty values
+        meta = dict([(k, v) for k, v in meta.items() if v])  # remove keys with empty values
         if meta.get(ACTION) == u'SAVENEW':
             # replace SAVENEW with just SAVE
             meta[ACTION] = u'SAVE'
@@ -403,7 +401,7 @@
 
     def find_attach(self, attachname):
         """ Find metadata for some attachment name in the edit-log. """
-        for meta in self.reverse(): # use reverse iteration to get the latest upload's data
+        for meta in self.reverse():  # use reverse iteration to get the latest upload's data
             if (meta['__rev'] == 99999998 and  # 99999999-1 because of 0-based
                 meta[ACTION] == 'ATTNEW' and
                 meta[EXTRA] == attachname):
@@ -412,9 +410,9 @@
             self.to_end()
             raise KeyError
         del meta['__rev']
-        del meta[EXTRA] # we have full name in NAME
+        del meta[EXTRA]  # we have full name in NAME
         meta[ACTION] = u'SAVE'
-        meta = dict([(k, v) for k, v in meta.items() if v]) # remove keys with empty values
+        meta = dict([(k, v) for k, v in meta.items() if v])  # remove keys with empty values
         return meta
 
 
@@ -429,7 +427,7 @@
             result.append("{0}{1}:{2}".format(
                           modifier,
                           u','.join(entries),
-                          u','.join(rights) # iterator has removed invalid rights
+                          u','.join(rights)  # iterator has removed invalid rights
                          ))
     result = u' '.join(result)
     logging.debug("regenerate_acl {0!r} -> {1!r}".format(acl_string, result))
@@ -448,6 +446,7 @@
     items = [item for item in items if item]
     return tuple(items)
 
+
 def _decode_dict(line):
     """
     Decode dict of key:value pairs from user data file
@@ -501,20 +500,20 @@
 
     def _process_usermeta(self, metadata):
         # stuff we want to have stored as boolean:
-        bool_defaults = [ # taken from cfg.checkbox_defaults
-            ('show_comments', 'False'),
-            ('edit_on_doubleclick', 'True'),
-            ('scroll_page_after_edit', 'True'),
-            ('want_trivial', 'False'),
-            ('mailto_author', 'False'),
-            ('disabled', 'False'),
+        bool_defaults = [  # taken from cfg.checkbox_defaults
+            (SHOW_COMMENTS, 'False'),
+            (EDIT_ON_DOUBLECLICK, 'True'),
+            (SCROLL_PAGE_AFTER_EDIT, 'True'),
+            (WANT_TRIVIAL, 'False'),
+            (MAILTO_AUTHOR, 'False'),
+            (DISABLED, 'False'),
         ]
         for key, default in bool_defaults:
             metadata[key] = metadata.get(key, default) in ['True', 'true', '1']
 
         # stuff we want to have stored as integer:
         int_defaults = [
-            ('edit_rows', '0'),
+            (EDIT_ROWS, '0'),
         ]
         for key, default in int_defaults:
             metadata[key] = int(metadata.get(key, default))
@@ -523,42 +522,42 @@
         metadata[MTIME] = int(float(metadata.get('last_saved', '0')))
 
         # rename aliasname to display_name:
-        metadata['display_name'] = metadata.get('aliasname')
+        metadata[DISPLAY_NAME] = metadata.get('aliasname')
 
         # rename subscribed_pages to subscribed_items
-        metadata['subscribed_items'] = metadata.get('subscribed_pages', [])
+        metadata[SUBSCRIBED_ITEMS] = metadata.get('subscribed_pages', [])
 
         # convert bookmarks from usecs (and str) to secs (int)
-        metadata['bookmarks'] = [(interwiki, int(long(bookmark)/1000000))
-                                 for interwiki, bookmark in metadata.get('bookmarks', {}).items()]
+        metadata[BOOKMARKS] = [(interwiki, int(long(bookmark) / 1000000))
+                               for interwiki, bookmark in metadata.get('bookmarks', {}).items()]
 
         # stuff we want to get rid of:
-        kill = ['aliasname', # renamed to display_name
-                'real_language', # crap (use 'language')
-                'wikiname_add_spaces', # crap magic (you get it like it is)
-                'recoverpass_key', # user can recover again if needed
-                'editor_default', # not used any more
-                'editor_ui', # not used any more
-                'external_target', # ancient, not used any more
-                'passwd', # ancient, not used any more (use enc_password)
-                'show_emoticons', # ancient, not used any more
-                'show_fancy_diff', # kind of diff display now depends on mimetype
-                'show_fancy_links', # not used any more (now link rendering depends on theme)
-                'show_toolbar', # not used any more
-                'show_topbottom', # crap
-                'show_nonexist_qm', # crap, can be done by css
-                'show_page_trail', # theme decides whether to show trail
-                'remember_last_visit', # we show trail, user can click there
-                'remember_me', # don't keep sessions open for a long time
-                'subscribed_pages', # renamed to subscribed_items
-                'edit_cols', # not used any more
-                'jid', # no jabber support
-                'tz_offset', # we have real timezone now
-                'date_fmt', # not used any more
-                'datetime_fmt', # not used any more
-                'last_saved', # renamed to MTIME
-                'email_subscribed_events', # XXX no support yet
-                'jabber_subscribed_events', # XXX no support yet
+        kill = ['aliasname',  # renamed to display_name
+                'real_language',  # crap (use 'language')
+                'wikiname_add_spaces',  # crap magic (you get it like it is)
+                'recoverpass_key',  # user can recover again if needed
+                'editor_default',  # not used any more
+                'editor_ui',  # not used any more
+                'external_target',  # ancient, not used any more
+                'passwd',  # ancient, not used any more (use enc_password)
+                'show_emoticons',  # ancient, not used any more
+                'show_fancy_diff',  # kind of diff display now depends on mimetype
+                'show_fancy_links',  # not used any more (now link rendering depends on theme)
+                'show_toolbar',  # not used any more
+                'show_topbottom',  # crap
+                'show_nonexist_qm',  # crap, can be done by css
+                'show_page_trail',  # theme decides whether to show trail
+                'remember_last_visit',  # we show trail, user can click there
+                'remember_me',  # don't keep sessions open for a long time
+                'subscribed_pages',  # renamed to subscribed_items
+                'edit_cols',  # not used any more
+                'jid',  # no jabber support
+                'tz_offset',  # we have real timezone now
+                'date_fmt',  # not used any more
+                'datetime_fmt',  # not used any more
+                'last_saved',  # renamed to MTIME
+                'email_subscribed_events',  # XXX no support yet
+                'jabber_subscribed_events',  # XXX no support yet
                ]
         for key in kill:
             if key in metadata:
@@ -566,22 +565,22 @@
 
         # finally, remove some empty values (that have empty defaults anyway or
         # make no sense when empty):
-        empty_kill = ['aliasname', 'display_name', 'bookmarks', 'enc_password',
-                      'language', 'css_url', 'email', ] # XXX check subscribed_items, quicklinks
+        empty_kill = ['aliasname', DISPLAY_NAME, BOOKMARKS, ENC_PASSWORD,
+                      'language', CSS_URL, EMAIL, ]  # XXX check subscribed_items, quicklinks
         for key in empty_kill:
             if key in metadata and metadata[key] in [u'', tuple(), {}, [], ]:
                 del metadata[key]
 
         # moin2 only supports passlib generated hashes, drop everything else
         # (users need to do pw recovery in case they are affected)
-        pw = metadata.get('enc_password')
+        pw = metadata.get(ENC_PASSWORD)
         if pw is not None:
             if pw.startswith('{PASSLIB}'):
                 # take it, but strip the prefix as moin2 does not use that any more
-                metadata['enc_password'] = pw[len('{PASSLIB}'):]
+                metadata[ENC_PASSWORD] = pw[len('{PASSLIB}'):]
             else:
                 # drop old, unsupported (and also more or less unsafe) hashing scheme
-                del metadata['enc_password']
+                del metadata[ENC_PASSWORD]
 
         # TODO quicklinks and subscribed_items - check for non-interwiki elements and convert them to interwiki
 
--- a/MoinMoin/search/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/search/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,11 +6,12 @@
 """
 
 from MoinMoin.i18n import L_
-from MoinMoin.forms import Search, InlineCheckbox, Submit
+from MoinMoin.forms import Search, InlineCheckbox
 
 from flatland import Form, String, Boolean
 from flatland.validation import Validator
 
+
 class ValidSearch(Validator):
     """Validator for a valid search form
     """
@@ -24,9 +25,10 @@
             return self.note_error(element, state, 'too_short_query_msg')
         return True
 
+
 class SearchForm(Form):
     q = Search
     history = InlineCheckbox.using(label=L_('search all revisions'))
-    submit = Submit.using(default=L_('Search'))
+    submit_label = L_('Search')
 
     validators = [ValidSearch()]
--- a/MoinMoin/search/analyzers.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/search/analyzers.py	Sat Feb 16 23:21:46 2013 +0100
@@ -32,7 +32,7 @@
         :param positions: Whether to record token positions in the token.
         """
         assert isinstance(value, unicode), "{0!r} is not unicode".format(value)
-        if u'/' not in value: # Add '/' if user forgot do this
+        if u'/' not in value:  # Add '/' if user forgot do this
             value += u'/'
         pos = start_pos
         tk = Token()
@@ -71,7 +71,7 @@
 
     def __init__(self, acl_rights_contents):
         """
-        :param cfg: wiki config
+        :param acl_rights_contents: ACL for contents
         """
         self._acl_rights_contents = acl_rights_contents
 
--- a/MoinMoin/security/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,8 +17,10 @@
 from flask import abort
 
 from MoinMoin.constants import rights
+from MoinMoin.constants.keys import NAME_EXACT
 from MoinMoin import user
 from MoinMoin.i18n import _, L_, N_
+from MoinMoin.util.pysupport import AutoNe
 
 
 def require_permission(permission):
@@ -100,7 +102,7 @@
         raise AttributeError(attr)
 
 
-class AccessControlList(object):
+class AccessControlList(AutoNe):
     """
     Access Control List - controls who may do what.
 
@@ -174,7 +176,7 @@
         useful in the wiki configuration though.
     """
 
-    special_users = ["All", "Known", "Trusted"] # order is important
+    special_users = ["All", "Known", "Trusted"]  # order is important
 
     def __init__(self, lines=[], default='', valid=None):
         """ Initialize an ACL, starting from <nothing>.
@@ -184,7 +186,7 @@
         self.default = default
         assert isinstance(lines, (list, tuple))
         if lines:
-            self.acl = [] # [ ('User', {"read": 0, ...}), ... ]
+            self.acl = []  # [ ('User', {"read": 0, ...}), ... ]
             self.acl_lines = []
             for line in lines:
                 self._addLine(line)
@@ -242,7 +244,7 @@
         allowed = None
         for entry, rightsdict in self.acl:
             if entry in self.special_users:
-                handler = getattr(self, "_special_"+entry, None)
+                handler = getattr(self, "_special_" + entry, None)
                 allowed = handler(name, dowhat, rightsdict)
             elif entry in groups:
                 this_group = groups[entry]
@@ -253,12 +255,13 @@
                         if special in this_group:
                             handler = getattr(self, "_special_" + special, None)
                             allowed = handler(name, dowhat, rightsdict)
-                            break # order of self.special_users is important
-            elif entry == name:  # XXX TODO maybe change this to "entry in names" to check users with multiple names in one go
+                            break  # order of self.special_users is important
+            elif entry == name:  # XXX TODO maybe change this to "entry in names"
+                                 # to check users with multiple names in one go
                 allowed = rightsdict.get(dowhat)
             if allowed is not None:
                 return allowed
-        return allowed # should be None
+        return allowed  # should be None
 
     def _special_All(self, name, dowhat, rightsdict):
         return rightsdict.get(dowhat)
@@ -268,7 +271,7 @@
             that means that there is a valid user account present.
             works for subscription emails.
         """
-        if user.search_users(name_exact=name): # is a user with this name known?
+        if user.search_users(**{NAME_EXACT: name}):  # is a user with this name known?
             return rightsdict.get(dowhat)
         return None
 
@@ -285,9 +288,6 @@
     def __eq__(self, other):
         return self.acl_lines == other.acl_lines
 
-    def __ne__(self, other):
-        return self.acl_lines != other.acl_lines
-
 
 class ACLStringIterator(object):
     """ Iterator for acl string
--- a/MoinMoin/security/_tests/test_security.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/_tests/test_security.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,7 +15,7 @@
 from MoinMoin.security import AccessControlList, ACLStringIterator
 
 from MoinMoin.user import User
-from MoinMoin.config import NAME, ACL
+from MoinMoin.constants.keys import NAME, ACL
 from MoinMoin.datastruct import ConfigGroups
 
 from MoinMoin._tests import update_item
@@ -203,6 +203,12 @@
 
     TO DO: test unknown user?
     """
+    def testhasACL(self):
+        acl = AccessControlList(valid=app.cfg.acl_rights_contents)
+        assert not acl.has_acl()
+        acl = AccessControlList(["All:read", ], valid=app.cfg.acl_rights_contents)
+        assert acl.has_acl()
+
     def testApplyACLByUser(self):
         """ security: applying acl by user name"""
         # This acl string...
@@ -329,6 +335,7 @@
     from MoinMoin._tests import wikiconfig
     class Config(wikiconfig.Config):
         content_acl = dict(hierarchic=False, before=u"WikiAdmin:admin,read,write,create,destroy", default=u"All:read,write", after=u"All:read")
+        acl_functions = u"SuperUser:superuser NoTextchaUser:notextcha"
 
     def setup_method(self, method):
         become_trusted(username=u'WikiAdmin')
@@ -378,6 +385,14 @@
             for right in mayNot:
                 yield _not_have_right, u, right, itemname
 
+        # check function rights
+        u = User(auth_username='SuperUser')
+        assert u.may.superuser()
+        u = User(auth_username='NoTextchaUser')
+        assert u.may.notextcha()
+        u = User(auth_username='SomeGuy')
+        assert not u.may.superuser()
+        assert not u.may.notextcha()
 
 class TestItemHierachicalAcls(object):
     """ security: real-life access control list on items testing
--- a/MoinMoin/security/_tests/test_textcha.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/_tests/test_textcha.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,8 +8,6 @@
 from flask import current_app as app
 from flask import g as flaskg
 
-import pytest
-
 from MoinMoin.security.textcha import TextCha, TextChaValid, TextChaizedForm
 from MoinMoin.constants.keys import LOCALE
 
--- a/MoinMoin/security/_tests/test_ticket.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/_tests/test_ticket.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import py
-
 from MoinMoin.security.ticket import createTicket, checkTicket
 
 
--- a/MoinMoin/security/textcha.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/textcha.py	Sat Feb 16 23:21:46 2013 +0100
@@ -41,8 +41,9 @@
 
 from MoinMoin.i18n import _, L_, N_
 
-SHA1_LEN = 40 # length of hexdigest
-TIMESTAMP_LEN = 10 # length of timestamp
+SHA1_LEN = 40  # length of hexdigest
+TIMESTAMP_LEN = 10  # length of timestamp
+
 
 class TextCha(object):
     """ Text CAPTCHA support """
@@ -112,12 +113,13 @@
 
             try:
                 self.answer_regex = self.textchas[self.question]
-                self.answer_re = re.compile(self.answer_regex, re.U|re.I)
+                self.answer_re = re.compile(self.answer_regex, re.U | re.I)
             except KeyError:
                 # this question does not exist, thus there is no answer
                 self.answer_regex = ur"[Invalid question]"
                 self.answer_re = None
-                logging.warning(u"TextCha: Non-existing question '{0}' for {1}. May be invalid or user may be trying to cheat.".format(self.question, self.user_info))
+                logging.warning(u"TextCha: Non-existing question '{0}' for {1}. "
+                                u"May be invalid or user may be trying to cheat.".format(self.question, self.user_info))
             except re.error:
                 logging.error(u"TextCha: Invalid regex in answer for question '{0}'".format(self.question))
                 self.init_qa()
@@ -137,7 +139,7 @@
                     # ...
                 }
         """
-        return not not self.textchas # we don't want to return the dict
+        return not not self.textchas  # we don't want to return the dict
 
     def amend_form(self):
         """ Amend the form by doing the following:
@@ -147,11 +149,13 @@
         """
         if self.is_enabled():
             if self.question:
-                self.form['textcha_question'].set("{0} {1}{2}".format(self.question, int(self.timestamp), self.signature))
+                self.form['textcha_question'].set("{0} {1}{2}".format(
+                    self.question, int(self.timestamp), self.signature))
         else:
             self.form['textcha_question'].optional = True
             self.form['textcha'].optional = True
 
+
 class TextChaValid(Validator):
     """Validator for TextChas
     """
@@ -172,6 +176,7 @@
 
         return True
 
+
 class TextChaizedForm(Form):
     """a form providing TextCha support"""
     textcha_question = String
--- a/MoinMoin/security/ticket.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/security/ticket.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,8 @@
 
 
 import time
-import hmac, hashlib
+import hmac
+import hashlib
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
@@ -62,5 +63,6 @@
         logging.debug("checkTicket: too old ticket, timestamp {0!r}".format(timestamp))
         return False
     ourticket = createTicket(timestamp_str, **kw)
-    logging.debug("checkTicket: returning {0!r}, got {1!r}, expected {2!r}".format(ticket == ourticket, ticket, ourticket))
+    logging.debug("checkTicket: returning {0!r}, got {1!r}, expected {2!r}".format(
+        ticket == ourticket, ticket, ourticket))
     return ticket == ourticket
--- a/MoinMoin/signalling/log.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/signalling/log.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,6 +17,7 @@
     wiki_name = app.cfg.interwikiname
     logging.info(u"item {0}:{1} displayed".format(wiki_name, item_name))
 
+
 @item_modified.connect_via(ANY)
 def log_item_modified(app, item_name):
     wiki_name = app.cfg.interwikiname
--- a/MoinMoin/static/js/jfu.js	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/static/js/jfu.js	Sat Feb 16 23:21:46 2013 +0100
@@ -123,6 +123,7 @@
         };
 
         this.buildMultiDownloadRow = function (files, handler) {
+            var rows = $('<tbody style="display:none;"/>');
             $.each(files, function (index, file) {
                 rows.append(handler.buildDownloadRow(file, handler).show());
             });
--- a/MoinMoin/storage/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -50,6 +50,7 @@
     acl_mapping = sorted(acl_mapping, key=lambda x: len(x[0]), reverse=True)
     return namespace_mapping, dict(backend_mapping), acl_mapping
 
+
 def create_simple_mapping(uri='stores:fs:instance',
                           content_acl=None, user_profile_acl=None):
     """
--- a/MoinMoin/storage/backends/_tests/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/backends/_tests/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,7 +12,7 @@
 
 import pytest
 
-from MoinMoin.config import SIZE, HASH_ALGORITHM
+from MoinMoin.constants.keys import SIZE, HASH_ALGORITHM
 
 class BackendTestBase(object):
     def setup_method(self, method):
--- a/MoinMoin/storage/backends/_tests/test_fileserver.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/backends/_tests/test_fileserver.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,9 +11,7 @@
 import os
 import tempfile
 
-import pytest
-
-from MoinMoin.config import NAME, MTIME, REVID, ITEMID, HASH_ALGORITHM
+from MoinMoin.constants.keys import NAME, MTIME, REVID, ITEMID, HASH_ALGORITHM
 from ..fileserver import Backend
 from . import BackendTestBase
 
--- a/MoinMoin/storage/backends/_tests/test_stores.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/backends/_tests/test_stores.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,8 +11,6 @@
 
 from __future__ import absolute_import, division
 
-import pytest
-
 from ..stores import MutableBackend
 from . import MutableBackendTestBase
 
--- a/MoinMoin/storage/backends/fileserver.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/backends/fileserver.py	Sat Feb 16 23:21:46 2013 +0100
@@ -22,7 +22,7 @@
 from StringIO import StringIO
 from werkzeug import url_quote, url_unquote
 
-from MoinMoin.config import NAME, ITEMID, REVID, MTIME, SIZE, CONTENTTYPE, HASH_ALGORITHM
+from MoinMoin.constants.keys import NAME, ITEMID, REVID, MTIME, SIZE, CONTENTTYPE, HASH_ALGORITHM
 from . import BackendBase
 
 from MoinMoin.util.mimetype import MimeType
@@ -76,7 +76,7 @@
         st = os.stat(path)
         root = self.path
         assert path.startswith(root)
-        relpath = path[len(root)+1:]
+        relpath = path[len(root) + 1:]
         # we always want to give NAME_SEP-separated names (not backslash):
         if os.sep == NAME_SEP:
             itemname = relpath
@@ -104,10 +104,10 @@
             raise
         meta = {}
         meta[NAME] = itemname
-        meta[MTIME] = int(st.st_mtime) # use int, not float
+        meta[MTIME] = int(st.st_mtime)  # use int, not float
         meta[REVID] = unicode(self._encode('%s.%d' % (meta[NAME], meta[MTIME])))
         meta[ITEMID] = meta[REVID]
-        meta[HASH_ALGORITHM] = u'' # XXX crap, but sendfile needs it for etag
+        meta[HASH_ALGORITHM] = u''  # XXX crap, but sendfile needs it for etag
         if stat.S_ISDIR(st.st_mode):
             # directory
             # we create a virtual wiki page listing links to subitems:
@@ -116,7 +116,7 @@
         elif stat.S_ISREG(st.st_mode):
             # normal file
             ct = unicode(MimeType(filename=itemname).content_type())
-            size = int(st.st_size) # use int instead of long
+            size = int(st.st_size)  # use int instead of long
         else:
             # symlink, device file, etc.
             ct = u'application/octet-stream'
@@ -169,7 +169,7 @@
         # update() method can efficiently update the index).
         for dirpath, dirnames, filenames in os.walk(self.path):
             key, mtime = self._mkkey(dirpath)
-            if 1: # key:
+            if 1:  # key:
                 yield self._encode('%s.%d' % (key, mtime))
             for filename in filenames:
                 yield self._encode('%s.%d' % self._mkkey(os.path.join(dirpath, filename)))
--- a/MoinMoin/storage/backends/stores.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/backends/stores.py	Sat Feb 16 23:21:46 2013 +0100
@@ -23,7 +23,7 @@
 
 import json
 
-from MoinMoin.config import REVID, DATAID, SIZE, HASH_ALGORITHM
+from MoinMoin.constants.keys import REVID, DATAID, SIZE, HASH_ALGORITHM
 from MoinMoin.util.crypto import make_uuid
 
 from . import BackendBase, MutableBackendBase
@@ -136,12 +136,14 @@
             size_expected = meta.get(SIZE)
             size_real = tfw.size
             if size_expected is not None and size_expected != size_real:
-                raise ValueError("computed data size ({0}) does not match data size declared in metadata ({1})".format(size_real, size_expected))
+                raise ValueError("computed data size ({0}) does not match data size declared in metadata ({1})".format(
+                                 size_real, size_expected))
             meta[SIZE] = size_real
             hash_expected = meta.get(HASH_ALGORITHM)
             hash_real = tfw.hash.hexdigest()
             if hash_expected is not None and hash_expected != hash_real:
-                raise ValueError("computed data hash ({0}) does not match data hash declared in metadata ({1})".format(hash_real, hash_expected))
+                raise ValueError("computed data hash ({0}) does not match data hash declared in metadata ({1})".format(
+                                 hash_real, hash_expected))
             meta[HASH_ALGORITHM] = hash_real
         else:
             dataid = meta[DATAID]
@@ -153,7 +155,7 @@
                 # if we do not store if we already have the dataid in the store,
                 # deserialization does not work as the fpos does not advance to the next record,
                 # because we do not read from the source file. Remove the check?
-                while data.read(64*1024):
+                while data.read(64 * 1024):
                     pass
 
         # if something goes wrong below, the data shall be purged by a garbage collection
--- a/MoinMoin/storage/error.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/error.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,26 +16,31 @@
     General class for exceptions on the storage layer.
     """
 
+
 class BackendError(StorageError):
     """
     Raised if the backend couldn't commit the action.
     """
 
+
 class NoSuchItemError(BackendError):
     """
     Raised if the requested item does not exist.
     """
 
+
 class ItemAlreadyExistsError(BackendError):
     """
     Raised if the Item you are trying to create already exists.
     """
 
+
 class NoSuchRevisionError(BackendError):
     """
     Raised if the requested revision of an item does not exist.
     """
 
+
 class RevisionAlreadyExistsError(BackendError):
     """
     Raised if the Revision you are trying to create already exists.
--- a/MoinMoin/storage/middleware/_tests/test_indexing.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_indexing.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,17 +15,11 @@
 
 from flask import g as flaskg
 
-from MoinMoin.config import NAME, SIZE, ITEMID, REVID, DATAID, HASH_ALGORITHM, CONTENT, COMMENT, \
-                            LATEST_REVS, ALL_REVS, NAMESPACE
-
-from ..indexing import IndexingMiddleware
+from MoinMoin.constants.keys import (NAME, SIZE, ITEMID, REVID, DATAID, HASH_ALGORITHM, CONTENT, COMMENT,
+                                     LATEST_REVS, ALL_REVS, NAMESPACE)
 
 from MoinMoin.auth import GivenAuth
 from MoinMoin._tests import wikiconfig
-from MoinMoin.storage.backends.stores import MutableBackend
-from MoinMoin.storage.stores.memory import BytesStore as MemoryBytesStore
-from MoinMoin.storage.stores.memory import FileStore as MemoryFileStore
-from MoinMoin.storage import create_simple_mapping
 
 
 def dumper(indexer, idx_name):
--- a/MoinMoin/storage/middleware/_tests/test_protecting.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_protecting.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,8 +12,6 @@
 
 import pytest
 
-from MoinMoin.config import ACL
-
 from ..protecting import ProtectingMiddleware, AccessDenied
 
 from .test_indexing import TestIndexingMiddleware
--- a/MoinMoin/storage/middleware/_tests/test_routing.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_routing.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,7 +12,7 @@
 
 import pytest
 
-from MoinMoin.config import NAME, NAMESPACE, REVID
+from MoinMoin.constants.keys import NAME, NAMESPACE
 
 from ..routing import Backend as RoutingBackend
 
--- a/MoinMoin/storage/middleware/_tests/test_serialization.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_serialization.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,16 +14,18 @@
 from ..routing import Backend as RoutingBackend
 from ..serialization import serialize, deserialize
 
+from MoinMoin.constants.keys import NAME, CONTENTTYPE
+
 from MoinMoin.storage.backends.stores import MutableBackend
 from MoinMoin.storage.stores.memory import BytesStore, FileStore
 
 
 contents = [
-    (u'Foo', {'name': [u'Foo', ], 'contenttype': u'text/plain'}, ''),
-    (u'Foo', {'name': [u'Foo', ], 'contenttype': u'text/plain'}, '2nd'),
-    (u'Subdir', {'name': [u'Subdir', ], 'contenttype': u'text/plain'}, ''),
-    (u'Subdir/Foo', {'name': [u'Subdir/Foo', ], 'contenttype': u'text/plain'}, ''),
-    (u'Subdir/Bar', {'name': [u'Subdir/Bar', ], 'contenttype': u'text/plain'}, ''),
+    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain'}, ''),
+    (u'Foo', {NAME: [u'Foo', ], CONTENTTYPE: u'text/plain'}, '2nd'),
+    (u'Subdir', {NAME: [u'Subdir', ], CONTENTTYPE: u'text/plain'}, ''),
+    (u'Subdir/Foo', {NAME: [u'Subdir/Foo', ], CONTENTTYPE: u'text/plain'}, ''),
+    (u'Subdir/Bar', {NAME: [u'Subdir/Bar', ], CONTENTTYPE: u'text/plain'}, ''),
 ]
 
 
@@ -71,7 +73,7 @@
 def test_serialize_deserialize(source, target):
     i = 0
     for name, meta, data in contents:
-        item = source[u'name']
+        item = source[name]
         item.store_revision(dict(meta, mtime=i), StringIO(data))
         i += 1
 
--- a/MoinMoin/storage/middleware/_tests/test_validation.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/_tests/test_validation.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,12 +8,10 @@
 
 from __future__ import absolute_import, division
 
-import pytest
-
 from MoinMoin.storage.middleware.validation import ContentMetaSchema, UserMetaSchema
 
 from MoinMoin.constants import keys
-from MoinMoin.config import CONTENTTYPE_USER
+from MoinMoin.constants.contenttypes import CONTENTTYPE_USER
 
 from MoinMoin.util.crypto import make_uuid
 
--- a/MoinMoin/storage/middleware/indexing.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/indexing.py	Sat Feb 16 23:21:46 2013 +0100
@@ -53,8 +53,6 @@
 
 import os
 import shutil
-import itertools
-import time
 import datetime
 
 from MoinMoin import log
@@ -75,13 +73,11 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin.config import WIKINAME, NAMESPACE, NAME, NAME_EXACT, MTIME, CONTENTTYPE, TAGS, \
-                            LANGUAGE, USERID, ADDRESS, HOSTNAME, SIZE, ACTION, COMMENT, SUMMARY, \
-                            CONTENT, EXTERNALLINKS, ITEMLINKS, ITEMTRANSCLUSIONS, ACL, EMAIL, OPENID, \
-                            ITEMID, REVID, CURRENT, PARENTID, \
-                            PTIME, \
-                            LATEST_REVS, ALL_REVS, BACKENDNAME, \
-                            CONTENTTYPE_USER
+from MoinMoin.constants.keys import (WIKINAME, NAMESPACE, NAME, NAME_EXACT, MTIME, CONTENTTYPE, TAGS, LANGUAGE,
+                                     USERID, ADDRESS, HOSTNAME, SIZE, ACTION, COMMENT, SUMMARY, CONTENT,
+                                     EXTERNALLINKS, ITEMLINKS, ITEMTRANSCLUSIONS, ACL, EMAIL, OPENID,
+                                     ITEMID, REVID, CURRENT, PARENTID, PTIME, LATEST_REVS, ALL_REVS, BACKENDNAME)
+from MoinMoin.constants.contenttypes import CONTENTTYPE_USER
 from MoinMoin.constants import keys
 from MoinMoin.constants.keys import ITEMTYPE
 
@@ -158,6 +154,7 @@
 from MoinMoin.converter import default_registry
 from MoinMoin.util.iri import Iri
 
+
 def convert_to_indexable(meta, data, item_name=None, is_new=False):
     """
     Convert revision data to a indexable content.
@@ -177,14 +174,18 @@
             self.meta = meta
             self.data = data
             self.revid = meta.get(REVID)
+
             class PseudoItem(object):
                 def __init__(self, name):
                     self.name = name
             self.item = PseudoItem(item_name)
+
         def read(self, *args, **kw):
             return self.data.read(*args, **kw)
+
         def seek(self, *args, **kw):
             return self.data.seek(*args, **kw)
+
         def tell(self, *args, **kw):
             return self.data.tell(*args, **kw)
 
@@ -232,8 +233,9 @@
             return doc
         # no way
         raise TypeError("No converter for {0} --> {1}".format(input_contenttype, output_contenttype))
-    except Exception as e: # catch all exceptions, we don't want to break an indexing run
-        logging.exception("Exception happened in conversion of item {0!r} rev {1} contenttype {2}:".format(item_name, meta.get(REVID, 'new'), meta.get(CONTENTTYPE, '')))
+    except Exception as e:  # catch all exceptions, we don't want to break an indexing run
+        logging.exception("Exception happened in conversion of item {0!r} rev {1} contenttype {2}:".format(
+                          item_name, meta.get(REVID, 'new'), meta.get(CONTENTTYPE, '')))
         doc = u'ERROR [{0!s}]'.format(e)
         return doc
 
@@ -440,7 +442,7 @@
             index_dir, index_dir_tmp = params[0], params_tmp[0]
             os.rename(index_dir_tmp, index_dir)
 
-    def index_revision(self, meta, content, backend_name, async=False): # True
+    def index_revision(self, meta, content, backend_name, async=False):  # True
         """
         Index a single revision, add it to all-revs and latest-revs index.
 
@@ -454,7 +456,7 @@
         else:
             writer = self.ix[ALL_REVS].writer()
         with writer as writer:
-            writer.update_document(**doc) # update, because store_revision() may give us an existing revid
+            writer.update_document(**doc)  # update, because store_revision() may give us an existing revid
         doc = backend_to_index(meta, content, self.schemas[LATEST_REVS], self.wikiname, backend_name)
         if async:
             writer = AsyncWriter(self.ix[LATEST_REVS])
@@ -488,7 +490,7 @@
                 latest_backends_revids = self._find_latest_backends_revids(self.ix[ALL_REVS], Term(ITEMID, itemid))
                 if latest_backends_revids:
                     # we have a latest revision, just update the document in the index:
-                    assert len(latest_backends_revids) == 1 # this item must have only one latest revision
+                    assert len(latest_backends_revids) == 1  # this item must have only one latest revision
                     latest_backend_revid = latest_backends_revids[0]
                     # we must fetch from backend because schema for LATEST_REVS is different than for ALL_REVS
                     # (and we can't be sure we have all fields stored, too)
@@ -498,7 +500,8 @@
                     with self.ix[ALL_REVS].searcher() as searcher:
                         doc = searcher.document(revid=latest_backend_revid[1])
                         content = doc[CONTENT]
-                    doc = backend_to_index(meta, content, self.schemas[LATEST_REVS], self.wikiname, backend_name=latest_backend_revid[0])
+                    doc = backend_to_index(meta, content, self.schemas[LATEST_REVS], self.wikiname,
+                                           backend_name=latest_backend_revid[0])
                     writer.update_document(**doc)
                 else:
                     # this is no revision left in this item that could be the new "latest rev", just kill the rev
@@ -558,7 +561,7 @@
         index = storage.open_index(ALL_REVS)
         try:
             # build an index of all we have (so we know what we have)
-            all_revids = self.backend # the backend is an iterator over all revids
+            all_revids = self.backend  # the backend is an iterator over all revids
             self._modify_index(index, self.schemas[ALL_REVS], self.wikiname, all_revids, 'add', procs, limitmb)
             latest_backends_revids = self._find_latest_backends_revids(index)
         finally:
@@ -566,7 +569,8 @@
         # now build the index of the latest revisions:
         index = storage.open_index(LATEST_REVS)
         try:
-            self._modify_index(index, self.schemas[LATEST_REVS], self.wikiname, latest_backends_revids, 'add', procs, limitmb)
+            self._modify_index(index, self.schemas[LATEST_REVS], self.wikiname, latest_backends_revids, 'add',
+                               procs, limitmb)
         finally:
             index.close()
 
@@ -593,7 +597,7 @@
             backend_revids = set(revids_backends)
             with index_all.searcher() as searcher:
                 ix_revids_backends = dict((doc[REVID], doc[BACKENDNAME]) for doc in searcher.all_stored_fields())
-            revids_backends.update(ix_revids_backends) # this is needed for stuff that was deleted from storage
+            revids_backends.update(ix_revids_backends)  # this is needed for stuff that was deleted from storage
             ix_revids = set(ix_revids_backends)
             add_revids = backend_revids - ix_revids
             del_revids = ix_revids - backend_revids
@@ -671,6 +675,7 @@
         else:
             raise ValueError("default_fields list must at least contain one field name")
         qp.add_plugin(RegexPlugin())
+
         def userid_pseudo_field_factory(fieldname):
             """generate a translator function, that searches for the userid
                in the given fieldname when provided with the username
@@ -689,7 +694,7 @@
             # username:JoeDoe searches for revisions modified by JoeDoe
             username=userid_pseudo_field_factory(keys.USERID),
             # assigned:JoeDoe searches for tickets assigned to JoeDoe
-            assigned=userid_pseudo_field_factory('assigned_to'), # XXX should be keys.ASSIGNED_TO
+            assigned=userid_pseudo_field_factory('assigned_to'),  # XXX should be keys.ASSIGNED_TO
         )))
         return qp
 
@@ -765,7 +770,7 @@
         """
         Return item with <name> (may be a new or existing item).
         """
-        return Item(self, name_exact=name)
+        return Item(self, **{NAME_EXACT: name})
 
     def get_item(self, **query):
         """
@@ -808,7 +813,7 @@
         """
         self.indexer = indexer
         self.backend = self.indexer.backend
-        self._name = query.get('name_exact')
+        self._name = query.get(NAME_EXACT)
         if latest_doc is None:
             # we need to call the method without acl check to avoid endless recursion:
             latest_doc = self.indexer._document(**query)
@@ -826,6 +831,7 @@
 
     def _get_itemid(self):
         return self._current.get(ITEMID)
+
     def _set_itemid(self, value):
         self._current[ITEMID] = value
     itemid = property(_get_itemid, _set_itemid)
@@ -873,7 +879,7 @@
         """
         parent_ids = set()
         for parent_name in self.parentnames:
-            rev = self.indexer._document(idx_name=LATEST_REVS, name_exact=parent_name)
+            rev = self.indexer._document(idx_name=LATEST_REVS, **{NAME_EXACT: parent_name})
             if rev:
                 parent_ids.add(rev[ITEMID])
         return parent_ids
@@ -986,8 +992,8 @@
         return meta, data, content
 
     def store_revision(self, meta, data, overwrite=False,
-                       trusted=False, # True for loading a serialized representation or other trusted sources
-                       name=None, # TODO name we decoded from URL path
+                       trusted=False,  # True for loading a serialized representation or other trusted sources
+                       name=None,  # TODO name we decoded from URL path
                        action=u'SAVE',
                        remote_addr=None,
                        userid=None,
@@ -1031,7 +1037,7 @@
                  keys.USERID: userid,
                  keys.WIKINAME: wikiname,
                  keys.NAMESPACE: None,
-                 keys.ITEMID: self.itemid, # real itemid or None
+                 keys.ITEMID: self.itemid,  # real itemid or None
                  'contenttype_current': contenttype_current,
                  'contenttype_guessed': contenttype_guessed,
                  'acl_parent': acl_parent,
@@ -1055,7 +1061,8 @@
         # just update the meta dict with the validated stuff:
         meta.update(dict(m.value.items()))
         # we do not want None / empty values:
-        meta = dict([(k, v) for k, v in meta.items() if v not in [None, ]]) # XXX do not kick out empty lists before fixing NAME processing
+        # XXX do not kick out empty lists before fixing NAME processing:
+        meta = dict([(k, v) for k, v in meta.items() if v not in [None, ]])
 
         if self.itemid is None:
             self.itemid = meta[ITEMID]
@@ -1151,7 +1158,7 @@
                 return
 
     def _load(self):
-        meta, data = self.backend.retrieve(self.backend_name, self.revid) # raises KeyError if rev does not exist
+        meta, data = self.backend.retrieve(self.backend_name, self.revid)  # raises KeyError if rev does not exist
         self.meta = Meta(self, self._doc, meta)
         self._data = data
         return meta, data
@@ -1178,6 +1185,7 @@
 
 from collections import Mapping
 
+
 class Meta(Mapping):
     def __init__(self, revision, doc, meta=None):
         self.revision = revision
@@ -1219,7 +1227,7 @@
         return cmp(self[MTIME], other[MTIME])
 
     def __len__(self):
-        return 0 # XXX
+        return 0  # XXX
 
     def __repr__(self):
         return "Meta _doc: {0!r} _meta: {1!r}".format(self._doc, self._meta)
--- a/MoinMoin/storage/middleware/protecting.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/protecting.py	Sat Feb 16 23:21:46 2013 +0100
@@ -21,9 +21,9 @@
 
 from whoosh.util import lru_cache
 
-from MoinMoin.config import ACL, CREATE, READ, PUBREAD, WRITE, DESTROY, ADMIN, \
-                            PTIME, ACL_RIGHTS_CONTENTS, \
-                            ALL_REVS, LATEST_REVS
+from MoinMoin.constants.rights import (CREATE, READ, PUBREAD, WRITE, DESTROY, ACL_RIGHTS_CONTENTS)
+from MoinMoin.constants.keys import ALL_REVS, LATEST_REVS, NAME_EXACT, ITEMID
+
 from MoinMoin.security import AccessControlList
 
 # max sizes of some lru caches:
@@ -55,7 +55,7 @@
     def __init__(self, indexer, user, acl_mapping):
         """
         :param indexer: indexing middleware instance
-        :param user_name: the user's name (used for checking permissions)
+        :param user: a User instance (used for checking permissions)
         :param acl_mapping: list of (name_prefix, acls) tuples, longest prefix first, '' last
                             acls = dict with before, default, after, hierarchic entries
         """
@@ -105,13 +105,14 @@
         """
 
         if itemid is not None:
-            item = self.get_item(itemid=itemid)
+            q = {ITEMID: itemid}
         elif fqname is not None:
             # itemid might be None for new, not yet stored items,
             # but we have fqname then
-            item = self.get_item(name_exact=fqname)
+            q = {NAME_EXACT: fqname}
         else:
             raise ValueError("need itemid or fqname")
+        item = self.get_item(**q)
         acl = item.acl
         fqname = item.fqname
         if acl is not None:
--- a/MoinMoin/storage/middleware/routing.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/routing.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,7 @@
 
 from __future__ import absolute_import, division
 
-from MoinMoin.config import NAME, BACKENDNAME, NAMESPACE
+from MoinMoin.constants.keys import NAME, BACKENDNAME, NAMESPACE
 
 from MoinMoin.storage.backends import BackendBase, MutableBackendBase
 
@@ -45,7 +45,7 @@
         }
 
         :type namespaces: list of tuples of namespace specifier -> backend names
-        :param mapping: [(namespace, backend_name), ...]
+        :param namespaces: [(namespace, backend_name), ...]
         :type backends: dict backend names -> backends
         :param backends: {backend_name: backend, ...}
         """
@@ -66,7 +66,7 @@
         find the backend it belongs to, the itemname without namespace
         spec and the namespace of the backend.
 
-        :param fq_name: fully-qualified itemnames
+        :param fq_names: fully-qualified itemnames
         :returns: tuple of (backend name, local item name, namespace)
         """
         fq_name = fq_names[0]
@@ -74,13 +74,13 @@
             if fq_name.startswith(namespace):
                 item_names = [fq_name[len(namespace):] for fq_name in fq_names]
                 return backend_name, item_names, namespace.rstrip(':')
-        raise AssertionError("No backend found for {0!r}. Namespaces: {1!r}".format(itemname, self.namespaces))
+        raise AssertionError("No backend found for {0!r}. Namespaces: {1!r}".format(fq_name, self.namespaces))
 
     def __iter__(self):
         # Note: yields enough information so we can retrieve the revision from
         #       the right backend later (this is more than just the revid).
         for backend_name, backend in self.backends.items():
-            for revid in backend: # TODO maybe directly yield the backend?
+            for revid in backend:  # TODO maybe directly yield the backend?
                 yield (backend_name, revid)
 
     def retrieve(self, backend_name, revid):
@@ -115,7 +115,7 @@
                 raise ValueError('can not determine namespace: empty NAME list, no NAMESPACE metadata present')
         else:
             if namespace:
-                namespace += u':' # needed for _get_backend
+                namespace += u':'  # needed for _get_backend
             backend_name, _, _ = self._get_backend([namespace])
         backend = self.backends[backend_name]
 
--- a/MoinMoin/storage/middleware/serialization.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/serialization.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,7 +9,7 @@
 
 4 bytes length of meta (m)
 m bytes metadata (json serialization, utf-8 encoded)
-        (the metadata contains the data length d in meta['size'])
+        (the metadata contains the data length d in meta[SIZE])
 d bytes binary data
 ... (repeat for all meta/data)
 4 bytes 00 (== length of next meta -> there is none, this is the end)
@@ -24,6 +24,9 @@
 
 from werkzeug.wsgi import LimitedStream
 
+from MoinMoin.constants.keys import NAME, ITEMTYPE, SIZE
+from MoinMoin.constants.itemtypes import ITEMTYPE_DEFAULT
+
 
 def serialize(backend, dst):
     dst.writelines(serialize_iter(backend))
@@ -44,6 +47,7 @@
                 break
             yield block
 
+
 def serialize_iter(backend):
     for revid in backend:
         if isinstance(revid, tuple):
@@ -57,6 +61,7 @@
     for data in serialize_rev(None, None):
         yield data
 
+
 def deserialize(src, backend):
     while True:
         meta_size_bytes = src.read(4)
@@ -66,14 +71,14 @@
         meta_str = src.read(meta_size)
         text = meta_str.decode('utf-8')
         meta = json.loads(text)
-        name = meta.get('name')
+        name = meta.get(NAME)
         if isinstance(name, unicode):
             # if we encounter single names, make a list of names:
-            meta['name'] = [name, ]
-        if 'itemtype' not in meta:
+            meta[NAME] = [name, ]
+        if ITEMTYPE not in meta:
             # temporary hack to upgrade serialized item files:
-            meta['itemtype'] = u'default'
-        data_size = meta[u'size']
+            meta[ITEMTYPE] = ITEMTYPE_DEFAULT
+        data_size = meta[SIZE]
         curr_pos = src.tell()
         limited = LimitedStream(src, data_size)
         backend.store(meta, limited)
--- a/MoinMoin/storage/middleware/validation.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/middleware/validation.py	Sat Feb 16 23:21:46 2013 +0100
@@ -29,7 +29,7 @@
 from flatland import Dict, List, Unset, Boolean, Integer, String
 
 from MoinMoin.constants import keys
-from MoinMoin.config import CONTENTTYPE_DEFAULT, CONTENTTYPE_USER
+from MoinMoin.constants.contenttypes import CONTENTTYPE_DEFAULT, CONTENTTYPE_USER
 
 from MoinMoin.util.crypto import make_uuid, UUID_LEN
 from MoinMoin.util.mime import Type
@@ -102,7 +102,7 @@
         return False
     if v != v.strip():
         return False
-    if v.startswith(u'+'): # used for views, like /+meta/<itemname>
+    if v.startswith(u'+'):  # used for views, like /+meta/<itemname>
         return False
     if v.endswith(u'/'):
         return False
@@ -225,7 +225,7 @@
         if element.value is None:
             return False
         return True
-    else: # untrusted
+    else:  # untrusted
         v = element.value
         if not isinstance(v, unicode):
             return False
@@ -338,32 +338,33 @@
     String.named(keys.DATAID).validated_by(uuid_validator).using(optional=True),
     # markup items may have this:
     List.named(keys.ITEMLINKS).of(String.named('itemlink').validated_by(wikiname_validator)).using(optional=True),
-    List.named(keys.ITEMTRANSCLUSIONS).of(String.named('itemtransclusion').validated_by(wikiname_validator)).using(optional=True),
+    List.named(keys.ITEMTRANSCLUSIONS).of(String.named('itemtransclusion').validated_by(wikiname_validator)).using(
+        optional=True),
     # TODO: CONTENT validation? can we do it here?
     *common_meta
 )
 
 UserMetaSchema = DuckDict.named('UserMetaSchema').of(
     String.named(keys.CONTENTTYPE).validated_by(user_contenttype_validator),
-    String.named('email').using(optional=True),
-    String.named('openid').using(optional=True),
-    String.named('enc_password').using(optional=True),
-    String.named('recoverpass_key').using(optional=True),
-    String.named('theme_name').using(optional=True),
-    String.named('timezone').using(optional=True),
-    String.named('locale').using(optional=True),
-    String.named('css_url').using(optional=True),
-    Integer.named('results_per_page').using(optional=True),
-    Integer.named('edit_rows').using(optional=True),
-    Boolean.named('disabled').using(optional=True),
-    Boolean.named('want_trivial').using(optional=True),
-    Boolean.named('show_comments').using(optional=True),
-    Boolean.named('edit_on_doubleclick').using(optional=True),
-    Boolean.named('scroll_page_after_edit').using(optional=True),
-    Boolean.named('mailto_author').using(optional=True),
-    List.named('quicklinks').of(String.named('quicklinks')).using(optional=True),
-    List.named('subscribed_items').of(String.named('subscribed_item')).using(optional=True),
-    List.named('email_subscribed_events').of(String.named('email_subscribed_event')).using(optional=True),
+    String.named(keys.EMAIL).using(optional=True),
+    String.named(keys.OPENID).using(optional=True),
+    String.named(keys.ENC_PASSWORD).using(optional=True),
+    String.named(keys.RECOVERPASS_KEY).using(optional=True),
+    String.named(keys.THEME_NAME).using(optional=True),
+    String.named(keys.TIMEZONE).using(optional=True),
+    String.named(keys.LOCALE).using(optional=True),
+    String.named(keys.CSS_URL).using(optional=True),
+    Integer.named(keys.RESULTS_PER_PAGE).using(optional=True),
+    Integer.named(keys.EDIT_ROWS).using(optional=True),
+    Boolean.named(keys.DISABLED).using(optional=True),
+    Boolean.named(keys.WANT_TRIVIAL).using(optional=True),
+    Boolean.named(keys.SHOW_COMMENTS).using(optional=True),
+    Boolean.named(keys.EDIT_ON_DOUBLECLICK).using(optional=True),
+    Boolean.named(keys.SCROLL_PAGE_AFTER_EDIT).using(optional=True),
+    Boolean.named(keys.MAILTO_AUTHOR).using(optional=True),
+    List.named(keys.QUICKLINKS).of(String.named('quicklinks')).using(optional=True),
+    List.named(keys.SUBSCRIBED_ITEMS).of(String.named('subscribed_item')).using(optional=True),
+    List.named(keys.EMAIL_SUBSCRIBED_EVENTS).of(String.named('email_subscribed_event')).using(optional=True),
     #TODO: DuckDict.named('bookmarks').using(optional=True),
     *common_meta
 )
--- a/MoinMoin/storage/stores/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -18,6 +18,7 @@
 
 from MoinMoin.util.StringIOClosing import StringIO
 
+
 class StoreBase(Mapping):
     """
     A simple read-only key/value store.
@@ -142,6 +143,7 @@
               file pointer position after we return.
         """
 
+
 class FileMutableStoreMixin(object):
     """
     mix this into a BytesMutableStore to get a FileMutableStore, like shown here:
--- a/MoinMoin/storage/stores/kc.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/kc.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,7 +17,8 @@
 
 from __future__ import absolute_import, division
 
-import os, errno
+import os
+import errno
 
 from kyotocabinet import *
 
@@ -33,7 +34,7 @@
     def from_uri(cls, uri):
         return cls(uri)
 
-    def __init__(self, path, mode=DB.OWRITER|DB.OAUTOTRAN, db_opts=DB.GCONCURRENT):
+    def __init__(self, path, mode=DB.OWRITER | DB.OAUTOTRAN, db_opts=DB.GCONCURRENT):
         """
         Store params for .open(). Please refer to kyotocabinet-python-legacy docs for more information.
 
@@ -56,7 +57,7 @@
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
-        self.open(mode=self.mode|DB.OCREATE)
+        self.open(mode=self.mode | DB.OCREATE)
         self.close()
 
     def destroy(self):
--- a/MoinMoin/storage/stores/kt.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/kt.py	Sat Feb 16 23:21:46 2013 +0100
@@ -142,7 +142,7 @@
         response = self.client.getresponse()
         if response.status != 200:
             return None
-        return response # XXX can we do that?
+        return response  # XXX can we do that?
 
     def set(self, key, value, xt=None):
         if isinstance(key, unicode):
@@ -152,7 +152,7 @@
         if xt is not None:
             xt = int(time.time()) + xt
             headers["X-Kt-Xt"] = str(xt)
-        value = value.read() # XXX reads value file into memory
+        value = value.read()  # XXX reads value file into memory
         self.client.request("PUT", key, value, headers)
         response = self.client.getresponse()
         body = response.read()
--- a/MoinMoin/storage/stores/mongodb.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/mongodb.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,8 @@
 
 from __future__ import absolute_import, division
 
-import pymongo, gridfs
+import pymongo
+import gridfs
 
 from . import MutableStoreBase, BytesMutableStoreBase, FileMutableStoreBase
 
@@ -21,7 +22,7 @@
     """
     @classmethod
     def from_uri(cls, uri):
-        params = uri.split('::') # moin_uri -> mongodb_uri::collection_name
+        params = uri.split('::')  # moin_uri -> mongodb_uri::collection_name
         return cls(*params)
 
     def __init__(self, uri='mongodb://127.0.0.1/moin_db', collection_name='moin_coll'):
--- a/MoinMoin/storage/stores/sqla.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/sqla.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,7 +17,7 @@
                BytesMutableStoreMixin, FileMutableStoreMixin)
 
 KEY_LEN = 128
-VALUE_LEN = 1024 * 1024 # 1MB binary data
+VALUE_LEN = 1024 * 1024  # 1MB binary data
 
 
 class BytesStore(BytesMutableStoreBase):
@@ -32,8 +32,8 @@
         :param cls: Class to create
         :param uri: The database uri that we pass on to SQLAlchemy.
         """
-        params = uri.split("::") # using "::" to support windows pathnames that
-                                 # may include ":" after the drive letter.
+        params = uri.split("::")  # using "::" to support windows pathnames that
+                                  # may include ":" after the drive letter.
         return cls(*params)
 
     def __init__(self, db_uri=None, table_name='store', verbose=False):
--- a/MoinMoin/storage/stores/sqlite.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/storage/stores/sqlite.py	Sat Feb 16 23:21:46 2013 +0100
@@ -35,8 +35,8 @@
                     db_name::table_name::compression_level
                     where table_name and compression level are optional
         """
-        params = uri.split("::") # using "::" to support windows pathnames that
-                                 # may include ":" after the drive letter.
+        params = uri.split("::")  # using "::" to support windows pathnames that
+                                  # may include ":" after the drive letter.
         if len(params) == 3:
             params[2] = int(params[2])
         return cls(*params)
@@ -69,7 +69,7 @@
 
     def open(self):
         self.conn = connect(self.db_name)
-        self.conn.row_factory = Row # make column access by ['colname'] possible
+        self.conn.row_factory = Row  # make column access by ['colname'] possible
 
     def close(self):
         pass
--- a/MoinMoin/templates/blog/utils.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/blog/utils.html	Sat Feb 16 23:21:46 2013 +0100
@@ -61,7 +61,7 @@
     {{ gen.form.open(form, id='moin-searchform', method='get', action=url_for('frontend.search')) }}
         <div>
             {{ forms.render(form['q']) }}
-            {{ gen.button(form['submit'], type='submit', id='moin-search-submit') }}
+            {{ forms.render_submit(form, id='moin-search-submit') }}
             {{ forms.render_errors(form) }}
             <br />
             <input type="checkbox" id="moin-blog-search-this"
--- a/MoinMoin/templates/delete.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/delete.html	Sat Feb 16 23:21:46 2013 +0100
@@ -12,7 +12,7 @@
     {{ forms.render(form['comment']) }}
     {{ forms.render_textcha(gen, form) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/destroy.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/destroy.html	Sat Feb 16 23:21:46 2013 +0100
@@ -13,7 +13,7 @@
         {{ forms.render(form['comment']) }}
         {{ forms.render_textcha(gen, form) }}
       </dl>
-      {{ forms.render(form['submit']) }}
+      {{ forms.render_submit(form) }}
     {{ gen.form.close() }}
     </div>
 {% else %}
@@ -25,7 +25,7 @@
         {{ forms.render(form['comment']) }}
         {{ forms.render_textcha(gen, form) }}
       </dl>
-      {{ forms.render(form['submit']) }}
+      {{ forms.render_submit(form) }}
     {{ gen.form.close() }}
     </div>
 {% endif %}
--- a/MoinMoin/templates/forms.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/forms.html	Sat Feb 16 23:21:46 2013 +0100
@@ -19,8 +19,8 @@
   <input type="hidden" name="{{ name }}" value="{{ value }}" />
 {% endmacro %}
 
-{% macro render_button(text) %}
-  <button type="submit">{{ text }}</button>
+{% macro render_submit(form) %}
+  {{ gen.input(type='submit', value=form.submit_label, class='button', **kwargs) }}
 {% endmacro %}
 
 {% macro render_textcha(gen, form) %}
@@ -52,9 +52,9 @@
       'small_natural': small_natural,
       'datetime': datetime,
       'search': search,
-      'submit': raw_input,
       'hidden': raw_input,
       'select': select,
+      'select_submit': select_submit,
       'multi_select': multi_select,
       'readonly_string_list': readonly_string_list,
       'readonly_item_link_list': readonly_item_link_list,
@@ -165,6 +165,13 @@
   </dd>
 {% endmacro %}
 
+{% macro select_submit(field) %}
+  {% set labels = field.properties.get('labels', {}) %}
+  {% for value in field.valid_values %}
+    {{ gen.button(field, type='submit', value=value, contents=labels.get(value, value)) }}
+  {% endfor %}
+{% endmacro %}
+
 {% macro multi_select(field) %}
   {% set valid_values = field.member_schema.valid_values %}
   {% set labels = field.member_schema.properties.get('labels', {}) %}
--- a/MoinMoin/templates/index.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/index.html	Sat Feb 16 23:21:46 2013 +0100
@@ -51,7 +51,7 @@
                 </li>
                 {{ forms.render(form['contenttype']) }}
             </ul>
-            {{ forms.render(form['submit']) }}
+            {{ forms.render_submit(form) }}
             {{ gen.form.close() }}
         </div>
         </li>
--- a/MoinMoin/templates/login.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/login.html	Sat Feb 16 23:21:46 2013 +0100
@@ -17,6 +17,7 @@
   {% endif %}
 </dl>
 {{ forms.render(form['submit']) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endif %}
 
@@ -29,6 +30,7 @@
   {{ forms.render(form['openid']) }}
 </dl>
 {{ forms.render(form['submit']) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endif %}
 
--- a/MoinMoin/templates/lookup.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/lookup.html	Sat Feb 16 23:21:46 2013 +0100
@@ -23,7 +23,7 @@
                 {{ forms.render(lookup_form[e]) }}
             {% endfor %}
         </dl>
-        {{ gen.input(lookup_form['submit'], type='submit') }}
+        {{ forms.render_submit(lookup_form) }}
     {{ gen.form.close() }}
     {% else %}
     {% if not results %}
--- a/MoinMoin/templates/lostpass.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/lostpass.html	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,7 @@
     {{ forms.render(form['username']) }}
     {{ forms.render(form['email']) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/modify.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/modify.html	Sat Feb 16 23:21:46 2013 +0100
@@ -39,11 +39,11 @@
     {{ forms.render_errors(form) }}
     {#
        Workaround:
-       For *Draw content, hide form['submit'] and form['comment'], since *Draw
+       For *Draw content, hide submit button and form['comment'], since *Draw
        POSTs originate from their respective applets.
     #}
     {% if not form['content_form'].is_draw %}
-        {{ forms.render(form['submit']) }}
+        {{ forms.render_submit(form) }}
         <dl>
             {{ forms.render_textcha(gen, form) }}
             {{ forms.render(form['comment']) }}
--- a/MoinMoin/templates/openid_register.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/openid_register.html	Sat Feb 16 23:21:46 2013 +0100
@@ -17,7 +17,7 @@
     {{ forms.render(form['email']) }}
     {{ forms.render_textcha(gen, form) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/recoverpass.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/recoverpass.html	Sat Feb 16 23:21:46 2013 +0100
@@ -11,6 +11,6 @@
     {{ forms.render(form['password1']) }}
     {{ forms.render(form['password2']) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endblock %}
--- a/MoinMoin/templates/register.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/register.html	Sat Feb 16 23:21:46 2013 +0100
@@ -14,7 +14,7 @@
     {{ forms.render(form['openid']) }}
     {{ forms.render_textcha(gen, form) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/rename.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/rename.html	Sat Feb 16 23:21:46 2013 +0100
@@ -13,7 +13,7 @@
     {{ forms.render(form['comment']) }}
     {{ forms.render_textcha(gen, form) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/revert.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/revert.html	Sat Feb 16 23:21:46 2013 +0100
@@ -9,7 +9,7 @@
     {{ forms.render(form['comment']) }}
     {{ forms.render_textcha(gen, form) }}
   </dl>
-  {{ forms.render(form['submit']) }}
+  {{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 </div>
 {% endblock %}
--- a/MoinMoin/templates/search.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/search.html	Sat Feb 16 23:21:46 2013 +0100
@@ -25,7 +25,7 @@
     {{ gen.form.open(medium_search_form, id='moin-long-searchform', method='get', action=url_for('frontend.search', item_name=item_name)) }}
         <p>
         {{ forms.render(medium_search_form['q']) }}
-        {{ forms.render(medium_search_form['submit']) }}
+        {{ forms.render_submit(medium_search_form) }}
         </p>
         <p>
         {{ forms.render(medium_search_form['history']) }}
--- a/MoinMoin/templates/ticket.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/ticket.html	Sat Feb 16 23:21:46 2013 +0100
@@ -49,7 +49,7 @@
         {{ forms.render(form['meta'][e]) }}
     {% endfor %}
     </dl>
-    {{ forms.render(form['submit']) }}
+    {{ forms.render_submit(form) }}
 
     <h2>Back references</h2>
     <dl>
--- a/MoinMoin/templates/usersettings_forms.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/usersettings_forms.html	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,7 @@
     {{ forms.render(form['locale']) }}
 </dl>
 {{ forms.render_hidden('part', 'personal') }}
-{{ forms.render_button(_("Save")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
@@ -25,7 +25,7 @@
     {{ forms.render(form['password2']) }}
 </dl>
 {{ forms.render_hidden('part', 'password') }}
-{{ forms.render_button(_("Change password")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
@@ -39,7 +39,7 @@
     {{ forms.render(form['email']) }}
 </dl>
 {{ forms.render_hidden('part', 'notification') }}
-{{ forms.render_button(_("Save")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
@@ -53,7 +53,7 @@
     {{ forms.render(form['results_per_page']) }}
 </dl>
 {{ forms.render_hidden('part', 'ui') }}
-{{ forms.render_button(_("Save")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
@@ -64,7 +64,7 @@
     {# TODO: find a good way to handle quicklinks #}
 </dl>
 {{ forms.render_hidden('part', 'navigation') }}
-{{ forms.render_button(_("Save")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
@@ -79,7 +79,7 @@
     {{ forms.render(form['disabled']) }}
 </dl>
 {{ forms.render_hidden('part', 'options') }}
-{{ forms.render_button(_("Save")) }}
+{{ forms.render_submit(form) }}
 {{ gen.form.close() }}
 {% endmacro %}
 
--- a/MoinMoin/templates/utils.html	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/templates/utils.html	Sat Feb 16 23:21:46 2013 +0100
@@ -99,7 +99,7 @@
     {{ gen.form.open(form, id='moin-searchform', method='get', action=url_for('frontend.search')) }}
         <div>
             {{ forms.render(form['q']) }}
-            {{ gen.button(form['submit'], type='submit', id='moin-search-submit') }}
+            {{ forms.render_submit(form, id='moin-search-submit') }}
             {{ forms.render_errors(form) }}
         </div>
     {{ gen.form.close() }}
--- a/MoinMoin/themes/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,6 @@
 import urllib
 
 from json import dumps
-from operator import attrgetter
 
 from flask import current_app as app
 from flask import g as flaskg
@@ -23,7 +22,7 @@
 
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin import wikiutil, user
-from MoinMoin.config import USERID, ADDRESS, HOSTNAME
+from MoinMoin.constants.keys import USERID, ADDRESS, HOSTNAME
 from MoinMoin.search import SearchForm
 from MoinMoin.util.interwiki import split_interwiki, getInterwikiHome, is_local_wiki, is_known_wiki, url_for_item
 from MoinMoin.util.crypto import cache_key
@@ -42,7 +41,8 @@
     try:
         return get_theme(theme_name)
     except KeyError:
-        logging.warning("Theme {0!r} was not found; using default of {1!r} instead.".format(theme_name, app.cfg.theme_default))
+        logging.warning("Theme {0!r} was not found; using default of {1!r} instead.".format(
+            theme_name, app.cfg.theme_default))
         theme_name = app.cfg.theme_default
         return get_theme(theme_name)
 
@@ -51,6 +51,7 @@
 def render_template(template, **context):
     return render_theme_template(get_current_theme(), template, **context)
 
+
 def themed_error(e):
     item_name = request.view_args.get('item_name', u'')
     if e.code == 403:
@@ -73,11 +74,11 @@
         self.cfg = cfg
         self.user = flaskg.user
         self.storage = flaskg.storage
-        self.ui_lang = 'en' # XXX
-        self.ui_dir = 'ltr' # XXX
-        self.content_lang = flaskg.content_lang # XXX
-        self.content_dir = 'ltr' # XXX
-        self.meta_items = [] # list of (name, content) for html head <meta>
+        self.ui_lang = 'en'  # XXX
+        self.ui_dir = 'ltr'  # XXX
+        self.content_lang = flaskg.content_lang  # XXX
+        self.content_dir = 'ltr'  # XXX
+        self.meta_items = []  # list of (name, content) for html head <meta>
 
     def location_breadcrumbs(self, item_name):
         """
@@ -236,12 +237,12 @@
                                 item_url, item_name = line.split(' ', 1)
                                 sisteritems[item_name.decode('utf-8')] = item_url
                             except:
-                                pass # ignore invalid lines
+                                pass  # ignore invalid lines
                         f.close()
                         app.cache.set(cid, sisteritems)
                         logging.info("Site: {0!r} Status: Updated. Pages: {1}".format(sistername, len(sisteritems)))
                     except IOError as err:
-                        (title, code, msg, headers) = err.args # code e.g. 304
+                        (title, code, msg, headers) = err.args  # code e.g. 304
                         logging.warning("Site: {0!r} Status: Not updated.".format(sistername))
                         logging.exception("exception was:")
                 if current in sisteritems:
@@ -328,6 +329,7 @@
         result['email'] = email
     return result
 
+
 def shorten_item_name(name, length=25):
     """
     Shorten item names
@@ -350,6 +352,7 @@
             name = u'{0}...{1}'.format(name[:half + left], name[-half:])
     return name
 
+
 def shorten_id(name, length=7):
     """
     Shorten IDs to specified length
@@ -375,6 +378,7 @@
     'application/x-svgdraw': 'drawing',
 }
 
+
 def contenttype_to_class(contenttype):
     """
     Convert a contenttype string to a css class.
--- a/MoinMoin/themes/foobar/static/css/common.css	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/foobar/static/css/common.css	Sat Feb 16 23:21:46 2013 +0100
@@ -28,7 +28,7 @@
 section { display: block; }
 nav ul { list-style: none; }
 blockquote, q { quotes: none; }
-blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: none; }
 a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
 ins { background-color: #ff9; color: #000; text-decoration: none; }
 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
@@ -219,7 +219,7 @@
 .moin-form dd input{width:70%}
 .moin-form dt{clear:both;float:left;width:30%;text-align:right;margin-top:.3em;padding-right:1%;}
 .moin-form dt label.required:after{content:'*';color:#000}
-.moin-form button,.moin-form input[type="submit"]{clear:both;display:table;margin:auto}
+.moin-form button,.moin-form input[type="submit"]{clear:both;display:block;margin:auto}
 #moin-modify dd,form[name="delete_item"] dd,form[name="rename_item"] dd,form[name="destroy_item"] dd{margin-left:.9em;width:100%;float:none;}
 #moin-modify dd input,form[name="delete_item"] dd input,form[name="rename_item"] dd input,form[name="destroy_item"] dd input{width:96%}
 #moin-modify dt,form[name="delete_item"] dt,form[name="rename_item"] dt,form[name="destroy_item"] dt{float:none;text-align:left;width:auto}
@@ -275,7 +275,7 @@
 #file_upload{margin-top:2em}
 form.upload_file{background-color:#d6d5d0;border:1px solid #ccc;cursor:pointer;direction:ltr;font-weight:bold;height:2.5em;line-height:2.5em;overflow:hidden;position:relative;text-align:center;width:15em;box-shadow:0 0 5px #9d9d9b;}
 form.upload_file:hover{box-shadow:0 0 5px #000}
-form.upload_file input{border:300px solid transparent;cursor:pointer;opacity:0;position:absolute}
+form.upload_file input{cursor:pointer;height:100%;margin:0;opacity:0;position:absolute}
 form.upload_file button{display:none}
 form.upload_file{display:block}
 .file_upload_template .file_upload_start{visibility:hidden;border-width:0;padding:0}
--- a/MoinMoin/themes/foobar/static/css/stylus/main.styl	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/foobar/static/css/stylus/main.styl	Sat Feb 16 23:21:46 2013 +0100
@@ -269,7 +269,7 @@
     button,
     input[type="submit"]
         clear both
-        display table
+        display block
         margin auto
 
 #moin-modify, form[name="delete_item"], form[name="rename_item"], form[name="destroy_item"]
@@ -525,8 +525,9 @@
     &:hover
         box-shadow 0px 0px 5px font_color
     input
-        border 300px solid transparent
         cursor pointer
+        height 100%
+        margin 0
         opacity 0
         position absolute
 
--- a/MoinMoin/themes/foobar/static/css/stylus/reset.css	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/foobar/static/css/stylus/reset.css	Sat Feb 16 23:21:46 2013 +0100
@@ -20,7 +20,7 @@
 section { display: block; }
 nav ul { list-style: none; }
 blockquote, q { quotes: none; }
-blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: none; }
 a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
 ins { background-color: #ff9; color: #000; text-decoration: none; }
 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
--- a/MoinMoin/themes/modernized/static/css/common.css	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/modernized/static/css/common.css	Sat Feb 16 23:21:46 2013 +0100
@@ -36,7 +36,7 @@
 section { display: block; }
 nav ul { list-style: none; }
 blockquote, q { quotes: none; }
-blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: none; }
 a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
 ins { background-color: #ff9; color: #000; text-decoration: none; }
 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
@@ -272,7 +272,7 @@
 .moin-form dd input{width:75%}
 .moin-form dt{clear:both;float:left;width:25%;text-align:right;margin-top:.3em;padding-right:1%;}
 .moin-form dt label.required:after{content:'*';color:#000}
-.moin-form button,.moin-form input[type="submit"]{clear:both;display:table;margin:auto}
+.moin-form button,.moin-form input[type="submit"]{clear:both;display:block;margin:auto}
 form[name="delete_item"] dd input,form[name="rename_item"] dd input,form[name="destroy_item"] dd input{width:100%}
 form[name="delete_item"] dt,form[name="rename_item"] dt,form[name="destroy_item"] dt{width:20%}
 #moin-modify dd{width:100%;float:none;}
@@ -393,8 +393,7 @@
 #file_upload{margin-top:2em}
 form.upload_file{background-color:#708090;border:1px solid #4e7da9;color:#cfcfcf;cursor:pointer;direction:ltr;font-weight:bold;height:2.5em;line-height:2.5em;overflow:hidden;position:relative;text-align:center;width:15em;box-shadow:0 0 5px #708090}
 form.upload_file:hover{color:#fff}
-form.upload_file input{-moz-transform:translate(-800px,0) scale(10);border:300px solid transparent;cursor:pointer;height:100%;margin:0;opacity:0;position:absolute;right:0;top:0}
-form.upload_file input{height:auto}
+form.upload_file input{cursor:pointer;height:100%;margin:0;opacity:0;position:absolute;right:0;top:0}
 form.upload_file button{display:none}
 form.upload_file{display:block}
 .file_upload_template .file_upload_start{visibility:hidden;border-width:0;padding:0}
--- a/MoinMoin/themes/modernized/static/css/stylus/main.styl	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/modernized/static/css/stylus/main.styl	Sat Feb 16 23:21:46 2013 +0100
@@ -406,7 +406,7 @@
     button,
     input[type="submit"]
         clear both
-        display table
+        display block
         margin auto
 
 form[name="delete_item"], form[name="rename_item"], form[name="destroy_item"]
@@ -961,8 +961,6 @@
     color heading_color
 
 form.upload_file input
-    -moz-transform translate(-800px, 0pt) scale(10)
-    border 300px solid transparent
     cursor pointer
     height 100%
     margin 0
@@ -971,9 +969,6 @@
     right 0
     top 0
 
-form.upload_file input
-    height auto
-
 form.upload_file button
     display none
 
--- a/MoinMoin/themes/modernized/static/css/stylus/reset.css	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/themes/modernized/static/css/stylus/reset.css	Sat Feb 16 23:21:46 2013 +0100
@@ -20,7 +20,7 @@
 section { display: block; }
 nav ul { list-style: none; }
 blockquote, q { quotes: none; }
-blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: none; }
 a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
 ins { background-color: #ff9; color: #000; text-decoration: none; }
 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
--- a/MoinMoin/user.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/user.py	Sat Feb 16 23:21:46 2013 +0100
@@ -31,14 +31,13 @@
 from flask import g as flaskg
 from flask import session, request, url_for
 
-from whoosh.query import Term, And, Or
-
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
 from MoinMoin import wikiutil
-from MoinMoin.config import CONTENTTYPE_USER
+from MoinMoin.constants.contenttypes import CONTENTTYPE_USER
 from MoinMoin.constants.keys import *
+from MoinMoin.constants.misc import ANON
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.mail import sendmail
 from MoinMoin.util.interwiki import getInterwikiHome, getInterwikiName, is_local_wiki
@@ -58,7 +57,7 @@
 space between words. Group page name is not allowed.""", name=username)
 
     # Name required to be unique. Check if name belong to another user.
-    if validate and search_users(name_exact=username):
+    if validate and search_users(**{NAME_EXACT: username}):
         return _("This user name already belongs to somebody else.")
 
     # XXX currently we just support creating with 1 name:
@@ -115,8 +114,8 @@
     """ Searches for a users with given query keys/values """
     # Since item name is a list, it's possible a list have been passed as parameter.
     # No problem, since user always have just one name (TODO: validate single name for user)
-    if q.get('name_exact') and isinstance(q.get('name_exact'), list):
-        q['name_exact'] = q['name_exact'][0]
+    if q.get(NAME_EXACT) and isinstance(q.get(NAME_EXACT), list):
+        q[NAME_EXACT] = q[NAME_EXACT][0]
     q = update_user_query(**q)
     backend = get_user_backend()
     docs = backend.documents(**q)
@@ -160,9 +159,9 @@
     :rtype: unicode
     :returns: user name that can be used in acl lines
     """
-    username_allowedchars = "'@.-_" # ' for names like O'Brian or email addresses.
-                                    # "," and ":" must not be allowed (ACL delimiters).
-                                    # We also allow _ in usernames for nicer URLs.
+    username_allowedchars = "'@.-_"  # ' for names like O'Brian or email addresses.
+                                     # "," and ":" must not be allowed (ACL delimiters).
+                                     # We also allow _ in usernames for nicer URLs.
     # Strip non alpha numeric characters (except username_allowedchars), keep white space
     name = ''.join([c for c in name if c.isalnum() or c.isspace() or c in username_allowedchars])
 
@@ -206,7 +205,7 @@
             return self._meta[name]
         except KeyError:
             v = self._defaults[name]
-            if isinstance(v, (list, dict, set)): # mutable
+            if isinstance(v, (list, dict, set)):  # mutable
                 self._meta[name] = v
             return v
 
@@ -286,11 +285,11 @@
 
         itemid = uid
         if not itemid and auth_username:
-            users = search_users(name_exact=auth_username)
+            users = search_users(**{NAME_EXACT: auth_username})
             if users:
                 itemid = users[0].meta[ITEMID]
-        if not itemid and _name and _name != 'anonymous':
-            users = search_users(name_exact=_name)
+        if not itemid and _name and _name != ANON:
+            users = search_users(**{NAME_EXACT: _name})
             if users:
                 itemid = users[0].meta[ITEMID]
         if itemid:
@@ -333,7 +332,7 @@
             assert isinstance(names, list)
             return names[0]
         except IndexError:
-            return u'anonymous'
+            return ANON
 
     @property
     def language(self):
@@ -378,8 +377,8 @@
 
         :param changed: bool, set this to True if you updated the user profile values
         """
-        if not self.valid and not self.disabled or changed: # do we need to save/update?
-            self.save() # yes, create/update user profile
+        if not self.valid and not self.disabled or changed:  # do we need to save/update?
+            self.save()  # yes, create/update user profile
 
     def exists(self):
         """ Do we have a user profile for this user?
@@ -441,7 +440,8 @@
         try:
             password_correct, recomputed_hash = pwd_context.verify_and_update(password, pw_hash)
         except (ValueError, TypeError) as err:
-            logging.error('in user profile %r, verifying the passlib pw hash raised an Exception [%s]' % (self.name, str(err)))
+            logging.error('in user profile %r, verifying the passlib pw hash raised an Exception [%s]' % (
+                self.name, str(err)))
         else:
             if recomputed_hash is not None:
                 data[ENC_PASSWORD] = recomputed_hash
@@ -481,13 +481,13 @@
             self.valid = True
 
         if not exists:
-            pass # XXX UserCreatedEvent
+            pass  # XXX UserCreatedEvent
         else:
-            pass # XXX UserChangedEvent
+            pass  # XXX UserChangedEvent
 
     def getText(self, text):
         """ translate a text to the language of this user """
-        return text # FIXME, was: self._request.getText(text, lang=self.language)
+        return text  # FIXME, was: self._request.getText(text, lang=self.language)
 
     # Bookmarks --------------------------------------------------------------
 
@@ -666,9 +666,9 @@
         item_name = getInterwikiName(item_name)
         trail_in_session = session.get('trail', [])
         trail = trail_in_session[:]
-        trail = [i for i in trail if i != item_name] # avoid dupes
-        trail.append(item_name) # append current item name at end
-        trail = trail[-self._cfg.trail_size:] # limit trail length
+        trail = [i for i in trail if i != item_name]  # avoid dupes
+        trail.append(item_name)  # append current item name at end
+        trail = trail[-self._cfg.trail_size:]  # limit trail length
         if trail != trail_in_session:
             session['trail'] = trail
 
--- a/MoinMoin/util/__init__.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/__init__.py	Sat Feb 16 23:21:46 2013 +0100
@@ -36,6 +36,7 @@
     '"': '&quot;'
 }
 
+
 def TranslateCDATA(text):
     """
         Convert a string to a CDATA-encoded one
@@ -46,6 +47,7 @@
     new_string, num_subst = re.subn(g_xmlIllegalCharPattern, lambda m: '&#x%02X;' % ord(m.group()), new_string)
     return new_string
 
+
 def TranslateText(text):
     """
         Convert a string to a PCDATA-encoded one (do minimal encoding)
@@ -68,23 +70,25 @@
     numbers = sorted(numbers[:])
     numbers.append(999999)
     pattern = ','
-    for i in range(len(numbers)-1):
+    for i in range(len(numbers) - 1):
         if pattern[-1] == ',':
             pattern = pattern + str(numbers[i])
-            if numbers[i] + 1 == numbers[i+1]:
+            if numbers[i] + 1 == numbers[i + 1]:
                 pattern = pattern + '-'
             else:
                 pattern = pattern + ','
-        elif numbers[i] + 1 != numbers[i+1]:
+        elif numbers[i] + 1 != numbers[i + 1]:
             pattern = pattern + str(numbers[i]) + ','
 
     if pattern[-1] in ',-':
         return pattern[1:-1]
     return pattern[1:]
 
+
 def getPageContent(results, offset, results_per_page):
     """ Selects the content to show on a single page
-        :param results: the whole result, from which results for one page will be selected (generally a generator but could be a list also),
+        :param results: the whole result, from which results for one page will be selected (generally a generator
+               but could be a list also),
         :param offset: after skipping how many results, the selection of results for that page will be done (int),
         :param results_per_page: number of results to be shown on a single page (int)
 
--- a/MoinMoin/util/_tests/test_crypto.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_crypto.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,6 @@
 """
 
 
-import pytest
 from MoinMoin.util import crypto
 
 
--- a/MoinMoin/util/_tests/test_diff_html.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_diff_html.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,7 @@
 MoinMoin - MoinMoin.util.diff_html Tests
 """
 
-import pytest
+
 from MoinMoin.util import diff_html
 
 def test_indent():
--- a/MoinMoin/util/_tests/test_forms.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_forms.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,7 +7,7 @@
 """
 
 from MoinMoin.util import forms
-import pytest
+
 
 class Bind(object):
     """ class for self defined test_bind attributes """
--- a/MoinMoin/util/_tests/test_interwiki.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_interwiki.py	Sat Feb 16 23:21:46 2013 +0100
@@ -16,7 +16,7 @@
 
 from MoinMoin.util.interwiki import split_interwiki, join_wiki, InterWikiMap, url_for_item, _split_namespace
 from MoinMoin._tests import wikiconfig
-from MoinMoin.config import CURRENT
+from MoinMoin.constants.keys import CURRENT
 from MoinMoin.app import before_wiki
 
 from flask import current_app as app
@@ -115,8 +115,8 @@
 
                  (('http://example.org/', u'SomePage', u'ns1'), 'http://example.org/:ns1:SomePage'),
                  (('http://example.org/?page=$PAGE&action=show&namespace=$NAMESPACE', u'SomePage', u'ns1'), 'http://example.org/?page=SomePage&action=show&namespace=ns1'),
-                 (('http://example.org/', u'Aktuelle\xc4nderungen', u'ns1ççç'), 'http://example.org/:ns1%C3%83%C2%A7%C3%83%C2%A7%C3%83%C2%A7:Aktuelle%C3%84nderungen'),
-                 (('http://example.org/$NAMESPACE/$PAGE/show', u'Aktuelle\xc4nderungen', u'nsç1'), 'http://example.org/ns%C3%83%C2%A71/Aktuelle%C3%84nderungen/show'),
+                 (('http://example.org/', u'Aktuelle\xc4nderungen', u'ns1\xc4'), 'http://example.org/:ns1%C3%84:Aktuelle%C3%84nderungen'),
+                 (('http://example.org/$NAMESPACE/$PAGE/show', u'Aktuelle\xc4nderungen', u'ns\xc41'), 'http://example.org/ns%C3%841/Aktuelle%C3%84nderungen/show'),
                 ]
         for (baseurl, pagename, namespace), url in tests:
             assert join_wiki(baseurl, pagename, namespace) == url
--- a/MoinMoin/util/_tests/test_mime.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_mime.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import pytest
-
 from MoinMoin.util.mime import *
 
 def test_Type_init_1():
--- a/MoinMoin/util/_tests/test_mimetype.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_mimetype.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,7 @@
 MoinMoin - MoinMoin.util.mimetype Tests
 """
 
-import pytest
+
 from MoinMoin.util import mimetype
 
 class TestMimeType(object):
@@ -14,7 +14,7 @@
 
     def test_parse_format(self):
         MimeType_obj = mimetype.MimeType(filename='test_file.jpg')
-        # format in config.parser_text_mimetype
+        # format in PARSER_TEXT_MIMETYPE
         test = [
         #test_format, test_mimetype
         ('html', ('text', 'html')),
@@ -27,7 +27,7 @@
             result = MimeType_obj.parse_format(test_format)
             assert result == test_mimetype
 
-        # format not in config.parser_text_mimetype
+        # format not in PARSER_TEXT_MIMETYPE
         test = [
         # test_format, test_mimetype
         ('wiki', ('text', 'x.moin.wiki')),
--- a/MoinMoin/util/_tests/test_thread_monitor.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_thread_monitor.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,7 +9,6 @@
 import shutil, tempfile
 import os
 
-import pytest
 from MoinMoin.util.thread_monitor import Monitor
 
 class TestMonitor(object):
--- a/MoinMoin/util/_tests/test_tree.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/_tests/test_tree.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,8 +6,6 @@
 """
 
 
-import pytest
-
 from MoinMoin.util.tree import *
 
 def test_Name():
--- a/MoinMoin/util/clock.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/clock.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,6 +15,7 @@
 
 from flask import g as flaskg
 
+
 class Clock(object):
     """
     Helper class for measuring the time needed to run code.
@@ -41,7 +42,7 @@
     def stop(self, timer):
         if timer in self.timers:
             value = time.time() - self.timers[timer].pop()
-            logging.info('timer {0}({1}): {2:.2f}ms'.format(timer, len(self.timers[timer]), value*1000))
+            logging.info('timer {0}({1}): {2:.2f}ms'.format(timer, len(self.timers[timer]), value * 1000))
             if not self.timers[timer]:
                 del self.timers[timer]
             return value
@@ -54,6 +55,7 @@
 def add_timing(f, name=None):
     if name is None:
         name = f.__name__
+
     @wraps(f)
     def wrapper(*args, **kw):
         flaskg.clock.start(name)
@@ -62,5 +64,6 @@
         return retval
     return wrapper
 
+
 def timed(name=None):
     return partial(add_timing, name=name)
--- a/MoinMoin/util/crypto.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/crypto.py	Sat Feb 16 23:21:46 2013 +0100
@@ -76,7 +76,7 @@
     return unicode(key), token
 
 
-def valid_token(key, token, timeout=2*60*60):
+def valid_token(key, token, timeout=2 * 60 * 60):
     """
     check if token is valid with respect to the secret key,
     the token must not be older than timeout seconds.
--- a/MoinMoin/util/diff3.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/diff3.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,12 +10,14 @@
                    '=========================\n',
                    '>>>>>>>>>>>>>>>>>>>>>>>>>\n')
 
+
 def text_merge(old, other, new, allow_conflicts=1, *markers):
     """ do line by line diff3 merge with three strings """
     result = merge(old.splitlines(1), other.splitlines(1), new.splitlines(1),
                    allow_conflicts, *markers)
     return ''.join(result)
 
+
 def merge(old, other, new, allow_conflicts=1, *markers):
     """ do line by line diff3 merge
         input must be lists containing single lines
@@ -36,7 +38,7 @@
             other_nr += 1
             new_nr += 1
         else:
-            if allow_conflicts == 2: # experimental addition to the algorithm
+            if allow_conflicts == 2:  # experimental addition to the algorithm
                 if other[other_nr] == new[new_nr]:
                     result.append(new[new_nr])
                     other_nr += 1
@@ -101,11 +103,11 @@
         result.extend(other[other_nr:])
     # new deleted lines
     elif (new_nr == new_len and (old_len - old_nr == other_len - other_nr) and
-          match(old, other, old_nr, other_nr, old_len-old_nr) == old_len - old_nr):
+          match(old, other, old_nr, other_nr, old_len - old_nr) == old_len - old_nr):
         pass
     # other deleted lines
-    elif (other_nr == other_len and (old_len - old_nr == new_len-new_nr) and
-          match(old, new, old_nr, new_nr, old_len-old_nr) == old_len - old_nr):
+    elif (other_nr == other_len and (old_len - old_nr == new_len - new_nr) and
+          match(old, new, old_nr, new_nr, old_len - old_nr) == old_len - old_nr):
         pass
     # conflict
     else:
@@ -121,6 +123,7 @@
             result.append(marker3)
     return result
 
+
 def tripple_match(old, other, new, other_match, new_match):
     """find next matching pattern unchanged in both other and new
        return the position in all three lists
@@ -132,7 +135,7 @@
             match_len = match(old, other, other_match[0], other_match[1],
                               difference)
             if match_len == difference:
-                return (new_match[0], other_match[1]+difference, new_match[1])
+                return (new_match[0], other_match[1] + difference, new_match[1])
             else:
                 other_match = find_match(old, other,
                                          other_match[0] + match_len,
@@ -154,6 +157,7 @@
         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
@@ -169,6 +173,7 @@
             break
     return i
 
+
 def find_match(list1, list2, nr1, nr2, mincount=3):
     """searches next matching pattern with lenght mincount
        if no pattern is found len of the both lists is returned
@@ -214,6 +219,7 @@
     else:
         return (len1, len2)
 
+
 def main():
 
     text0 = """AAA 001
--- a/MoinMoin/util/diff_html.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/diff_html.py	Sat Feb 16 23:21:46 2013 +0100
@@ -13,6 +13,7 @@
 
 from MoinMoin.i18n import _, L_, N_
 
+
 def indent(line):
     eol = ''
     while line and line[0] == '\n':
@@ -52,7 +53,7 @@
         if lastmatch == match[0:2]:
             lastmatch = (match[0] + match[2], match[1] + match[2])
             continue
-        llineno, rlineno = lastmatch[0]+1, lastmatch[1]+1
+        llineno, rlineno = lastmatch[0] + 1, lastmatch[1] + 1
         leftpane = u''
         rightpane = u''
         linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1])
--- a/MoinMoin/util/diff_text.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/diff_text.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,6 +8,7 @@
 
 import difflib
 
+
 def diff(oldlines, newlines, **kw):
     """
     Find changes between oldlines and newlines.
@@ -54,12 +55,12 @@
             lcount_new = lcount_new + 1
         elif marker in ['-', '+']:
             if (count == i) and count > 3:
-                lines[:i-3] = []
+                lines[:i - 3] = []
                 i = 4
                 count = 0
             elif count > 6:
                 # remove lines and insert new hunk indicator
-                lines[i-count+3:i-3] = ['@@ -{0:d}, +{1:d} @@\n'.format(lcount_old, lcount_new)]
+                lines[i - count + 3:i - 3] = ['@@ -{0:d}, +{1:d} @@\n'.format(lcount_old, lcount_new)]
                 i = i - count + 8
                 count = 0
             else:
@@ -70,10 +71,10 @@
             else:
                 lcount_new = lcount_new + 1
         elif marker == '?':
-            lines[i:i+1] = []
+            lines[i:i + 1] = []
 
     # remove unchanged lines a the end
     if count > 3:
-        lines[-count+3:] = []
+        lines[-count + 3:] = []
 
     return lines
--- a/MoinMoin/util/filesys.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/filesys.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,13 +7,17 @@
 """
 
 
-import sys, os, shutil, time, errno
+import sys
+import os
+import shutil
+import time
+import errno
 from stat import S_ISDIR, ST_MODE, S_IMODE
-import warnings
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
+
 #############################################################################
 ### Misc Helpers
 #############################################################################
@@ -32,6 +36,7 @@
 
 rename_overwrite = rename
 
+
 def rename_no_overwrite(oldname, newname, delete_old=False):
     """ Multiplatform rename
 
@@ -67,7 +72,9 @@
 
 def touch(name):
     if sys.platform == 'win32':
-        import win32file, win32con, pywintypes
+        import win32file
+        import win32con
+        import pywintypes
 
         access = win32file.GENERIC_WRITE
         share = (win32file.FILE_SHARE_DELETE |
@@ -105,7 +112,8 @@
                     if retry > max_retries:
                         raise
                     if err.errno == errno.EACCES:
-                        logging.warning('{0}({1!r}, {2!r}) -> access denied. retrying...'.format(fn.__name__, args, kwargs))
+                        logging.warning('{0}({1!r}, {2!r}) -> access denied. retrying...'.format(
+                            fn.__name__, args, kwargs))
                         time.sleep(0.01)
                         continue
                     raise
@@ -192,7 +200,7 @@
             st = os.stat(src)
             mode = S_IMODE(st[ST_MODE])
             if hasattr(os, 'chmod'):
-                os.chmod(dst, mode) # KEEP THIS ONE!
+                os.chmod(dst, mode)  # KEEP THIS ONE!
     else:
         shutil.copystat(src, dst)
 
--- a/MoinMoin/util/forms.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/forms.py	Sat Feb 16 23:21:46 2013 +0100
@@ -13,6 +13,7 @@
 
 from MoinMoin.i18n import _, L_, N_
 
+
 def label_filter(tagname, attributes, contents, context, bind):
     """Provide a translated, generated fallback for field labels."""
     if bind is not None and not contents:
@@ -20,6 +21,7 @@
     return contents
 label_filter.tags = set(['label'])
 
+
 def button_filter(tagname, attributes, contents, context, bind):
     """Show translated text in clickable buttons and submits."""
     if bind is None:
@@ -33,14 +35,16 @@
     return contents
 button_filter.tags = set(['input', 'button'])
 
+
 def required_filter(tagname, attributes, contents, context, bind):
-    if (bind is not None and not bind.optional):
+    if bind is not None and not bind.optional:
         attributes[u'class'] = u'required'
         if tagname == 'input':
             attributes[u'required'] = u'required'
     return contents
 required_filter.tags = set(['input', 'label'])
 
+
 def autofocus_filter(tagname, attributes, contents, context, bind):
     if bind is not None:
         autofocus = bind.properties.get('autofocus')
@@ -49,6 +53,7 @@
     return contents
 autofocus_filter.tags = set(['input', 'textarea', ])
 
+
 def placeholder_filter(tagname, attributes, contents, context, bind):
     if bind is not None:
         placeholder = bind.properties.get('placeholder')
@@ -57,6 +62,7 @@
     return contents
 placeholder_filter.tags = set(['input', 'textarea', ])
 
+
 def error_filter_factory(class_='moin-error'):
     """Returns an HTML generation filter annotating field CSS class on error.
 
--- a/MoinMoin/util/interwiki.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/interwiki.py	Sat Feb 16 23:21:46 2013 +0100
@@ -15,13 +15,12 @@
 
 import os.path
 
-from MoinMoin.config import CURRENT
+from MoinMoin.constants.keys import CURRENT
+from MoinMoin.constants.contenttypes import CHARSET
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import config
-
 
 def is_local_wiki(wiki_name):
     """
@@ -72,6 +71,8 @@
                 item_name = u'{0}:{1}'.format(namespace, item_name)
             if wiki_name:
                 url = u'{0}:{1}'.format(wiki_name, item_name)
+            else:
+                url = item_name
             url = u'/{0}'.format(url)
         else:
             if (rev is None or rev == CURRENT) and endpoint == 'frontend.show_item':
@@ -89,10 +90,11 @@
                 # just want e.g. +show/42/FooBar to append it to the other wiki's
                 # base URL.
                 i = local_url.index('/%2B')
-                path = local_url[i+1:]
+                path = local_url[i + 1:]
                 url = wiki_base_url + path
     return url
 
+
 def _split_namespace(namespaces, url):
     """
     Find the longest namespace in the set.
@@ -121,6 +123,7 @@
         url = url[length:]
     return namespace, url
 
+
 def split_interwiki(wikiurl):
     """ Split a interwiki name, into wikiname and pagename, e.g:
 
@@ -163,6 +166,7 @@
             item_name = u':{0}'.format(item_name)
         return u'Self', namespace, item_name
 
+
 def join_wiki(wikiurl, wikitail, namespace):
     """
     Add a (url_quoted) page name to an interwiki url.
@@ -176,8 +180,8 @@
     :rtype: string
     :returns: generated URL of the page in the other wiki
     """
-    wikitail = url_quote(wikitail, charset=config.charset, safe='/')
-    namespace = url_quote(namespace, charset=config.charset, safe='/')
+    wikitail = url_quote(wikitail, charset=CHARSET, safe='/')
+    namespace = url_quote(namespace, charset=CHARSET, safe='/')
     if not('$PAGE' in wikiurl or '$NAMESPACE' in wikiurl):
         if namespace:
             namespace = u':{0}:'.format(namespace)
@@ -190,11 +194,12 @@
         wikiurl = wikiurl.replace('$NAMESPACE', namespace)
     return wikiurl
 
+
 def getInterwikiName(item_name):
     """
     Get the (fully qualified) interwiki name of a local item name.
 
-    :param item_ame: item name (unicode)
+    :param item_name: item name (unicode)
     :rtype: unicode
     :returns: wiki_name:item_name
     """
--- a/MoinMoin/util/iri.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/iri.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,6 +10,7 @@
 
 import codecs
 import re
+from MoinMoin.util.pysupport import AutoNe
 
 
 def _iriquote_replace(exc):
@@ -25,7 +26,7 @@
 codecs.register_error('iriquote', _iriquote_replace)
 
 
-class Iri(object):
+class Iri(AutoNe):
     __slots__ = '_scheme', '_authority', '_path', '_query', '_fragment'
 
     overall_rules = r"""
@@ -160,12 +161,6 @@
 
         return NotImplemented
 
-    def __ne__(self, other):
-        ret = self.__eq__(other)
-        if ret is NotImplemented:
-            return ret
-        return not ret
-
     def __repr__(self):
         return '{0}(scheme={1!r}, authority={2!r}, path={3!r}, query={4!r}, fragment={5!r})'.format(
                 self.__class__.__name__,
@@ -231,8 +226,10 @@
 
     def __del_scheme(self):
         self._scheme = None
+
     def __get_scheme(self):
         return self._scheme
+
     def __set_scheme(self, value):
         self._scheme = unicode(value).lower()
     scheme = property(__get_scheme, __set_scheme, __del_scheme,
@@ -240,8 +237,10 @@
 
     def __del_authority(self):
         self._authority = None
+
     def __get_authority(self):
         return self._authority
+
     def __set_authority(self, value):
         if value.__class__ is not IriAuthority:
             value = IriAuthority(value, False)
@@ -251,8 +250,10 @@
 
     def __del_path(self):
         self._path = None
+
     def __get_path(self):
         return self._path
+
     def __set_path(self, value):
         if value.__class__ is not IriPath:
             value = IriPath(value, False)
@@ -262,8 +263,10 @@
 
     def __del_query(self):
         self._query = None
+
     def __get_query(self):
         return self._query
+
     def __set_query(self, value):
         self._query = IriQuery(value, False)
     query = property(__get_query, __set_query, __del_query,
@@ -271,8 +274,10 @@
 
     def __del_fragment(self):
         self._fragment = None
+
     def __get_fragment(self):
         return self._fragment
+
     def __set_fragment(self, value):
         self._fragment = IriFragment(value, False)
     fragment = property(__get_fragment, __set_fragment, __del_fragment,
@@ -283,8 +288,12 @@
     __slots__ = '_quoted'
 
     # Rules for quoting parts of the IRI.
-    quote_rules_iri = u"""((?:%[0-9a-fA-F]{2})+)|([^-!$&'*+.0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz|\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)"""
-    quote_rules_uri = u"""((?:%[0-9a-fA-F]{2})+)|([^-!$&'*+.0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz|]+)"""
+    quote_rules_iri = (u"""((?:%[0-9a-fA-F]{2})+)|"""
+                       u"""([^-!$&'*+.0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz|"""
+                       u"""\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)""")
+    quote_rules_uri = (u"""((?:%[0-9a-fA-F]{2})+)|"""
+                       u"""([^-!$&'*+.0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz|"""
+                       u"""]+)""")
     quote_filter = frozenset()
 
     _quote_re_iri = re.compile(quote_rules_iri)
@@ -313,7 +322,8 @@
         """
         Quote all illegal characters.
 
-        :param rules: List of unicode ranges
+        :param input: the string to quote
+        :param url: True for URI, False for IRI
         :param requote: Input string is already quoted
         :returns: Quoted string
         """
@@ -401,7 +411,7 @@
         return self._quote(self, url=True)
 
 
-class IriAuthority(object):
+class IriAuthority(AutoNe):
     authority_rules = r"""
     ^
     (
@@ -452,12 +462,6 @@
                     self.port == other.port
         return NotImplemented
 
-    def __ne__(self, other):
-        ret = self.__eq__(other)
-        if ret is NotImplemented:
-            return ret
-        return not ret
-
     def __nonzero__(self):
         if self._userinfo or self._host or self.port:
             return True
@@ -547,16 +551,20 @@
 
     def __del_userinfo(self):
         self._userinfo = None
+
     def __get_userinfo(self):
         return self._userinfo
+
     def __set_userinfo(self, value):
         self._userinfo = IriAuthorityUserinfo(value, False)
     userinfo = property(__get_userinfo, __set_userinfo, __del_userinfo)
 
     def __del_host(self):
         self._host = None
+
     def __get_host(self):
         return self._host
+
     def __set_host(self, value):
         self._host = IriAuthorityHost(value, False)
     host = property(__get_host, __set_host, __del_host)
@@ -570,7 +578,7 @@
     pass
 
 
-class IriPath(object):
+class IriPath(AutoNe):
     __slots__ = '_list'
 
     def __init__(self, iri_path=None, _quoted=True):
@@ -592,12 +600,6 @@
             return self._list == other._list
         return NotImplemented
 
-    def __ne__(self, other):
-        ret = self.__eq__(other)
-        if ret is NotImplemented:
-            return ret
-        return not ret
-
     def __getitem__(self, key):
         ret = self._list[key]
         if isinstance(key, slice):
@@ -692,11 +694,14 @@
         """
         return u'/'.join((i.urlquoted for i in self._list))
 
+
 class IriPathSegment(_Value):
     quote_filter = frozenset('@:/')
 
+
 class IriQuery(_Value):
     quote_filter = frozenset('@:/?')
 
+
 class IriFragment(_Value):
     quote_filter = frozenset('@:/?')
--- a/MoinMoin/util/mime.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/mime.py	Sat Feb 16 23:21:46 2013 +0100
@@ -7,8 +7,10 @@
 
 
 from collections import namedtuple
+from MoinMoin.util.pysupport import AutoNe
 
-class Type(namedtuple('Type', 'type subtype parameters')):
+
+class Type(namedtuple('Type', 'type subtype parameters'), AutoNe):
     """
     :ivar type: Type part
     :type type: unicode
@@ -18,7 +20,8 @@
     :type parameters: dict
     """
 
-    __token_allowed = s = frozenset(r"""!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~""")
+    __token_allowed = s = frozenset(r"""!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"""
+                                    r"""^_`abcdefghijklmnopqrstuvwxyz{|}~""")
 
     def __new__(cls, _type=None, type=None, subtype=None, parameters=None):
         """
@@ -53,12 +56,6 @@
 
         return NotImplemented
 
-    def __ne__(self, other):
-        ret = self.__eq__(other)
-        if ret is NotImplemented:
-            return ret
-        return not ret
-
     def __unicode__(self):
         ret = [u'{0}/{1}'.format(self.type or '*', self.subtype or '*')]
 
--- a/MoinMoin/util/mimetype.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/mimetype.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,7 +10,7 @@
 
 import mimetypes
 
-from MoinMoin import config
+from MoinMoin.constants.contenttypes import PARSER_TEXT_MIMETYPE
 
 # prevents unexpected results on Windows
 # see http://bugs.python.org/issue10551
@@ -74,7 +74,7 @@
     ('application', 'javascript'): ('text', 'javascript'),
 }
 
-MIMETYPES_spoil_mapping = {} # inverse mapping of above
+MIMETYPES_spoil_mapping = {}  # inverse mapping of above
 for _key, _value in MIMETYPES_sanitize_mapping.items():
     MIMETYPES_spoil_mapping[_value] = _key
 
@@ -83,9 +83,9 @@
     """ represents a mimetype like text/plain """
 
     def __init__(self, mimestr=None, filename=None):
-        self.major = self.minor = None # sanitized mime type and subtype
-        self.params = {} # parameters like "charset" or others
-        self.charset = None # this stays None until we know for sure!
+        self.major = self.minor = None  # sanitized mime type and subtype
+        self.params = {}  # parameters like "charset" or others
+        self.charset = None  # this stays None until we know for sure!
         self.raw_mimestr = mimestr
         self.filename = filename
         if mimestr:
@@ -108,14 +108,14 @@
         mimetype, parameters = parameters[0], parameters[1:]
         mimetype = mimetype.split('/')
         if len(mimetype) >= 2:
-            major, minor = mimetype[:2] # we just ignore more than 2 parts
+            major, minor = mimetype[:2]  # we just ignore more than 2 parts
         else:
             major, minor = self.parse_format(mimetype[0])
         self.major = major.lower()
         self.minor = minor.lower()
         for param in parameters:
             key, value = param.split('=')
-            if value[0] == '"' and value[-1] == '"': # remove quotes
+            if value[0] == '"' and value[-1] == '"':  # remove quotes
                 value = value[1:-1]
             self.params[key.lower()] = value
         if 'charset' in self.params:
@@ -129,7 +129,7 @@
             type "wiki" instead of "text/x.moin.wiki".
         """
         format = format.lower()
-        if format in config.parser_text_mimetype:
+        if format in PARSER_TEXT_MIMETYPE:
             mimetype = 'text', format
         else:
             mapping = {
--- a/MoinMoin/util/monkeypatch.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/monkeypatch.py	Sat Feb 16 23:21:46 2013 +0100
@@ -17,6 +17,7 @@
 import werkzeug.serving
 from werkzeug._internal import _log
 
+
 class BaseRequestHandler(werkzeug.serving.BaseRequestHandler):
     def log(self, type, message, *args):
         _log(type, "{0} {1}\n".format(self.address_string(),
--- a/MoinMoin/util/paramparser.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/paramparser.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,11 +12,13 @@
 class BracketError(Exception):
     pass
 
+
 class BracketUnexpectedCloseError(BracketError):
     def __init__(self, bracket):
         self.bracket = bracket
         BracketError.__init__(self, "Unexpected closing bracket {0}".format(bracket))
 
+
 class BracketMissingCloseError(BracketError):
     def __init__(self, bracket):
         self.bracket = bracket
@@ -116,8 +118,8 @@
     quoted = None       # we're inside quotes, indicates quote character used
     skipquote = 0       # next quote is a quoted quote
     noquote = False     # no quotes expected because word didn't start with one
-    seplimit_reached = False # number of separators exhausted
-    separator_count = 0 # number of separators encountered
+    seplimit_reached = False  # number of separators exhausted
+    separator_count = 0  # number of separators encountered
     SPACE = [' ', '\t', ]
     nextitemsep = [separator]   # used for skipping trailing space
     SPACE = [' ', '\t', ]
@@ -162,7 +164,7 @@
         char = args[idx]
         next = None
         if idx + 1 < max:
-            next = args[idx+1]
+            next = args[idx + 1]
         if skipquote:
             skipquote -= 1
         if not separator is None and not quoted and char in SPACE:
@@ -202,7 +204,7 @@
             quoted = char
         elif char == quoted and not skipquote:
             if next == quoted:
-                skipquote = 2 # will be decremented right away
+                skipquote = 2  # will be decremented right away
             else:
                 quoted = None
         elif not quoted and char in opening:
--- a/MoinMoin/util/plugins.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/plugins.py	Sat Feb 16 23:21:46 2013 +0100
@@ -11,7 +11,8 @@
 """
 
 
-import os, sys
+import os
+import sys
 import imp
 import hashlib
 
@@ -23,9 +24,11 @@
 class PluginError(Exception):
     """ Base class for plugin errors """
 
+
 class PluginMissingError(PluginError):
     """ Raised when a plugin is not found """
 
+
 class PluginAttributeError(PluginError):
     """ Raised when plugin does not contain an attribtue """
 
--- a/MoinMoin/util/profile.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/profile.py	Sat Feb 16 23:21:46 2013 +0100
@@ -38,7 +38,9 @@
 """
 
 
-import os, time, gc
+import os
+import time
+import gc
 
 
 class Profiler:
@@ -62,9 +64,9 @@
         self.requestsPerSample = requestsPerSample
         self.collect = collect
         self.pid = os.getpid()
-        self.count = 0 # count between somples
-        self.requests = 0 # requests added
-        self.data = {'collect': 'NA'} # Sample data
+        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
--- a/MoinMoin/util/pysupport.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/pysupport.py	Sat Feb 16 23:21:46 2013 +0100
@@ -6,7 +6,8 @@
 MoinMoin - Supporting functions for Python magic
 """
 
-import os, sys
+import os
+import sys
 import re
 import imp
 
@@ -139,3 +140,14 @@
             lock.release()
 
     return decorated
+
+
+class AutoNe(object):
+    """
+    Implement __ne__ in terms of __eq__. This is a mixin class.
+    """
+    def __ne__(self, other):
+        ret = self.__eq__(other)
+        if ret is NotImplemented:
+            return ret
+        return not ret
--- a/MoinMoin/util/thread_monitor.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/thread_monitor.py	Sat Feb 16 23:21:46 2013 +0100
@@ -23,7 +23,7 @@
 class Monitor(object):
     def __init__(self):
         self.enabled = False
-        assert hasattr(sys, "_current_frames") # make sure we have py >= 2.5
+        assert hasattr(sys, "_current_frames")  # make sure we have py >= 2.5
 
     def activate_hook(self):
         """ Activates the thread monitor hook. Note that this might interfere
--- a/MoinMoin/util/version.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/util/version.py	Sat Feb 16 23:21:46 2013 +0100
@@ -10,6 +10,7 @@
 
 import re
 
+
 class Version(tuple):
     """
     Version objects store versions like 1.2.3a4 in a structured
--- a/MoinMoin/wikiutil.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/MoinMoin/wikiutil.py	Sat Feb 16 23:21:46 2013 +0100
@@ -14,8 +14,6 @@
 from __future__ import absolute_import, division
 
 import os
-import re
-import time
 
 from MoinMoin import log
 logging = log.getLogger(__name__)
@@ -24,11 +22,12 @@
 from flask import g as flaskg
 from flask import request
 
-from MoinMoin import config
-from MoinMoin.config import CURRENT, IS_SYSITEM
+from MoinMoin.constants.contenttypes import CHARSET
+from MoinMoin.constants.keys import CURRENT, IS_SYSITEM
+from MoinMoin.constants.misc import URI_SCHEMES, CLEAN_INPUT_TRANSLATION_MAP, ITEM_INVALID_CHARS_REGEX
+from MoinMoin.constants.contenttypes import DRAWING_EXTENSIONS
 
 from MoinMoin.i18n import _, L_, N_
-from MoinMoin.util import pysupport
 from MoinMoin.util.mimetype import MimeType
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError
 
@@ -40,6 +39,7 @@
 CHILD_PREFIX = "/"
 CHILD_PREFIX_LEN = len(CHILD_PREFIX)
 
+
 #############################################################################
 ### Data validation / cleanup
 #############################################################################
@@ -62,8 +62,8 @@
         if isinstance(text, str):
             # the translate() below can ONLY process unicode, thus, if we get
             # str, we try to decode it using the usual coding:
-            text = text.decode(config.charset)
-        return text.translate(config.clean_input_translation_map)
+            text = text.decode(CHARSET)
+        return text.translate(CLEAN_INPUT_TRANSLATION_MAP)
 
 
 # TODO: use similar code in a flatland validator
@@ -81,7 +81,7 @@
     :returns: decoded and sanitized page name
     """
     # Strip invalid characters
-    name = config.page_invalid_chars_regex.sub(u'', name)
+    name = ITEM_INVALID_CHARS_REGEX.sub(u'', name)
 
     # Split to pages and normalize each one
     pages = name.split(u'/')
@@ -158,6 +158,7 @@
             itemname = itemname[CHILD_PREFIX_LEN:]
     return itemname
 
+
 def RelItemName(context, itemname):
     """
     Return the relative item name for some context.
@@ -177,7 +178,7 @@
     else:
         # some kind of sister/aunt
         context_frags = context.split('/')   # A, B, C, D, E
-        itemname_frags = itemname.split('/') # A, B, C, F
+        itemname_frags = itemname.split('/')  # A, B, C, F
         # first throw away common parents:
         common = 0
         for cf, pf in zip(context_frags, itemname_frags):
@@ -185,8 +186,8 @@
                 common += 1
             else:
                 break
-        context_frags = context_frags[common:] # D, E
-        itemname_frags = itemname_frags[common:] # F
+        context_frags = context_frags[common:]  # D, E
+        itemname_frags = itemname_frags[common:]  # F
         go_up = len(context_frags)
         return PARENT_PREFIX * go_up + '/'.join(itemname_frags)
 
@@ -211,14 +212,10 @@
 #############################################################################
 
 def drawing2fname(drawing):
-    config.drawing_extensions = ['.tdraw', '.adraw',
-                                 '.svg',
-                                 '.png', '.jpg', '.jpeg', '.gif',
-                                ]
     fname, ext = os.path.splitext(drawing)
     # note: do not just check for empty extension or stuff like drawing:foo.bar
     # will fail, instead of being expanded to foo.bar.tdraw
-    if ext not in config.drawing_extensions:
+    if ext not in DRAWING_EXTENSIONS:
         # for backwards compatibility, twikidraw is the default:
         drawing += '.tdraw'
     return drawing
@@ -234,19 +231,19 @@
     :returns: group letter or None
     """
     c = name[0]
-    if u'\uAC00' <= c <= u'\uD7AF': # Hangul Syllables
+    if u'\uAC00' <= c <= u'\uD7AF':  # Hangul Syllables
         return unichr(0xac00 + (int(ord(c) - 0xac00) / 588) * 588)
     else:
-        return c.upper() # we put lower and upper case words into the same index group
+        return c.upper()  # we put lower and upper case words into the same index group
 
 
-def is_URL(arg, schemes=config.uri_schemes):
+def is_URL(arg, schemes=URI_SCHEMES):
     """ Return True if arg is a URL (with a scheme given in the schemes list).
 
         Note: there are not that many requirements for generic URLs, basically
         the only mandatory requirement is the ':' between scheme and rest.
         Scheme itself could be anything, also the rest (but we only support some
-        schemes, as given in config.uri_schemes, so it is a bit less ambiguous).
+        schemes, as given in URI_SCHEMES, so it is a bit less ambiguous).
     """
     if ':' not in arg:
         return False
@@ -260,6 +257,7 @@
     """ Returns true if there is a conflict marker in the text. """
     return "/!\\ '''Edit conflict" in text
 
+
 def anchor_name_from_text(text):
     """
     Generate an anchor name from the given text.
@@ -275,6 +273,7 @@
         return 'A{0}'.format(res)
     return res
 
+
 def split_anchor(pagename):
     """
     Split a pagename that (optionally) has an anchor into the real pagename
@@ -313,7 +312,7 @@
     if app.cfg.log_reverse_dns_lookups:
         import socket
         try:
-            return unicode(socket.gethostbyaddr(addr)[0], config.charset)
+            return unicode(socket.gethostbyaddr(addr)[0], CHARSET)
         except (socket.error, UnicodeError):
             pass
 
--- a/_ui_tests/conftest.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/_ui_tests/conftest.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,6 +12,7 @@
 sys.path.append(os.path.dirname(__file__))
 import driver_register
 
+
 def pytest_runtest_makereport(item, call):
     """
     Entry point for event which occurs after each test has run
--- a/_ui_tests/driver_register.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/_ui_tests/driver_register.py	Sat Feb 16 23:21:46 2013 +0100
@@ -9,6 +9,7 @@
 
 driver = None
 
+
 def register_driver(driver_):
     """
     set the driver global variable to driver_
@@ -16,6 +17,7 @@
     global driver
     driver = driver_
 
+
 def get_driver():
     """
     get the value of the driver global variable
--- a/_ui_tests/test_subitems.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/_ui_tests/test_subitems.py	Sat Feb 16 23:21:46 2013 +0100
@@ -2,6 +2,7 @@
 # License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
 
 """Functional test: create subitem"""
+
 import config
 import utils
 
--- a/_ui_tests/utils.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/_ui_tests/utils.py	Sat Feb 16 23:21:46 2013 +0100
@@ -3,9 +3,11 @@
 # License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
 
 """Functions to facilitate functional testing"""
-import pytest
 
 import random
+import urllib
+
+import pytest
 
 try:
     from selenium import webdriver
@@ -13,7 +15,6 @@
     pytest.skip('selenium needs to be installed for this test')
 
 import config
-import urllib
 
 try:
     f = urllib.urlopen(config.BASE_URL)
@@ -31,7 +32,7 @@
     profile = webdriver.FirefoxProfile()
     profile.set_preference("intl.accept_languages", "en")
     driver = webdriver.Firefox(firefox_profile=profile)
-    driver_register.register_driver(driver) # register with
+    driver_register.register_driver(driver)  # register with
     # driver_register, which is needed so that printscreen on test
     # failure works
     driver.implicitly_wait(20)
@@ -42,7 +43,7 @@
     """
     generates a random string containing numbers, of length 'length'
     """
-    word = unicode(random.randint(10**(length-1), 10**length))
+    word = unicode(random.randint(10 ** (length - 1), 10 ** length))
     return word
 
 
--- a/contrib/pep8/DeleteTrailingSpaces.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/contrib/pep8/DeleteTrailingSpaces.py	Sat Feb 16 23:21:46 2013 +0100
@@ -12,7 +12,8 @@
 from anywhere within the contrib path.
 """
 
-import sys, os
+import sys
+import os
 import warnings
 warnings.simplefilter("once")
 
--- a/contrib/wsgi/profiler.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/contrib/wsgi/profiler.py	Sat Feb 16 23:21:46 2013 +0100
@@ -23,6 +23,7 @@
 from MoinMoin import log
 logging = log.getLogger(__name__)
 
+
 class ProfilerMiddleware(object):
     """ Abstract base class for profiling middlewares.
 
@@ -62,6 +63,7 @@
         """ Override in subclasses to clean up when server/script shuts down. """
         pass
 
+
 class CProfileMiddleware(ProfilerMiddleware):
     """ A profiler based on the the cProfile module from the standard lib. """
     def __init__(self, app, filename):
@@ -74,6 +76,7 @@
     def shutdown(self):
         self._profile.dump_stats(self._filename)
 
+
 class HotshotMiddleware(ProfilerMiddleware):
     """ A profiler based on the more recent hotshot module from the stdlib. """
     def __init__(self, app, *args, **kwargs):
@@ -85,6 +88,7 @@
     def shutdown(self):
         self._profile.close()
 
+
 class PycallgraphMiddleware(ProfilerMiddleware):
     """ A call graphing middleware utilizing the pycallgraph 3rd party
     module (available at http://pycallgraph.slowchop.com/). """
--- a/contrib/wsgi/proxy.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/contrib/wsgi/proxy.py	Sat Feb 16 23:21:46 2013 +0100
@@ -8,6 +8,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 
+
 class ProxyTrust(object):
     """
     Middleware that rewrites the remote address according to trusted
--- a/contrib/wsgi/raw_wsgi_bench.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/contrib/wsgi/raw_wsgi_bench.py	Sat Feb 16 23:21:46 2013 +0100
@@ -5,7 +5,10 @@
     @copyright: 2008 MoinMoin:FlorianKrupicka
     @license: GNU GPL, see COPYING for details.
 """
-import time, itertools, sys, os
+import time
+import itertools
+import sys
+import os
 
 from werkzeug.test import Client
 
--- a/setup.cfg	Sun Feb 10 19:31:30 2013 +0100
+++ b/setup.cfg	Sat Feb 16 23:21:46 2013 +0100
@@ -40,19 +40,25 @@
 directory = MoinMoin/translations/
 
 [pytest]
+# Note: we need pytest-pep8 >= 1.0.4 to make pep8maxlinelength work, but that
+# needs a pytest >= 2.3, so, we can't use that until our test work with that.
+#pep8maxlinelength = 120
 norecursedirs = .hg _build tmp* env* dlc wiki
 minversion = 2.0
 pep8ignore =
  *.py E121 E122 E123 E124 E125 E126 E127 E128  # continuation line indentation
- *.py E225  # missing whitespace around operator
- *.py E226  # missing optional whitespace around operator
- *.py E261  # less than 2 blanks before inline comment
- *.py E301 E302  # separate toplevel definitions with 2 empty lines, method defs inside class by 1 empty line
- *.py E401  # imports on separate lines
- *.py E501  # maximum line length (default 79 chars)
+ *.py E501  # maximum line length (see also pep8maxlinelength)
+ */_tests/*.py E225 E226  # missing whitespace / missing optional whitespace around operator
+ */_tests/*.py E261  # less than 2 blanks before inline comment
+ */_tests/*.py E301 E302  # separate toplevel definitions with 2 empty lines, method defs inside class by 1 empty line
+ */_tests/*.py E401  # imports on separate lines
+ wikiconfig_*.py ALL  # local stuff, not in the repo
+ MoinMoin/config/default.py E501  # maximum line length (long lines expected there)
+ MoinMoin/util/_tests/test_paramparser.py E241 # whitespace around comma (we have some "tabular" formatting there)
+ MoinMoin/constants/chartypes.py E501  # auto-generated, long lines
+ MoinMoin/script/migration/moin19/_logfile19.py ALL  # legacy code "as is"
+ MoinMoin/script/migration/moin19/_utils19.py ALL  # legacy code "as is"
+ docs/conf.py ALL  # sphinx stuff, automatically generated, don't check this
  upload.py ALL  # 3rd party (and not in the repo): rietveld upload tool
- wikiconfig_*.py ALL  # local stuff, not in the repo
- docs/conf.py ALL  # sphinx stuff, automatically generated, don't check this
- MoinMoin/util/md5crypt.py ALL  # 3rd party stuff, don't check this
- MoinMoin/util/_tests/test_paramparser.py E241 # whitespace around comma (we have some "tabular" formatting there)
+ MoinMoin/util/SubProcess.py ALL  # 3rd party stuff, patched stdlib code
 
--- a/setup.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/setup.py	Sat Feb 16 23:21:46 2013 +0100
@@ -3,7 +3,8 @@
 # Copyright: 2001-2012 MoinMoin:ThomasWaldmann
 # License: GNU GPL v2 (or any later version), see LICENSE.txt for details.
 
-import sys, os
+import sys
+import os
 
 from MoinMoin import project, version
 
@@ -80,29 +81,29 @@
         'https://bitbucket.org/thomaswaldmann/emeraldtree/get/tip.tar.gz#egg=emeraldtree-0.9.2',
     ],
     install_requires=[
-        'blinker>=1.1', # event signalling (e.g. for change notification trigger)
-        'docutils>=0.8.1', # reST markup processing
-        'Markdown>=2.1.1', # Markdown markup processing
-        'Flask>=0.8', # micro framework
-        'Flask-Babel>=0.7', # i18n support
-        'Flask-Cache>=0.3.4', # caching support
-        'Flask-Script>=0.3.3', # scripting support
-        'Flask-Themes>=0.1.3.1', # theme support
-        'emeraldtree>=0.9.2', # xml processing
-        'flatland==dev', # repo checkout at revision 269:6c5d262d7eff works
-        'Jinja2>=2.6', # template engine
-        'pygments>=1.4', # src code / text file highlighting
-        'Werkzeug>=0.8.1', # wsgi toolkit
-        'pytest>=2.1, <2.3', # pytest is needed by unit tests
-                             # note: currently 2.3.x is not compatible with our test code,
-                             # likely due to the fixtures changes.
-        'pytest-pep8<1.0.3', # coding style checker
-                             # note: pytest-pep8 1.0.3 needs pytest 2.3
-        'whoosh>=2.4.0', # needed for indexed search
-        'sphinx>=1.1', # needed to build the docs
-        'pdfminer', # pdf -> text/plain conversion
-        'passlib>=1.6.0', # strong password hashing (1.6 needed for consteq)
-        'XStatic>=0.0.2', # support for static file pypi packages
+        'blinker>=1.1',  # event signalling (e.g. for change notification trigger)
+        'docutils>=0.8.1',  # reST markup processing
+        'Markdown>=2.1.1',  # Markdown markup processing
+        'Flask>=0.8',  # micro framework
+        'Flask-Babel>=0.7',  # i18n support
+        'Flask-Cache>=0.3.4',  # caching support
+        'Flask-Script>=0.3.3',  # scripting support
+        'Flask-Themes>=0.1.3.1',  # theme support
+        'emeraldtree>=0.9.2',  # xml processing
+        'flatland==dev',  # repo checkout at revision 269:6c5d262d7eff works
+        'Jinja2>=2.6',  # template engine
+        'pygments>=1.4',  # src code / text file highlighting
+        'Werkzeug>=0.8.1',  # wsgi toolkit
+        'pytest>=2.1, <2.3',  # pytest is needed by unit tests
+                              # note: currently 2.3.x is not compatible with our test code,
+                              # likely due to the fixtures changes.
+        'pytest-pep8<1.0.3',  # coding style checker
+                              # note: pytest-pep8 1.0.3 needs pytest 2.3
+        'whoosh>=2.4.0',  # needed for indexed search
+        'sphinx>=1.1',  # needed to build the docs
+        'pdfminer',  # pdf -> text/plain conversion
+        'passlib>=1.6.0',  # strong password hashing (1.6 needed for consteq)
+        'XStatic>=0.0.2',  # support for static file pypi packages
         'XStatic-CKEditor>=3.6.1.2',
         'XStatic-jQuery>=1.8.2',
         'XStatic-jQuery-File-Upload>=4.4.2',
@@ -115,14 +116,14 @@
     # optional features and their list of requirements
     extras_require={
         #'featurename': ["req1", "req2", ],
-        'pil': ["PIL"], # used by image get for scaling/rotating/etc.
-                        # PIL is a binary dependency and some features of it
-                        # require special libs/header to be installed before
-                        # it can be compiled successfully
-        'ldap': ["python-ldap>=2.0.0"], # used by ldap auth
-        'openid': ["python-openid>=2.2.4"], # used by openid rp auth
-        'sqla': ["sqlalchemy>=0.7.1"], # used by sqla store
-        'mongodb': ["pymongo"], # used by mongodb store
+        'pil': ["PIL"],  # used by image get for scaling/rotating/etc.
+                         # PIL is a binary dependency and some features of it
+                         # require special libs/header to be installed before
+                         # it can be compiled successfully
+        'ldap': ["python-ldap>=2.0.0"],  # used by ldap auth
+        'openid': ["python-openid>=2.2.4"],  # used by openid rp auth
+        'sqla': ["sqlalchemy>=0.7.1"],  # used by sqla store
+        'mongodb': ["pymongo"],  # used by mongodb store
     },
     entry_points=dict(
         console_scripts=['moin = MoinMoin.script:main'],
--- a/wikiconfig.py	Sun Feb 10 19:31:30 2013 +0100
+++ b/wikiconfig.py	Sat Feb 16 23:21:46 2013 +0100
@@ -25,7 +25,7 @@
     #          intermap.txt
     # If that's not true, feel free to adjust the pathes.
     instance_dir = os.path.join(wikiconfig_dir, 'wiki')
-    data_dir = os.path.join(instance_dir, 'data') # Note: this used to have a trailing / in the past
+    data_dir = os.path.join(instance_dir, 'data')  # Note: this used to have a trailing / in the past
     index_storage = 'FileStorage', (os.path.join(instance_dir, "index"), ), {}
 
     # This provides a simple default setup for your backend configuration.
@@ -76,7 +76,7 @@
         serve_files.update([(xs.name, xs.base_dir)])
 
 
-MOINCFG = Config # Flask only likes uppercase stuff
+MOINCFG = Config  # Flask only likes uppercase stuff
 # Flask settings - see the flask documentation about their meaning
 SECRET_KEY = 'you need to change this so it is really secret'
 #DEBUG = False # use True for development only, not for public sites!