changeset 5659:41fc338a810f

Merge stable
author Mads Kiilerich <madski@unity3d.com>
date Wed, 20 Jan 2016 01:41:02 +0100
parents 6af24662e4a7 (diff) dba6c44f0a30 (current diff)
children 072175b07608
files
diffstat 170 files changed, 2976 insertions(+), 2374 deletions(-) [+]
line wrap: on
line diff
--- a/CONTRIBUTORS	Fri Jan 15 14:55:27 2016 +0000
+++ b/CONTRIBUTORS	Wed Jan 20 01:41:02 2016 +0100
@@ -22,6 +22,7 @@
     Étienne Gilli <etienne.gilli@gmail.com> 2015
     Grzegorz Krason <grzegorz.krason@gmail.com> 2015
     Jan Heylen <heyleke@gmail.com> 2015
+    Jiří Suchan <yed@vanyli.net> 2015
     Kazunari Kobayashi <kobanari@nifty.com> 2015
     Kevin Bullock <kbullock@ringworld.org> 2015
     kobanari <kobanari@nifty.com> 2015
--- a/README.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/README.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -172,7 +172,7 @@
 - convert the database in a one-time step
 
 Maintaining interoperability
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Interoperability with RhodeCode 2.2.X installations is provided so you don't
 have to immediately commit to switching to Kallithea. This option will most
@@ -191,7 +191,7 @@
 ``$VIRTUAL_ENV/lib/python2.7/site-packages/Kallithea-0.1-py2.7.egg/kallithea``.
 
 One-time conversion
-~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^
 
 Alternatively, if you would like to convert the database for good, you can use
 a helper script provided by Kallithea. This script will operate directly on the
@@ -209,7 +209,7 @@
    above, watch out for stray brand.pyc after removing brand.py.
 
 Git hooks
-~~~~~~~~~
+^^^^^^^^^
 
 After switching to Kallithea, it will be necessary to update the Git_ hooks in
 your repositories. If not, the Git_ hooks from RhodeCode will still be called,
--- a/development.ini	Fri Jan 15 14:55:27 2016 +0000
+++ b/development.ini	Wed Jan 20 01:41:02 2016 +0100
@@ -163,6 +163,7 @@
 #cheaper-step = 1
 
 ## COMMON ##
+#host = 127.0.0.1
 host = 0.0.0.0
 port = 5000
 
@@ -280,12 +281,6 @@
 #issue_server_link_wiki = https://wiki.example.com/{id}
 #issue_prefix_wiki = WIKI-
 
-## instance-id prefix
-## a prefix key for this instance used for cache invalidation when running
-## multiple instances of kallithea, make sure it's globally unique for
-## all running kallithea instances. Leave empty if you don't use it
-instance_id =
-
 ## alternative return HTTP header for failed authentication. Default HTTP
 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 ## handling that. Set this variable to 403 to return HTTPForbidden
@@ -301,6 +296,18 @@
 ## allows to setup custom hooks in settings page
 allow_custom_hooks_settings = True
 
+## extra extensions for indexing, space separated and without the leading '.'.
+# index.extensions =
+#    gemfile
+#    lock
+
+## extra filenames for indexing, space separated
+# index.filenames =
+#    .dockerignore
+#    .editorconfig
+#    INSTALL
+#    CHANGELOG
+
 ####################################
 ###        CELERY CONFIG        ####
 ####################################
@@ -486,13 +493,12 @@
 #sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
 
 # MySQL
-#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
+#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea?charset=utf8
 
 # see sqlalchemy docs for others
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
@@ -560,16 +566,16 @@
 class = StreamHandler
 args = (sys.stderr,)
 #level = INFO
+level = DEBUG
 #formatter = generic
-level = DEBUG
 formatter = color_formatter
 
 [handler_console_sql]
 class = StreamHandler
 args = (sys.stderr,)
 #level = WARN
+level = DEBUG
 #formatter = generic
-level = DEBUG
 formatter = color_formatter_sql
 
 ################
--- a/docs/api/api.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/api/api.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -10,7 +10,7 @@
 
 
 API access for web views
-++++++++++++++++++++++++
+------------------------
 
 API access can also be turned on for each web view in Kallithea that is
 decorated with the ``@LoginRequired`` decorator. Some views use
@@ -36,7 +36,7 @@
 
 
 API access
-++++++++++
+----------
 
 Clients must send JSON encoded JSON-RPC requests::
 
@@ -76,7 +76,7 @@
 
 
 API client
-++++++++++
+----------
 
 Kallithea comes with a ``kallithea-api`` command line tool, providing a convenient
 way to call the JSON-RPC API.
@@ -110,11 +110,11 @@
 
 
 API methods
-+++++++++++
+-----------
 
 
 pull
-----
+^^^^
 
 Pull the given repo from remote location. Can be used to automatically keep
 remote repos up to date.
@@ -136,7 +136,7 @@
     error :  null
 
 rescan_repos
-------------
+^^^^^^^^^^^^
 
 Rescan repositories. If ``remove_obsolete`` is set,
 Kallithea will delete repos that are in the database but not in the filesystem.
@@ -159,7 +159,7 @@
     error :  null
 
 invalidate_cache
-----------------
+^^^^^^^^^^^^^^^^
 
 Invalidate the cache for a repository.
 This command can only be executed using the api_key of a user with admin rights,
@@ -181,7 +181,7 @@
     error :  null
 
 lock
-----
+^^^^
 
 Set the locking state on the given repository by the given user.
 If the param ``userid`` is skipped, it is set to the ID of the user who is calling this method.
@@ -212,7 +212,7 @@
     error :  null
 
 get_ip
-------
+^^^^^^
 
 Return IP address as seen from Kallithea server, together with all
 defined IP addresses for given user.
@@ -244,7 +244,7 @@
     error :  null
 
 get_user
---------
+^^^^^^^^
 
 Get a user by username or userid. The result is empty if user can't be found.
 If userid param is skipped, it is set to id of user who is calling this method.
@@ -288,7 +288,7 @@
     error:  null
 
 get_users
----------
+^^^^^^^^^
 
 List all existing users.
 This command can only be executed using the api_key of a user with admin rights.
@@ -325,7 +325,7 @@
 .. _create-user:
 
 create_user
------------
+^^^^^^^^^^^
 
 Create new user.
 This command can only be executed using the api_key of a user with admin rights.
@@ -371,7 +371,7 @@
     kallithea-api create_user username:bent email:bent@example.com firstname:Bent lastname:Bentsen extern_type:ldap extern_name:uid=bent,dc=example,dc=com
 
 update_user
------------
+^^^^^^^^^^^
 
 Update the given user if such user exists.
 This command can only be executed using the api_key of a user with admin rights.
@@ -415,7 +415,7 @@
     error:  null
 
 delete_user
------------
+^^^^^^^^^^^
 
 Delete the given user if such a user exists.
 This command can only be executed using the api_key of a user with admin rights.
@@ -439,7 +439,7 @@
     error:  null
 
 get_user_group
---------------
+^^^^^^^^^^^^^^
 
 Get an existing user group.
 This command can only be executed using the api_key of a user with admin rights.
@@ -481,7 +481,7 @@
     error : null
 
 get_user_groups
----------------
+^^^^^^^^^^^^^^^
 
 List all existing user groups.
 This command can only be executed using the api_key of a user with admin rights.
@@ -507,7 +507,7 @@
     error : null
 
 create_user_group
------------------
+^^^^^^^^^^^^^^^^^
 
 Create a new user group.
 This command can only be executed using the api_key of a user with admin rights.
@@ -537,7 +537,7 @@
     error:  null
 
 add_user_to_user_group
-----------------------
+^^^^^^^^^^^^^^^^^^^^^^
 
 Adds a user to a user group. If the user already is in that group, success will be
 ``false``.
@@ -564,7 +564,7 @@
     error:  null
 
 remove_user_from_user_group
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Remove a user from a user group. If the user isn't in the given group, success will
 be ``false``.
@@ -591,7 +591,7 @@
     error:  null
 
 get_repo
---------
+^^^^^^^^
 
 Get an existing repository by its name or repository_id. Members will contain
 either users_group or users associated to that repository.
@@ -680,7 +680,7 @@
     error:  null
 
 get_repos
----------
+^^^^^^^^^
 
 List all existing repositories.
 This command can only be executed using the api_key of a user with admin rights,
@@ -717,7 +717,7 @@
     error:  null
 
 get_repo_nodes
---------------
+^^^^^^^^^^^^^^
 
 Return a list of files and directories for a given path at the given revision.
 It is possible to specify ret_type to show only ``files`` or ``dirs``.
@@ -748,7 +748,7 @@
     error:  null
 
 create_repo
------------
+^^^^^^^^^^^
 
 Create a repository. If the repository name contains "/", all needed repository
 groups will be created. For example "foo/bar/baz" will create repository groups
@@ -800,7 +800,7 @@
     error:  null
 
 update_repo
------------
+^^^^^^^^^^^
 
 Update a repository.
 This command can only be executed using the api_key of a user with admin rights,
@@ -860,7 +860,7 @@
     error:  null
 
 fork_repo
----------
+^^^^^^^^^
 
 Create a fork of the given repo. If using Celery, this will
 return success message immediately and a fork will be created
@@ -896,7 +896,7 @@
     error:  null
 
 delete_repo
------------
+^^^^^^^^^^^
 
 Delete a repository.
 This command can only be executed using the api_key of a user with admin rights,
@@ -923,7 +923,7 @@
     error:  null
 
 grant_user_permission
----------------------
+^^^^^^^^^^^^^^^^^^^^^
 
 Grant permission for a user on the given repository, or update the existing one if found.
 This command can only be executed using the api_key of a user with admin rights.
@@ -949,7 +949,7 @@
     error:  null
 
 revoke_user_permission
-----------------------
+^^^^^^^^^^^^^^^^^^^^^^
 
 Revoke permission for a user on the given repository.
 This command can only be executed using the api_key of a user with admin rights.
@@ -974,7 +974,7 @@
     error:  null
 
 grant_user_group_permission
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Grant permission for a user group on the given repository, or update the
 existing one if found.
@@ -1001,7 +1001,7 @@
     error:  null
 
 revoke_user_group_permission
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Revoke permission for a user group on the given repository.
 This command can only be executed using the api_key of a user with admin rights.
--- a/docs/index.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/index.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -63,7 +63,7 @@
 
 
 Other topics
-------------
+************
 
 * :ref:`genindex`
 * :ref:`search`
--- a/docs/installation_iis.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/installation_iis.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -28,7 +28,7 @@
 own virtual folder will be noted where appropriate.
 
 Application pool
-................
+^^^^^^^^^^^^^^^^
 
 Make sure that there is a unique application pool for the Kallithea application
 with an identity that has read access to the Kallithea distribution.
@@ -44,7 +44,7 @@
     as long as the Kallithea requirements are met by the existing pool.
 
 ISAPI handler
-.............
+^^^^^^^^^^^^^
 
 The ISAPI handler can be generated using::
 
@@ -68,7 +68,7 @@
 site will be processed through this logic henceforth.
 
 Authentication with Kallithea using IIS authentication modules
-..............................................................
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The recommended way to handle authentication with Kallithea using IIS is to let
 IIS handle all the authentication and just pass it to Kallithea.
--- a/docs/installation_win.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/installation_win.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -6,7 +6,7 @@
 
 
 First time install
-::::::::::::::::::
+------------------
 
 Target OS: Windows 7 and newer or Windows Server 2008 R2 and newer
 
@@ -15,7 +15,7 @@
 To install on an older version of Windows, see `<installation_win_old.html>`_
 
 Step 1 -- Install Python
-------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 Install Python 2.x.y (x = 6 or 7). Latest version is recommended. If you need another version, they can run side by side.
 
@@ -31,7 +31,7 @@
 be needed in the next step. In this case, it is "2.7".
 
 Step 2 -- Python BIN
---------------------
+^^^^^^^^^^^^^^^^^^^^
 
 Add Python BIN folder to the path. This can be done manually (editing
 "PATH" environment variable) or by using Windows Support Tools that
@@ -45,7 +45,7 @@
 path. Typically this is ``C:\\Python27``.
 
 Step 3 -- Install pywin32 extensions
-------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Download pywin32 from:
 http://sourceforge.net/projects/pywin32/files/
@@ -61,7 +61,7 @@
   (Win32)
 
 Step 4 -- Install pip
----------------------
+^^^^^^^^^^^^^^^^^^^^^
 
 pip is a package management system for Python. You will need it to install Kallithea and its dependencies.
 
@@ -85,7 +85,7 @@
   SETX PATH "%PATH%;[your-python-path]\Scripts" /M
 
 Step 5 -- Kallithea folder structure
-------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Create a Kallithea folder structure.
 
@@ -102,7 +102,7 @@
   C:\Kallithea\Repos
 
 Step 6 -- Install virtualenv
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. note::
    A python virtual environment will allow for isolation between the Python packages of your system and those used for Kallithea.
@@ -119,7 +119,7 @@
   virtualenv C:\Kallithea\Env
 
 Step 7 -- Install Kallithea
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 In order to install Kallithea, you need to be able to run "pip install kallithea". It will use pip to install the Kallithea Python package and its dependencies.
 Some Python packages use managed code and need to be compiled.
@@ -146,7 +146,7 @@
           normal.
 
 Step 8 -- Install git (optional)
---------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Mercurial being a python package, it was installed automatically when doing "pip install kallithea".
 
@@ -155,7 +155,7 @@
 See http://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows for instructions.
 
 Step 9 -- Configuring Kallithea
--------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Steps taken from `<setup.html>`_
 
@@ -194,7 +194,7 @@
 If you decided not to install git, you will get errors about it that you can ignore.
 
 Step 10 -- Running Kallithea
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 In the previous command prompt, being in the C:\\Kallithea\\Bin folder, type::
 
@@ -222,7 +222,7 @@
 
 
 Upgrading
-:::::::::
+---------
 
 Stop running Kallithea
 Open a CommandPrompt like in Step 7 (cd to C:\Kallithea\Env\Scripts and activate) and type::
--- a/docs/installation_win_old.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/installation_win_old.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -6,7 +6,7 @@
 
 
 First-time install
-::::::::::::::::::
+------------------
 
 Target OS: Windows XP SP3 32-bit English (Clean installation)
 + All Windows Updates until 24-may-2012
@@ -24,7 +24,7 @@
    - http://bugs.python.org/issue7511
 
 Step 1 -- Install Visual Studio 2008 Express
---------------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Optional: You can also install MinGW, but VS2008 installation is easier.
 
@@ -58,7 +58,7 @@
    Copy C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat to C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat
 
 Step 2 -- Install Python
-------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 Install Python 2.x.y (x = 6 or 7) x86 version (32-bit). DO NOT USE A 3.x version.
 Download Python 2.x.y from:
@@ -74,7 +74,7 @@
    64-bit: Just download and install the 64-bit version of python.
 
 Step 3 -- Install Win32py extensions
-------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Download pywin32 from:
 http://sourceforge.net/projects/pywin32/files/
@@ -93,7 +93,7 @@
      http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
 
 Step 4 -- Python BIN
---------------------
+^^^^^^^^^^^^^^^^^^^^
 
 Add Python BIN folder to the path
 
@@ -120,7 +120,7 @@
   Typically: C:\\Python27
 
 Step 5 -- Kallithea folder structure
-------------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Create a Kallithea folder structure
 
@@ -137,7 +137,7 @@
   C:\Kallithea\Repos
 
 Step 6 -- Install virtualenv
-----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Install Virtual Env for Python
 
@@ -157,7 +157,7 @@
 to include it)
 
 Step 7 -- Install Kallithea
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Finally, install Kallithea
 
@@ -195,7 +195,7 @@
 Some warnings will appear, don't worry as they are normal.
 
 Step 8 -- Configuring Kallithea
--------------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 steps taken from http://packages.python.org/Kallithea/setup.html
 
@@ -233,7 +233,7 @@
 it again.
 
 Step 9 -- Running Kallithea
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 In the previous command prompt, being in the C:\\Kallithea\\Bin folder,
 just type::
@@ -263,7 +263,7 @@
 
 
 Upgrading
-:::::::::
+---------
 
 Stop running Kallithea
 Open a CommandPrompt like in Step7 (VS2008 path + activate) and type::
--- a/docs/setup.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/setup.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -346,7 +346,7 @@
 will be saved there.
 
 Active Directory
-''''''''''''''''
+^^^^^^^^^^^^^^^^
 
 Kallithea can use Microsoft Active Directory for user authentication.  This
 is done through an LDAP or LDAPS connection to Active Directory.  The
@@ -383,7 +383,7 @@
 permissions before the user logs in for the first time, using the :ref:`create-user` API.
 
 Container-based authentication
-''''''''''''''''''''''''''''''
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 In a container-based authentication setup, Kallithea reads the user name from
 the ``REMOTE_USER`` server variable provided by the WSGI container.
@@ -393,7 +393,7 @@
 Kallithea.
 
 Proxy pass-through authentication
-'''''''''''''''''''''''''''''''''
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 In a proxy pass-through authentication setup, Kallithea reads the user name
 from the ``X-Forwarded-User`` request header, which should be configured to be
@@ -427,6 +427,74 @@
       RequestHeader set X-Forwarded-User %{RU}e
     </Location>
 
+Setting metadata in container/reverse-proxy
+'''''''''''''''''''''''''''''''''''''''''''
+
+When a new user account is created on the first login, Kallithea has no information about
+the user's email and full name. So you can set some additional request headers like in the
+example below. In this example the user is authenticated via Kerberos and an Apache
+mod_python fixup handler is used to get the user information from a LDAP server. But you
+could set the request headers however you want.
+
+.. code-block:: apache
+
+    <Location /someprefix>
+      ProxyPass http://127.0.0.1:5000/someprefix
+      ProxyPassReverse http://127.0.0.1:5000/someprefix
+      SetEnvIf X-Url-Scheme https HTTPS=1
+
+      AuthName "Kerberos Login"
+      AuthType Kerberos
+      Krb5Keytab /etc/apache2/http.keytab
+      KrbMethodK5Passwd off
+      KrbVerifyKDC on
+      Require valid-user
+
+      PythonFixupHandler ldapmetadata
+
+      RequestHeader set X_REMOTE_USER %{X_REMOTE_USER}e
+      RequestHeader set X_REMOTE_EMAIL %{X_REMOTE_EMAIL}e
+      RequestHeader set X_REMOTE_FIRSTNAME %{X_REMOTE_FIRSTNAME}e
+      RequestHeader set X_REMOTE_LASTNAME %{X_REMOTE_LASTNAME}e
+    </Location>
+
+.. code-block:: python
+
+    from mod_python import apache
+    import ldap
+
+    LDAP_SERVER = "ldap://server.mydomain.com:389"
+    LDAP_USER = ""
+    LDAP_PASS = ""
+    LDAP_ROOT = "dc=mydomain,dc=com"
+    LDAP_FILTER = "sAMAcountName=%s"
+    LDAP_ATTR_LIST = ['sAMAcountName','givenname','sn','mail']
+
+    def fixuphandler(req):
+        if req.user is None:
+            # no user to search for
+            return apache.OK
+        else:
+            try:
+                if('\\' in req.user):
+                    username = req.user.split('\\')[1]
+                elif('@' in req.user):
+                    username = req.user.split('@')[0]
+                else:
+                    username = req.user
+                l = ldap.initialize(LDAP_SERVER)
+                l.simple_bind_s(LDAP_USER, LDAP_PASS)
+                r = l.search_s(LDAP_ROOT, ldap.SCOPE_SUBTREE, LDAP_FILTER % username, attrlist=LDAP_ATTR_LIST)
+
+                req.subprocess_env['X_REMOTE_USER'] = username
+                req.subprocess_env['X_REMOTE_EMAIL'] = r[0][1]['mail'][0].lower()
+                req.subprocess_env['X_REMOTE_FIRSTNAME'] = "%s" % r[0][1]['givenname'][0]
+                req.subprocess_env['X_REMOTE_LASTNAME'] = "%s" % r[0][1]['sn'][0]
+            except Exception, e:
+                apache.log_error("error getting data from ldap %s" % str(e), apache.APLOG_ERR)
+
+            return apache.OK
+
 .. note::
    If you enable proxy pass-through authentication, make sure your server is
    only accessible through the proxy. Otherwise, any client would be able to
@@ -746,11 +814,6 @@
    When running apache as root, please make sure it doesn't run Kallithea as
    root, for examply by adding: ``user=www-data group=www-data`` to the configuration.
 
-.. note::
-   If running Kallithea in multiprocess mode,
-   make sure you set ``instance_id = *`` in the configuration so each process
-   gets it's own cache invalidation key.
-
 Example WSGI dispatch script:
 
 .. code-block:: python
--- a/docs/usage/general.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/usage/general.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -151,7 +151,7 @@
 features that merit further explanation.
 
 Repository extra fields
-~~~~~~~~~~~~~~~~~~~~~~~
+^^^^^^^^^^^^^^^^^^^^^^^
 
 In the *Visual* tab, there is an option "Use repository extra
 fields", which allows to set custom fields for each repository in the system.
@@ -165,7 +165,7 @@
 Newly created fields are accessible via the API.
 
 Meta tagging
-~~~~~~~~~~~~
+^^^^^^^^^^^^
 
 In the *Visual* tab, option "Stylify recognised meta tags" will cause Kallithea
 to turn certain text fragments in repository and repository group
--- a/docs/usage/performance.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/usage/performance.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -38,7 +38,6 @@
     scaled horizontally on one (recommended) or multiple machines. In order
     to scale horizontally you need to do the following:
 
-    - Each instance needs its own .ini file and unique ``instance_id`` set.
     - Each instance's ``data`` storage needs to be configured to be stored on a
       shared disk storage, preferably together with repositories. This ``data``
       dir contains template caches, sessions, whoosh index and is used for
--- a/docs/usage/vcs_support.rst	Fri Jan 15 14:55:27 2016 +0000
+++ b/docs/usage/vcs_support.rst	Wed Jan 20 01:41:02 2016 +0100
@@ -23,7 +23,7 @@
 
 
 Web server with chunked encoding
-````````````````````````````````
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Large Git pushes require an HTTP server with support for
 chunked encoding for POST. The Python web servers waitress_ and
@@ -51,7 +51,7 @@
 
 
 Working with Mercurial subrepositories
-``````````````````````````````````````
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 This section explains how to use Mercurial subrepositories_ in Kallithea.
 
--- a/kallithea/bin/template.ini.mako	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/bin/template.ini.mako	Wed Jan 20 01:41:02 2016 +0100
@@ -278,12 +278,6 @@
 #issue_server_link_wiki = https://wiki.example.com/{id}
 #issue_prefix_wiki = WIKI-
 
-<%text>## instance-id prefix</%text>
-<%text>## a prefix key for this instance used for cache invalidation when running</%text>
-<%text>## multiple instances of kallithea, make sure it's globally unique for</%text>
-<%text>## all running kallithea instances. Leave empty if you don't use it</%text>
-instance_id =
-
 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
 <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
@@ -299,6 +293,18 @@
 <%text>## allows to setup custom hooks in settings page</%text>
 allow_custom_hooks_settings = True
 
+<%text>## extra extensions for indexing, space separated and without the leading '.'.</%text>
+# index.extensions =
+#    gemfile
+#    lock
+
+<%text>## extra filenames for indexing, space separated</%text>
+# index.filenames =
+#    .dockerignore
+#    .editorconfig
+#    INSTALL
+#    CHANGELOG
+
 <%text>####################################</%text>
 <%text>###        CELERY CONFIG        ####</%text>
 <%text>####################################</%text>
@@ -489,14 +495,13 @@
 
 %elif database_engine == 'mysql':
 # MySQL
-sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
+sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea?charset=utf8
 
 %endif
 # see sqlalchemy docs for others
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.db1.convert_unicode = true
 
 <%text>################################</%text>
 <%text>### LOGGING CONFIGURATION   ####</%text>
--- a/kallithea/config/conf.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/config/conf.py	Wed Jan 20 01:41:02 2016 +0100
@@ -25,19 +25,21 @@
 :license: GPLv3, see LICENSE.md for more details.
 """
 
-from kallithea.lib.utils2 import __get_lem
+from kallithea.lib.utils2 import __get_lem, __get_index_filenames
 
 
 # language map is also used by whoosh indexer, which for those specified
 # extensions will index it's content
 LANGUAGES_EXTENSIONS_MAP = __get_lem()
 
-#==============================================================================
-# WHOOSH INDEX EXTENSIONS
-#==============================================================================
-# EXTENSIONS WE WANT TO INDEX CONTENT OFF USING WHOOSH
+# Whoosh index targets
+
+# Extensions we want to index content of using whoosh
 INDEX_EXTENSIONS = LANGUAGES_EXTENSIONS_MAP.keys()
 
+# Filenames we want to index content of using whoosh
+INDEX_FILENAMES = __get_index_filenames()
+
 # list of readme files to search in file tree and display in summary
 # attached weights defines the search  order lower is first
 ALL_READMES = [
--- a/kallithea/config/deployment.ini_tmpl	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/config/deployment.ini_tmpl	Wed Jan 20 01:41:02 2016 +0100
@@ -274,12 +274,6 @@
 #issue_server_link_wiki = https://wiki.example.com/{id}
 #issue_prefix_wiki = WIKI-
 
-## instance-id prefix
-## a prefix key for this instance used for cache invalidation when running
-## multiple instances of kallithea, make sure it's globally unique for
-## all running kallithea instances. Leave empty if you don't use it
-instance_id =
-
 ## alternative return HTTP header for failed authentication. Default HTTP
 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 ## handling that. Set this variable to 403 to return HTTPForbidden
@@ -295,6 +289,18 @@
 ## allows to setup custom hooks in settings page
 allow_custom_hooks_settings = True
 
+## extra extensions for indexing, space separated and without the leading '.'.
+# index.extensions =
+#    gemfile
+#    lock
+
+## extra filenames for indexing, space separated
+# index.filenames =
+#    .dockerignore
+#    .editorconfig
+#    INSTALL
+#    CHANGELOG
+
 ####################################
 ###        CELERY CONFIG        ####
 ####################################
@@ -479,13 +485,12 @@
 #sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
 
 # MySQL
-#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
+#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea?charset=utf8
 
 # see sqlalchemy docs for others
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
--- a/kallithea/config/environment.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/config/environment.py	Wed Jan 20 01:41:02 2016 +0100
@@ -33,8 +33,8 @@
 
 from kallithea.lib import helpers
 from kallithea.lib.auth import set_available_permissions
-from kallithea.lib.utils import repo2db_mapper, make_ui, set_app_settings,\
-    load_rcextensions, check_git_version, set_vcs_config
+from kallithea.lib.utils import repo2db_mapper, make_ui, set_app_settings, \
+    load_rcextensions, check_git_version, set_vcs_config, set_indexer_config
 from kallithea.lib.utils2 import engine_from_config, str2bool
 from kallithea.lib.db_manage import DbManage
 from kallithea.model import init_model
@@ -118,7 +118,7 @@
     config['base_path'] = repos_path
     set_app_settings(config)
 
-    instance_id = kallithea.CONFIG.get('instance_id')
+    instance_id = kallithea.CONFIG.get('instance_id', '*')
     if instance_id == '*':
         instance_id = '%s-%s' % (platform.uname()[1], os.getpid())
         kallithea.CONFIG['instance_id'] = instance_id
@@ -130,6 +130,7 @@
     # pylons
     kallithea.CONFIG.update(config)
     set_vcs_config(kallithea.CONFIG)
+    set_indexer_config(kallithea.CONFIG)
 
     #check git version
     check_git_version()
--- a/kallithea/controllers/admin/admin.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/admin.py	Wed Jan 20 01:41:02 2016 +0100
@@ -125,8 +125,8 @@
 
     @HasPermissionAllDecorator('hg.admin')
     def index(self):
-        users_log = UserLog.query()\
-                .options(joinedload(UserLog.user))\
+        users_log = UserLog.query() \
+                .options(joinedload(UserLog.user)) \
                 .options(joinedload(UserLog.repository))
 
         #FILTERING
--- a/kallithea/controllers/admin/auth_settings.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/auth_settings.py	Wed Jan 20 01:41:02 2016 +0100
@@ -28,8 +28,8 @@
 import traceback
 
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from kallithea.lib import helpers as h
 from kallithea.lib.compat import formatted_json
@@ -146,4 +146,4 @@
             h.flash(_('error occurred during update of auth settings'),
                     category='error')
 
-        return redirect(url('auth_home'))
+        raise HTTPFound(location=url('auth_home'))
--- a/kallithea/controllers/admin/defaults.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/defaults.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,8 +31,8 @@
 from formencode import htmlfill
 
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator
@@ -112,7 +112,7 @@
             h.flash(_('Error occurred during update of defaults'),
                     category='error')
 
-        return redirect(url('defaults'))
+        raise HTTPFound(location=url('defaults'))
 
     def delete(self, id):
         """DELETE /defaults/id: Delete an existing item"""
--- a/kallithea/controllers/admin/gists.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/gists.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,8 +31,8 @@
 import formencode.htmlfill
 
 from pylons import request, response, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound, HTTPNotFound, HTTPForbidden
 
 from kallithea.model.forms import GistForm
 from kallithea.model.gist import GistModel
@@ -44,7 +44,6 @@
 from kallithea.lib.utils import jsonify
 from kallithea.lib.utils2 import safe_int, safe_unicode, time_to_datetime
 from kallithea.lib.helpers import Page
-from webob.exc import HTTPNotFound, HTTPForbidden
 from sqlalchemy.sql.expression import or_
 from kallithea.lib.vcs.exceptions import VCSError, NodeNotChangedError
 
@@ -70,27 +69,27 @@
     def index(self):
         """GET /admin/gists: All items in the collection"""
         # url('gists')
-        not_default_user = c.authuser.username != User.DEFAULT_USER
+        not_default_user = not c.authuser.is_default_user
         c.show_private = request.GET.get('private') and not_default_user
         c.show_public = request.GET.get('public') and not_default_user
 
-        gists = Gist().query()\
-            .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
+        gists = Gist().query() \
+            .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time())) \
             .order_by(Gist.created_on.desc())
 
         # MY private
         if c.show_private and not c.show_public:
-            gists = gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\
+            gists = gists.filter(Gist.gist_type == Gist.GIST_PRIVATE) \
                              .filter(Gist.gist_owner == c.authuser.user_id)
         # MY public
         elif c.show_public and not c.show_private:
-            gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\
+            gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) \
                              .filter(Gist.gist_owner == c.authuser.user_id)
 
         # MY public+private
         elif c.show_private and c.show_public:
             gists = gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC,
-                                     Gist.gist_type == Gist.GIST_PRIVATE))\
+                                     Gist.gist_type == Gist.GIST_PRIVATE)) \
                              .filter(Gist.gist_owner == c.authuser.user_id)
 
         # default show ALL public gists
@@ -144,8 +143,8 @@
         except Exception as e:
             log.error(traceback.format_exc())
             h.flash(_('Error occurred during gist creation'), category='error')
-            return redirect(url('new_gist'))
-        return redirect(url('gist', gist_id=new_gist_id))
+            raise HTTPFound(location=url('new_gist'))
+        raise HTTPFound(location=url('gist', gist_id=new_gist_id))
 
     @LoginRequired()
     @NotAnonymous()
@@ -185,7 +184,7 @@
         else:
             raise HTTPForbidden()
 
-        return redirect(url('gists'))
+        raise HTTPFound(location=url('gists'))
 
     @LoginRequired()
     def show(self, gist_id, revision='tip', format='html', f_path=None):
@@ -270,7 +269,7 @@
                 h.flash(_('Error occurred during update of gist %s') % gist_id,
                         category='error')
 
-            return redirect(url('gist', gist_id=gist_id))
+            raise HTTPFound(location=url('gist', gist_id=gist_id))
 
         return rendered
 
--- a/kallithea/controllers/admin/my_account.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/my_account.py	Wed Jan 20 01:41:02 2016 +0100
@@ -32,8 +32,8 @@
 from sqlalchemy import func
 from formencode import htmlfill
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from kallithea import EXTERN_TYPE_INTERNAL
 from kallithea.lib import helpers as h
@@ -69,7 +69,7 @@
         if c.user.username == User.DEFAULT_USER:
             h.flash(_("You can't edit this user since it's"
                       " crucial for entire application"), category='warning')
-            return redirect(url('users'))
+            raise HTTPFound(location=url('users'))
         c.EXTERN_TYPE_INTERNAL = EXTERN_TYPE_INTERNAL
 
     def _load_my_repos_data(self, watched=False):
@@ -81,9 +81,9 @@
                               self.authuser.user_id).all()]
         else:
             admin = True
-            repos_list = Session().query(Repository)\
+            repos_list = Session().query(Repository) \
                          .filter(Repository.user_id ==
-                                 self.authuser.user_id)\
+                                 self.authuser.user_id) \
                          .order_by(func.lower(Repository.repo_name)).all()
 
         repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
@@ -144,7 +144,7 @@
                 h.flash(_('Error occurred during update of user %s') \
                         % form_result.get('username'), category='error')
         if update:
-            return redirect('my_account')
+            raise HTTPFound(location='my_account')
         return htmlfill.render(
             render('admin/my_account/my_account.html'),
             defaults=defaults,
@@ -207,7 +207,7 @@
         c.active = 'emails'
         self.__load_data()
 
-        c.user_email_map = UserEmailMap.query()\
+        c.user_email_map = UserEmailMap.query() \
             .filter(UserEmailMap.user == c.user).all()
         return render('admin/my_account/my_account.html')
 
@@ -225,7 +225,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during email saving'),
                     category='error')
-        return redirect(url('my_account_emails'))
+        raise HTTPFound(location=url('my_account_emails'))
 
     def my_account_emails_delete(self):
         email_id = request.POST.get('del_email_id')
@@ -233,7 +233,7 @@
         user_model.delete_extra_email(self.authuser.user_id, email_id)
         Session().commit()
         h.flash(_("Removed email from user"), category='success')
-        return redirect(url('my_account_emails'))
+        raise HTTPFound(location=url('my_account_emails'))
 
     def my_account_api_keys(self):
         c.active = 'api_keys'
@@ -257,7 +257,7 @@
         ApiKeyModel().create(self.authuser.user_id, description, lifetime)
         Session().commit()
         h.flash(_("API key successfully created"), category='success')
-        return redirect(url('my_account_api_keys'))
+        raise HTTPFound(location=url('my_account_api_keys'))
 
     def my_account_api_keys_delete(self):
         api_key = request.POST.get('del_api_key')
@@ -274,4 +274,4 @@
             Session().commit()
             h.flash(_("API key successfully deleted"), category='success')
 
-        return redirect(url('my_account_api_keys'))
+        raise HTTPFound(location=url('my_account_api_keys'))
--- a/kallithea/controllers/admin/notifications.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/notifications.py	Wed Jan 20 01:41:02 2016 +0100
@@ -30,8 +30,7 @@
 
 from pylons import request
 from pylons import tmpl_context as c
-from pylons.controllers.util import abort
-from webob.exc import HTTPBadRequest
+from webob.exc import HTTPBadRequest, HTTPForbidden
 
 from kallithea.model.db import Notification
 from kallithea.model.notification import NotificationModel
@@ -155,7 +154,7 @@
                     for un in no.notifications_to_users)
         repo_admin = h.HasRepoPermissionAny('repository.admin')
         if no and (h.HasPermissionAny('hg.admin')() or repo_admin or owner):
-            unotification = NotificationModel()\
+            unotification = NotificationModel() \
                             .get_user_notification(c.user.user_id, no)
 
             # if this association to user is not valid, we don't want to show
@@ -168,7 +167,7 @@
 
                 return render('admin/notifications/show_notification.html')
 
-        return abort(403)
+        raise HTTPForbidden()
 
     def edit(self, notification_id, format='html'):
         """GET /_admin/notifications/id/edit: Form to edit an existing item"""
--- a/kallithea/controllers/admin/permissions.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/permissions.py	Wed Jan 20 01:41:02 2016 +0100
@@ -32,8 +32,8 @@
 from formencode import htmlfill
 
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator
@@ -139,7 +139,7 @@
                 h.flash(_('Error occurred during update of permissions'),
                         category='error')
 
-            return redirect(url('admin_permissions'))
+            raise HTTPFound(location=url('admin_permissions'))
 
         c.user = User.get_default_user()
         defaults = {'anonymous': c.user.active}
@@ -184,7 +184,7 @@
     def permission_ips(self):
         c.active = 'ips'
         c.user = User.get_default_user()
-        c.user_ip_map = UserIpMap.query()\
+        c.user_ip_map = UserIpMap.query() \
                         .filter(UserIpMap.user == c.user).all()
 
         return render('admin/permissions/permissions.html')
--- a/kallithea/controllers/admin/repo_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/repo_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -33,8 +33,8 @@
 from formencode import htmlfill
 
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _, ungettext
+from webob.exc import HTTPFound, HTTPForbidden, HTTPNotFound, HTTPInternalServerError
 
 import kallithea
 from kallithea.lib import helpers as h
@@ -49,7 +49,6 @@
 from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
 from kallithea.model.meta import Session
 from kallithea.model.repo import RepoModel
-from webob.exc import HTTPInternalServerError, HTTPNotFound
 from kallithea.lib.utils2 import safe_int
 from sqlalchemy.sql.expression import func
 
@@ -111,8 +110,8 @@
     def index(self, format='html'):
         """GET /repo_groups: All items in the collection"""
         # url('repos_groups')
-        _list = RepoGroup.query()\
-                    .order_by(func.lower(RepoGroup.group_name))\
+        _list = RepoGroup.query() \
+                    .order_by(func.lower(RepoGroup.group_name)) \
                     .all()
         group_iter = RepoGroupList(_list, perm_set=['group.admin'])
         repo_groups_data = []
@@ -189,10 +188,10 @@
                     % request.POST.get('group_name'), category='error')
             parent_group_id = form_result['group_parent_id']
             #TODO: maybe we should get back to the main view, not the admin one
-            return redirect(url('repos_groups', parent_group=parent_group_id))
+            raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id))
         h.flash(_('Created repository group %s') % gr.group_name,
                 category='success')
-        return redirect(url('repos_group_home', group_name=gr.group_name))
+        raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name))
 
     def new(self):
         """GET /repo_groups/new: Form to create a new item"""
@@ -209,7 +208,7 @@
             if HasRepoGroupPermissionAll('group.admin')(group_name, 'group create'):
                 pass
             else:
-                return abort(403)
+                raise HTTPForbidden()
 
         self.__load_defaults()
         return render('admin/repo_groups/repo_group_add.html')
@@ -266,7 +265,7 @@
             h.flash(_('Error occurred during update of repository group %s') \
                     % request.POST.get('group_name'), category='error')
 
-        return redirect(url('edit_repo_group', group_name=group_name))
+        raise HTTPFound(location=url('edit_repo_group', group_name=group_name))
 
     @HasRepoGroupPermissionAnyDecorator('group.admin')
     def delete(self, group_name):
@@ -283,13 +282,13 @@
         if repos:
             h.flash(_('This group contains %s repositories and cannot be '
                       'deleted') % len(repos), category='warning')
-            return redirect(url('repos_groups'))
+            raise HTTPFound(location=url('repos_groups'))
 
         children = gr.children.all()
         if children:
             h.flash(_('This group contains %s subgroups and cannot be deleted'
                       % (len(children))), category='warning')
-            return redirect(url('repos_groups'))
+            raise HTTPFound(location=url('repos_groups'))
 
         try:
             RepoGroupModel().delete(group_name)
@@ -303,8 +302,8 @@
                     % group_name, category='error')
 
         if gr.parent_group:
-            return redirect(url('repos_group_home', group_name=gr.parent_group.group_name))
-        return redirect(url('repos_groups'))
+            raise HTTPFound(location=url('repos_group_home', group_name=gr.parent_group.group_name))
+        raise HTTPFound(location=url('repos_groups'))
 
     def show_by_name(self, group_name):
         """
@@ -330,13 +329,13 @@
         #overwrite our cached list with current filter
         c.repo_cnt = 0
 
-        groups = RepoGroup.query().order_by(RepoGroup.group_name)\
+        groups = RepoGroup.query().order_by(RepoGroup.group_name) \
             .filter(RepoGroup.group_parent_id == c.group.group_id).all()
         c.groups = self.scm_model.get_repo_groups(groups)
 
-        c.repos_list = Repository.query()\
-                        .filter(Repository.group_id == c.group.group_id)\
-                        .order_by(func.lower(Repository.repo_name))\
+        c.repos_list = Repository.query() \
+                        .filter(Repository.group_id == c.group.group_id) \
+                        .order_by(func.lower(Repository.repo_name)) \
                         .all()
 
         repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
@@ -404,7 +403,7 @@
             if self._revoke_perms_on_yourself(form_result):
                 msg = _('Cannot revoke permission for yourself as admin')
                 h.flash(msg, category='warning')
-                return redirect(url('edit_repo_group_perms', group_name=group_name))
+                raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
         recursive = form_result['recursive']
         # iterate over all members(if in recursive mode) of this groups and
         # set the permissions !
@@ -418,7 +417,7 @@
         #              repo_name, self.ip_addr, self.sa)
         Session().commit()
         h.flash(_('Repository group permissions updated'), category='success')
-        return redirect(url('edit_repo_group_perms', group_name=group_name))
+        raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
 
     @HasRepoGroupPermissionAnyDecorator('group.admin')
     def delete_perms(self, group_name):
--- a/kallithea/controllers/admin/repos.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/repos.py	Wed Jan 20 01:41:02 2016 +0100
@@ -29,11 +29,10 @@
 import traceback
 import formencode
 from formencode import htmlfill
-from webob.exc import HTTPInternalServerError, HTTPForbidden, HTTPNotFound
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
 from sqlalchemy.sql.expression import func
+from webob.exc import HTTPFound, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
 
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import LoginRequired, \
@@ -43,7 +42,7 @@
 from kallithea.lib.utils import action_logger, jsonify
 from kallithea.lib.vcs import RepositoryError
 from kallithea.model.meta import Session
-from kallithea.model.db import User, Repository, UserFollowing, RepoGroup,\
+from kallithea.model.db import User, Repository, UserFollowing, RepoGroup, \
     Setting, RepositoryField
 from kallithea.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
 from kallithea.model.scm import ScmModel, AvailableRepoGroupChoices, RepoList
@@ -71,7 +70,7 @@
 
         if repo_obj is None:
             h.not_mapped_error(repo_name)
-            return redirect(url('repos'))
+            raise HTTPFound(location=url('repos'))
 
         return repo_obj
 
@@ -103,8 +102,8 @@
     def index(self, format='html'):
         """GET /repos: All items in the collection"""
         # url('repos')
-        _list = Repository.query()\
-                        .order_by(func.lower(Repository.repo_name))\
+        _list = Repository.query() \
+                        .order_by(func.lower(Repository.repo_name)) \
                         .all()
 
         c.repos_list = RepoList(_list, perm_set=['repository.admin'])
@@ -128,7 +127,7 @@
         try:
             # CanWriteGroup validators checks permissions of this POST
             form_result = RepoForm(repo_groups=c.repo_groups,
-                                   landing_revs=c.landing_revs_choices)()\
+                                   landing_revs=c.landing_revs_choices)() \
                             .to_python(dict(request.POST))
 
             # create is done sometimes async on celery, db transaction
@@ -152,9 +151,9 @@
             msg = (_('Error creating repository %s')
                    % form_result.get('repo_name'))
             h.flash(msg, category='error')
-            return redirect(url('home'))
+            raise HTTPFound(location=url('home'))
 
-        return redirect(h.url('repo_creating_home',
+        raise HTTPFound(location=h.url('repo_creating_home',
                               repo_name=form_result['repo_name_full'],
                               task_id=task_id))
 
@@ -240,7 +239,7 @@
         c.repo_info = self._load_repo(repo_name)
         self.__load_defaults(c.repo_info)
         c.active = 'settings'
-        c.repo_fields = RepositoryField.query()\
+        c.repo_fields = RepositoryField.query() \
             .filter(RepositoryField.repository == c.repo_info).all()
 
         repo_model = RepoModel()
@@ -282,7 +281,7 @@
             log.error(traceback.format_exc())
             h.flash(_('Error occurred during update of repository %s') \
                     % repo_name, category='error')
-        return redirect(url('edit_repo', repo_name=changed_name))
+        raise HTTPFound(location=url('edit_repo', repo_name=changed_name))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def delete(self, repo_name):
@@ -299,7 +298,7 @@
         repo = repo_model.get_by_repo_name(repo_name)
         if not repo:
             h.not_mapped_error(repo_name)
-            return redirect(url('repos'))
+            raise HTTPFound(location=url('repos'))
         try:
             _forks = repo.forks.count()
             handle_forks = None
@@ -327,15 +326,15 @@
                     category='error')
 
         if repo.group:
-            return redirect(url('repos_group_home', group_name=repo.group.group_name))
-        return redirect(url('repos'))
+            raise HTTPFound(location=url('repos_group_home', group_name=repo.group.group_name))
+        raise HTTPFound(location=url('repos'))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def edit(self, repo_name):
         """GET /repo_name/settings: Form to edit an existing item"""
         # url('edit_repo', repo_name=ID)
         defaults = self.__load_data(repo_name)
-        c.repo_fields = RepositoryField.query()\
+        c.repo_fields = RepositoryField.query() \
             .filter(RepositoryField.repository == c.repo_info).all()
         repo_model = RepoModel()
         c.users_array = repo_model.get_users_js()
@@ -372,7 +371,7 @@
         #              repo_name, self.ip_addr, self.sa)
         Session().commit()
         h.flash(_('Repository permissions updated'), category='success')
-        return redirect(url('edit_repo_perms', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name))
 
     def edit_permissions_revoke(self, repo_name):
         try:
@@ -404,12 +403,12 @@
         """GET /repo_name/settings: Form to edit an existing item"""
         # url('edit_repo', repo_name=ID)
         c.repo_info = self._load_repo(repo_name)
-        c.repo_fields = RepositoryField.query()\
+        c.repo_fields = RepositoryField.query() \
             .filter(RepositoryField.repository == c.repo_info).all()
         c.active = 'fields'
         if request.POST:
 
-            return redirect(url('repo_edit_fields'))
+            raise HTTPFound(location=url('repo_edit_fields'))
         return render('admin/repos/repo_edit.html')
 
     @HasRepoPermissionAllDecorator('repository.admin')
@@ -431,7 +430,7 @@
             if isinstance(e, formencode.Invalid):
                 msg += ". " + e.msg
             h.flash(msg, category='error')
-        return redirect(url('edit_repo_fields', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def delete_repo_field(self, repo_name, field_id):
@@ -443,7 +442,7 @@
             log.error(traceback.format_exc())
             msg = _('An error occurred during removal of field')
             h.flash(msg, category='error')
-        return redirect(url('edit_repo_fields', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def edit_advanced(self, repo_name):
@@ -451,8 +450,8 @@
         # url('edit_repo', repo_name=ID)
         c.repo_info = self._load_repo(repo_name)
         c.default_user_id = User.get_default_user().user_id
-        c.in_public_journal = UserFollowing.query()\
-            .filter(UserFollowing.user_id == c.default_user_id)\
+        c.in_public_journal = UserFollowing.query() \
+            .filter(UserFollowing.user_id == c.default_user_id) \
             .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 
         _repos = Repository.query().order_by(Repository.repo_name).all()
@@ -468,7 +467,7 @@
 
         c.active = 'advanced'
         if request.POST:
-            return redirect(url('repo_edit_advanced'))
+            raise HTTPFound(location=url('repo_edit_advanced'))
         return htmlfill.render(
             render('admin/repos/repo_edit.html'),
             defaults=defaults,
@@ -495,7 +494,7 @@
             h.flash(_('An error occurred during setting this'
                       ' repository in public journal'),
                     category='error')
-        return redirect(url('edit_repo_advanced', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 
 
     @HasRepoPermissionAllDecorator('repository.admin')
@@ -521,7 +520,7 @@
             h.flash(_('An error occurred during this operation'),
                     category='error')
 
-        return redirect(url('edit_repo_advanced', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def edit_advanced_locking(self, repo_name):
@@ -542,7 +541,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during unlocking'),
                     category='error')
-        return redirect(url('edit_repo_advanced', repo_name=repo_name))
+        raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name))
 
     @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
     def toggle_locking(self, repo_name):
@@ -567,7 +566,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during unlocking'),
                     category='error')
-        return redirect(url('summary_home', repo_name=repo_name))
+        raise HTTPFound(location=url('summary_home', repo_name=repo_name))
 
     @HasRepoPermissionAllDecorator('repository.admin')
     def edit_caches(self, repo_name):
@@ -577,7 +576,7 @@
         c.active = 'caches'
         if request.POST:
             try:
-                ScmModel().mark_for_invalidation(repo_name, delete=True)
+                ScmModel().mark_for_invalidation(repo_name)
                 Session().commit()
                 h.flash(_('Cache invalidation successful'),
                         category='success')
@@ -586,7 +585,7 @@
                 h.flash(_('An error occurred during cache invalidation'),
                         category='error')
 
-            return redirect(url('edit_repo_caches', repo_name=c.repo_name))
+            raise HTTPFound(location=url('edit_repo_caches', repo_name=c.repo_name))
         return render('admin/repos/repo_edit.html')
 
     @HasRepoPermissionAllDecorator('repository.admin')
@@ -603,7 +602,7 @@
                 log.error(traceback.format_exc())
                 h.flash(_('An error occurred during pull from remote location'),
                         category='error')
-            return redirect(url('edit_repo_remote', repo_name=c.repo_name))
+            raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name))
         return render('admin/repos/repo_edit.html')
 
     @HasRepoPermissionAllDecorator('repository.admin')
@@ -636,6 +635,6 @@
                 log.error(traceback.format_exc())
                 h.flash(_('An error occurred during deletion of repository stats'),
                         category='error')
-            return redirect(url('edit_repo_statistics', repo_name=c.repo_name))
+            raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name))
 
         return render('admin/repos/repo_edit.html')
--- a/kallithea/controllers/admin/settings.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/settings.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,8 +31,8 @@
 
 from formencode import htmlfill
 from pylons import request, tmpl_context as c, url, config
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from kallithea.lib import helpers as h
 from kallithea.lib.auth import LoginRequired, HasPermissionAllDecorator
@@ -206,7 +206,7 @@
             if invalidate_cache:
                 log.debug('invalidating all repositories cache')
                 for repo in Repository.get_all():
-                    ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
+                    ScmModel().mark_for_invalidation(repo.repo_name)
 
             filesystem_repos = ScmModel().repo_scan()
             added, removed = repo2db_mapper(filesystem_repos, rm_obsolete,
@@ -218,7 +218,7 @@
                  for repo_name in added) or '-',
                  ', '.join(h.escape(safe_unicode(repo_name)) for repo_name in removed) or '-')),
                 category='success')
-            return redirect(url('admin_settings_mapping'))
+            raise HTTPFound(location=url('admin_settings_mapping'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
@@ -278,7 +278,7 @@
                           'application settings'),
                           category='error')
 
-            return redirect(url('admin_settings_global'))
+            raise HTTPFound(location=url('admin_settings_global'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
@@ -336,7 +336,7 @@
                           'visualisation settings'),
                         category='error')
 
-            return redirect(url('admin_settings_visual'))
+            raise HTTPFound(location=url('admin_settings_visual'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
@@ -359,12 +359,12 @@
                                'Kallithea version: %s' % c.kallithea_version)
             if not test_email:
                 h.flash(_('Please enter email address'), category='error')
-                return redirect(url('admin_settings_email'))
+                raise HTTPFound(location=url('admin_settings_email'))
 
-            test_email_txt_body = EmailNotificationModel()\
+            test_email_txt_body = EmailNotificationModel() \
                 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
                                 'txt', body=test_body)
-            test_email_html_body = EmailNotificationModel()\
+            test_email_html_body = EmailNotificationModel() \
                 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
                                 'html', body=test_body)
 
@@ -374,7 +374,7 @@
                      test_email_txt_body, test_email_html_body)
 
             h.flash(_('Send email task created'), category='success')
-            return redirect(url('admin_settings_email'))
+            raise HTTPFound(location=url('admin_settings_email'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
@@ -425,7 +425,7 @@
                     h.flash(_('Error occurred during hook creation'),
                             category='error')
 
-                return redirect(url('admin_settings_hooks'))
+                raise HTTPFound(location=url('admin_settings_hooks'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
@@ -449,7 +449,7 @@
             full_index = request.POST.get('full_index', False)
             run_task(tasks.whoosh_index, repo_location, full_index)
             h.flash(_('Whoosh reindex task scheduled'), category='success')
-            return redirect(url('admin_settings_search'))
+            raise HTTPFound(location=url('admin_settings_search'))
 
         defaults = Setting.get_app_settings()
         defaults.update(self._get_hg_ui_settings())
--- a/kallithea/controllers/admin/user_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/user_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,8 +31,8 @@
 
 from formencode import htmlfill
 from pylons import request, tmpl_context as c, url, config
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 from sqlalchemy.orm import joinedload
 from sqlalchemy.sql.expression import func
@@ -90,8 +90,8 @@
     def index(self, format='html'):
         """GET /users_groups: All items in the collection"""
         # url('users_groups')
-        _list = UserGroup.query()\
-                        .order_by(func.lower(UserGroup.users_group_name))\
+        _list = UserGroup.query() \
+                        .order_by(func.lower(UserGroup.users_group_name)) \
                         .all()
         group_iter = UserGroupList(_list, perm_set=['usergroup.admin'])
         user_groups_data = []
@@ -163,7 +163,7 @@
             h.flash(_('Error occurred during creation of user group %s') \
                     % request.POST.get('users_group_name'), category='error')
 
-        return redirect(url('users_groups'))
+        raise HTTPFound(location=url('users_groups'))
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
     def new(self, format='html'):
@@ -224,7 +224,7 @@
             h.flash(_('Error occurred during update of user group %s') \
                     % request.POST.get('users_group_name'), category='error')
 
-        return redirect(url('edit_users_group', id=id))
+        raise HTTPFound(location=url('edit_users_group', id=id))
 
     @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def delete(self, id):
@@ -246,7 +246,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of user group'),
                     category='error')
-        return redirect(url('users_groups'))
+        raise HTTPFound(location=url('users_groups'))
 
     def show(self, id, format='html'):
         """GET /user_groups/id: Show a specific item"""
@@ -312,13 +312,13 @@
                                                  form['perms_updates'])
         except RepoGroupAssignmentError:
             h.flash(_('Target group cannot be the same'), category='error')
-            return redirect(url('edit_user_group_perms', id=id))
+            raise HTTPFound(location=url('edit_user_group_perms', id=id))
         #TODO: implement this
         #action_logger(self.authuser, 'admin_changed_repo_permissions',
         #              repo_name, self.ip_addr, self.sa)
         Session().commit()
         h.flash(_('User group permissions updated'), category='success')
-        return redirect(url('edit_user_group_perms', id=id))
+        raise HTTPFound(location=url('edit_user_group_perms', id=id))
 
     @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def delete_perms(self, id):
@@ -362,20 +362,20 @@
             'repositories': {},
             'repositories_groups': {}
         }
-        ugroup_repo_perms = UserGroupRepoToPerm.query()\
-            .options(joinedload(UserGroupRepoToPerm.permission))\
-            .options(joinedload(UserGroupRepoToPerm.repository))\
-            .filter(UserGroupRepoToPerm.users_group_id == id)\
+        ugroup_repo_perms = UserGroupRepoToPerm.query() \
+            .options(joinedload(UserGroupRepoToPerm.permission)) \
+            .options(joinedload(UserGroupRepoToPerm.repository)) \
+            .filter(UserGroupRepoToPerm.users_group_id == id) \
             .all()
 
         for gr in ugroup_repo_perms:
             permissions['repositories'][gr.repository.repo_name]  \
                 = gr.permission.permission_name
 
-        ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
-            .options(joinedload(UserGroupRepoGroupToPerm.permission))\
-            .options(joinedload(UserGroupRepoGroupToPerm.group))\
-            .filter(UserGroupRepoGroupToPerm.users_group_id == id)\
+        ugroup_group_perms = UserGroupRepoGroupToPerm.query() \
+            .options(joinedload(UserGroupRepoGroupToPerm.permission)) \
+            .options(joinedload(UserGroupRepoGroupToPerm.group)) \
+            .filter(UserGroupRepoGroupToPerm.users_group_id == id) \
             .all()
 
         for gr in ugroup_group_perms:
@@ -418,8 +418,8 @@
             Session().add(user_group)
             usergroup_model = UserGroupModel()
 
-            defs = UserGroupToPerm.query()\
-                .filter(UserGroupToPerm.users_group == user_group)\
+            defs = UserGroupToPerm.query() \
+                .filter(UserGroupToPerm.users_group == user_group) \
                 .all()
             for ug in defs:
                 Session().delete(ug)
@@ -444,7 +444,7 @@
             h.flash(_('An error occurred during permissions saving'),
                     category='error')
 
-        return redirect(url('edit_user_group_default_perms', id=id))
+        raise HTTPFound(location=url('edit_user_group_default_perms', id=id))
 
     @HasUserGroupPermissionAnyDecorator('usergroup.admin')
     def edit_advanced(self, id):
--- a/kallithea/controllers/admin/users.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/admin/users.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,10 +31,9 @@
 
 from formencode import htmlfill
 from pylons import request, tmpl_context as c, url, config
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
 from sqlalchemy.sql.expression import func
-from webob.exc import HTTPNotFound
+from webob.exc import HTTPFound, HTTPNotFound
 
 import kallithea
 from kallithea.lib.exceptions import DefaultUserException, \
@@ -72,9 +71,9 @@
         """GET /users: All items in the collection"""
         # url('users')
 
-        c.users_list = User.query().order_by(User.username)\
-                        .filter(User.username != User.DEFAULT_USER)\
-                        .order_by(func.lower(User.username))\
+        c.users_list = User.query().order_by(User.username) \
+                        .filter(User.username != User.DEFAULT_USER) \
+                        .order_by(func.lower(User.username)) \
                         .all()
 
         users_data = []
@@ -148,7 +147,7 @@
             log.error(traceback.format_exc())
             h.flash(_('Error occurred during creation of user %s') \
                     % request.POST.get('username'), category='error')
-        return redirect(url('users'))
+        raise HTTPFound(location=url('users'))
 
     def new(self, format='html'):
         """GET /users/new: Form to create a new item"""
@@ -201,7 +200,7 @@
             log.error(traceback.format_exc())
             h.flash(_('Error occurred during update of user %s') \
                     % form_result.get('username'), category='error')
-        return redirect(url('edit_user', id=id))
+        raise HTTPFound(location=url('edit_user', id=id))
 
     def delete(self, id):
         """DELETE /users/id: Delete an existing item"""
@@ -222,7 +221,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during deletion of user'),
                     category='error')
-        return redirect(url('users'))
+        raise HTTPFound(location=url('users'))
 
     def show(self, id, format='html'):
         """GET /users/id: Show a specific item"""
@@ -306,7 +305,7 @@
         ApiKeyModel().create(c.user.user_id, description, lifetime)
         Session().commit()
         h.flash(_("API key successfully created"), category='success')
-        return redirect(url('edit_user_api_keys', id=c.user.user_id))
+        raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id))
 
     def delete_api_key(self, id):
         c.user = self._get_user_or_raise_if_default(id)
@@ -324,7 +323,7 @@
             Session().commit()
             h.flash(_("API key successfully deleted"), category='success')
 
-        return redirect(url('edit_user_api_keys', id=c.user.user_id))
+        raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id))
 
     def update_account(self, id):
         pass
@@ -363,8 +362,8 @@
             Session().add(user)
             user_model = UserModel()
 
-            defs = UserToPerm.query()\
-                .filter(UserToPerm.user == user)\
+            defs = UserToPerm.query() \
+                .filter(UserToPerm.user == user) \
                 .all()
             for ug in defs:
                 Session().delete(ug)
@@ -387,12 +386,12 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during permissions saving'),
                     category='error')
-        return redirect(url('edit_user_perms', id=id))
+        raise HTTPFound(location=url('edit_user_perms', id=id))
 
     def edit_emails(self, id):
         c.user = self._get_user_or_raise_if_default(id)
         c.active = 'emails'
-        c.user_email_map = UserEmailMap.query()\
+        c.user_email_map = UserEmailMap.query() \
             .filter(UserEmailMap.user == c.user).all()
 
         defaults = c.user.get_dict()
@@ -420,7 +419,7 @@
             log.error(traceback.format_exc())
             h.flash(_('An error occurred during email saving'),
                     category='error')
-        return redirect(url('edit_user_emails', id=id))
+        raise HTTPFound(location=url('edit_user_emails', id=id))
 
     def delete_email(self, id):
         """DELETE /user_emails_delete/id: Delete an existing item"""
@@ -431,16 +430,16 @@
         user_model.delete_extra_email(id, email_id)
         Session().commit()
         h.flash(_("Removed email from user"), category='success')
-        return redirect(url('edit_user_emails', id=id))
+        raise HTTPFound(location=url('edit_user_emails', id=id))
 
     def edit_ips(self, id):
         c.user = self._get_user_or_raise_if_default(id)
         c.active = 'ips'
-        c.user_ip_map = UserIpMap.query()\
+        c.user_ip_map = UserIpMap.query() \
             .filter(UserIpMap.user == c.user).all()
 
         c.inherit_default_ips = c.user.inherit_default_permissions
-        c.default_user_ip_map = UserIpMap.query()\
+        c.default_user_ip_map = UserIpMap.query() \
             .filter(UserIpMap.user == User.get_default_user()).all()
 
         defaults = c.user.get_dict()
@@ -470,8 +469,8 @@
                     category='error')
 
         if 'default_user' in request.POST:
-            return redirect(url('admin_permissions_ips'))
-        return redirect(url('edit_user_ips', id=id))
+            raise HTTPFound(location=url('admin_permissions_ips'))
+        raise HTTPFound(location=url('edit_user_ips', id=id))
 
     def delete_ip(self, id):
         """DELETE /user_ips_delete/id: Delete an existing item"""
@@ -483,5 +482,5 @@
         h.flash(_("Removed IP address from user whitelist"), category='success')
 
         if 'default_user' in request.POST:
-            return redirect(url('admin_permissions_ips'))
-        return redirect(url('edit_user_ips', id=id))
+            raise HTTPFound(location=url('admin_permissions_ips'))
+        raise HTTPFound(location=url('edit_user_ips', id=id))
--- a/kallithea/controllers/api/api.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/api/api.py	Wed Jan 20 01:41:02 2016 +0100
@@ -25,7 +25,6 @@
 :license: GPLv3, see LICENSE.md for more details.
 """
 
-
 import time
 import traceback
 import logging
@@ -705,10 +704,10 @@
 
     @HasPermissionAllDecorator('hg.admin')
     def update_user(self, apiuser, userid, username=Optional(None),
-                    email=Optional(None),password=Optional(None),
+                    email=Optional(None), password=Optional(None),
                     firstname=Optional(None), lastname=Optional(None),
                     active=Optional(None), admin=Optional(None),
-                    extern_type=Optional(None), extern_name=Optional(None),):
+                    extern_type=Optional(None), extern_name=Optional(None)):
         """
         updates given user if such user exists. This command can
         be executed only using api_key belonging to user with admin rights.
@@ -1074,7 +1073,7 @@
             raise JSONRPCError('failed to delete user group ID:%s %s' %
                                (user_group.users_group_id,
                                 user_group.users_group_name)
-            )
+                               )
 
     # permission check inside
     def add_user_to_user_group(self, apiuser, usergroupid, userid):
@@ -1455,7 +1454,7 @@
         """
         if not HasPermissionAnyApi('hg.admin')(user=apiuser):
             if not isinstance(owner, Optional):
-                #forbid setting owner for non-admins
+                # forbid setting owner for non-admins
                 raise JSONRPCError(
                     'Only Kallithea admin can specify `owner` param'
                 )
@@ -1562,7 +1561,7 @@
                 raise JSONRPCError('no permission to create (or move) repositories')
 
             if not isinstance(owner, Optional):
-                #forbid setting owner for non-admins
+                # forbid setting owner for non-admins
                 raise JSONRPCError(
                     'Only Kallithea admin can specify `owner` param'
                 )
@@ -1660,7 +1659,7 @@
                                      'repository.read')(user=apiuser,
                                                         repo_name=repo.repo_name):
             if not isinstance(owner, Optional):
-                #forbid setting owner for non-admins
+                # forbid setting owner for non-admins
                 raise JSONRPCError(
                     'Only Kallithea admin can specify `owner` param'
                 )
@@ -1741,7 +1740,7 @@
         if not HasPermissionAnyApi('hg.admin')(user=apiuser):
             # check if we have admin permission for this repo !
             if not HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
-                                                           repo_name=repo.repo_name):
+                                                               repo_name=repo.repo_name):
                 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
 
         try:
@@ -2175,7 +2174,7 @@
             log.error(traceback.format_exc())
             raise JSONRPCError('failed to delete repo group ID:%s %s' %
                                (repo_group.group_id, repo_group.group_name)
-            )
+                               )
 
     # permission check inside
     def grant_user_permission_to_repo_group(self, apiuser, repogroupid, userid,
@@ -2315,7 +2314,7 @@
     # permission check inside
     def grant_user_group_permission_to_repo_group(
             self, apiuser, repogroupid, usergroupid, perm,
-            apply_to_children=Optional('none'),):
+            apply_to_children=Optional('none')):
         """
         Grant permission for user group on given repository group, or update
         existing one if found. This command can be executed only using
@@ -2381,9 +2380,9 @@
             Session().commit()
             return dict(
                 msg='Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
-                        perm.permission_name, apply_to_children,
-                        user_group.users_group_name, repo_group.name
-                    ),
+                    perm.permission_name, apply_to_children,
+                    user_group.users_group_name, repo_group.name
+                ),
                 success=True
             )
         except Exception:
@@ -2509,9 +2508,9 @@
             user_id = get_user_or_error(userid).user_id
 
         gists = []
-        _gists = Gist().query()\
-            .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
-            .filter(Gist.gist_owner == user_id)\
+        _gists = Gist().query() \
+            .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time())) \
+            .filter(Gist.gist_owner == user_id) \
             .order_by(Gist.created_on.desc())
         for gist in _gists:
             gists.append(gist.get_api_data())
--- a/kallithea/controllers/changelog.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/changelog.py	Wed Jan 20 01:41:02 2016 +0100
@@ -29,9 +29,8 @@
 import traceback
 
 from pylons import request, url, session, tmpl_context as c
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
-from webob.exc import HTTPNotFound, HTTPBadRequest
+from webob.exc import HTTPFound, HTTPNotFound, HTTPBadRequest
 
 import kallithea.lib.helpers as h
 from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
@@ -39,7 +38,7 @@
 from kallithea.lib.helpers import RepoPage
 from kallithea.lib.compat import json
 from kallithea.lib.graphmod import graph_data
-from kallithea.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError,\
+from kallithea.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
     ChangesetError, NodeDoesNotExistError, EmptyRepositoryError
 from kallithea.lib.utils2 import safe_int, safe_str
 
@@ -99,8 +98,8 @@
         if request.GET.get('set'):
             request.GET.pop('set', None)
             if revision is None:
-                return redirect(url('changelog_home', repo_name=repo_name, **request.GET))
-            return redirect(url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET))
+                raise HTTPFound(location=url('changelog_home', repo_name=repo_name, **request.GET))
+            raise HTTPFound(location=url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET))
 
         limit = 2000
         default = 100
@@ -118,7 +117,7 @@
             branch_name not in c.db_repo_scm_instance.branches and
             branch_name not in c.db_repo_scm_instance.closed_branches and
             not revision):
-            return redirect(url('changelog_file_home', repo_name=c.repo_name,
+            raise HTTPFound(location=url('changelog_file_home', repo_name=c.repo_name,
                                     revision=branch_name, f_path=f_path or ''))
 
         if revision == 'tip':
@@ -140,7 +139,7 @@
                         collection = cs.get_file_history(f_path)
                     except RepositoryError as e:
                         h.flash(safe_str(e), category='warning')
-                        redirect(h.url('changelog_home', repo_name=repo_name))
+                        raise HTTPFound(location=h.url('changelog_home', repo_name=repo_name))
                 collection = list(reversed(collection))
             else:
                 collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision,
@@ -155,11 +154,11 @@
             c.statuses = c.db_repo.statuses(page_revisions)
         except EmptyRepositoryError as e:
             h.flash(safe_str(e), category='warning')
-            return redirect(url('summary_home', repo_name=c.repo_name))
+            raise HTTPFound(location=url('summary_home', repo_name=c.repo_name))
         except (RepositoryError, ChangesetDoesNotExistError, Exception) as e:
             log.error(traceback.format_exc())
             h.flash(safe_str(e), category='error')
-            return redirect(url('changelog_home', repo_name=c.repo_name))
+            raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name))
 
         c.branch_name = branch_name
         c.branch_filters = [('', _('None'))] + \
--- a/kallithea/controllers/changeset.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/changeset.py	Wed Jan 20 01:41:02 2016 +0100
@@ -29,19 +29,18 @@
 import logging
 import traceback
 from collections import defaultdict
-from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound
 
 from pylons import tmpl_context as c, request, response
 from pylons.i18n.translation import _
-from pylons.controllers.util import redirect
+from webob.exc import HTTPFound, HTTPForbidden, HTTPBadRequest, HTTPNotFound
+
 from kallithea.lib.utils import jsonify
-
 from kallithea.lib.vcs.exceptions import RepositoryError, \
     ChangesetDoesNotExistError
 
 from kallithea.lib.compat import json
 import kallithea.lib.helpers as h
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
     NotAnonymous
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.utils import action_logger
@@ -207,7 +206,7 @@
             if not c.cs_ranges:
                 raise RepositoryError('Changeset range returned empty result')
 
-        except(ChangesetDoesNotExistError,), e:
+        except ChangesetDoesNotExistError:
             log.debug(traceback.format_exc())
             msg = _('Such revision does not exist for this repository')
             h.flash(msg, category='error')
@@ -226,7 +225,6 @@
 
         # Iterate over ranges (default changeset view is always one changeset)
         for changeset in c.cs_ranges:
-            inlines = []
             if method == 'show':
                 c.statuses.extend([ChangesetStatusModel().get_status(
                             c.db_repo.repo_id, changeset.raw_id)])
@@ -244,7 +242,7 @@
                                               changeset.raw_id, with_revisions=True)
                                 if st.changeset_comment_id is not None)
 
-                inlines = ChangesetCommentsModel()\
+                inlines = ChangesetCommentsModel() \
                             .get_inline_comments(c.db_repo.repo_id,
                                                  revision=changeset.raw_id)
                 c.inline_comments.extend(inlines)
@@ -254,7 +252,7 @@
             cs2 = changeset.raw_id
             cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset().raw_id
             context_lcl = get_line_ctx('', request.GET)
-            ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET)
+            ign_whitespace_lcl = get_ignore_ws('', request.GET)
 
             _diff = c.db_repo_scm_instance.get_diff(cs1, cs2,
                 ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
@@ -383,7 +381,7 @@
                 msg = _('Changing status on a changeset associated with '
                         'a closed pull request is not allowed')
                 h.flash(msg, category='warning')
-                return redirect(h.url('changeset_home', repo_name=repo_name,
+                raise HTTPFound(location=h.url('changeset_home', repo_name=repo_name,
                                       revision=revision))
         action_logger(self.authuser,
                       'user_commented_revision:%s' % revision,
@@ -392,7 +390,7 @@
         Session().commit()
 
         if not request.environ.get('HTTP_X_PARTIAL_XHR'):
-            return redirect(h.url('changeset_home', repo_name=repo_name,
+            raise HTTPFound(location=h.url('changeset_home', repo_name=repo_name,
                                   revision=revision))
         #only ajax below
         data = {
--- a/kallithea/controllers/compare.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/compare.py	Wed Jan 20 01:41:02 2016 +0100
@@ -30,11 +30,11 @@
 import logging
 import re
 
-from webob.exc import HTTPBadRequest
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound, HTTPBadRequest
 
+from kallithea.lib.utils2 import safe_str
 from kallithea.lib.vcs.utils.hgcompat import unionrepo
 from kallithea.lib import helpers as h
 from kallithea.lib.base import BaseRepoController, render
@@ -114,10 +114,10 @@
                 from dulwich.client import SubprocessGitClient
 
                 gitrepo = Repo(org_repo.path)
-                SubprocessGitClient(thin_packs=False).fetch(other_repo.path, gitrepo)
+                SubprocessGitClient(thin_packs=False).fetch(safe_str(other_repo.path), gitrepo)
 
                 gitrepo_remote = Repo(other_repo.path)
-                SubprocessGitClient(thin_packs=False).fetch(org_repo.path, gitrepo_remote)
+                SubprocessGitClient(thin_packs=False).fetch(safe_str(org_repo.path), gitrepo_remote)
 
                 revs = []
                 for x in gitrepo_remote.get_walker(include=[other_rev],
@@ -206,19 +206,19 @@
             msg = 'Could not find org repo %s' % org_repo
             log.error(msg)
             h.flash(msg, category='error')
-            return redirect(url('compare_home', repo_name=c.repo_name))
+            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))
 
         if other_repo is None:
             msg = 'Could not find other repo %s' % other_repo
             log.error(msg)
             h.flash(msg, category='error')
-            return redirect(url('compare_home', repo_name=c.repo_name))
+            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))
 
         if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
             msg = 'compare of two different kind of remote repos not available'
             log.error(msg)
             h.flash(msg, category='error')
-            return redirect(url('compare_home', repo_name=c.repo_name))
+            raise HTTPFound(location=url('compare_home', repo_name=c.repo_name))
 
         c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name,
             returnempty=True)
--- a/kallithea/controllers/files.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/files.py	Wed Jan 20 01:41:02 2016 +0100
@@ -33,14 +33,14 @@
 
 from pylons import request, response, tmpl_context as c, url
 from pylons.i18n.translation import _
-from pylons.controllers.util import redirect
+from webob.exc import HTTPFound
+
 from kallithea.lib.utils import jsonify, action_logger
-
 from kallithea.lib import diffs
 from kallithea.lib import helpers as h
 
 from kallithea.lib.compat import OrderedDict
-from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
+from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_str, \
     str2bool
 from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from kallithea.lib.base import BaseRepoController, render
@@ -48,7 +48,7 @@
 from kallithea.lib.vcs.conf import settings
 from kallithea.lib.vcs.exceptions import RepositoryError, \
     ChangesetDoesNotExistError, EmptyRepositoryError, \
-    ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
+    ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError, \
     NodeDoesNotExistError, ChangesetError, NodeError
 from kallithea.lib.vcs.nodes import FileNode
 
@@ -56,7 +56,7 @@
 from kallithea.model.scm import ScmModel
 from kallithea.model.db import Repository
 
-from kallithea.controllers.changeset import anchor_url, _ignorews_url,\
+from kallithea.controllers.changeset import anchor_url, _ignorews_url, \
     _context_url, get_line_ctx, get_ignore_ws
 from webob.exc import HTTPNotFound
 from kallithea.lib.exceptions import NonRelativePathError
@@ -92,7 +92,7 @@
             h.flash(h.literal(_('There are no files yet. %s') % add_new),
                     category='warning')
             raise HTTPNotFound()
-        except(ChangesetDoesNotExistError, LookupError), e:
+        except (ChangesetDoesNotExistError, LookupError):
             msg = _('Such revision does not exist for this repository')
             h.flash(msg, category='error')
             raise HTTPNotFound()
@@ -112,7 +112,7 @@
             file_node = cs.get_node(path)
             if file_node.is_dir():
                 raise RepositoryError('given path is a directory')
-        except(ChangesetDoesNotExistError,), e:
+        except ChangesetDoesNotExistError:
             msg = _('Such revision does not exist for this repository')
             h.flash(msg, category='error')
             raise HTTPNotFound()
@@ -137,6 +137,7 @@
         c.f_path = f_path
         c.annotate = annotate
         cur_rev = c.changeset.revision
+        c.fulldiff = request.GET.get('fulldiff')
 
         # prev link
         try:
@@ -306,7 +307,7 @@
                 % (h.person_by_id(repo.locked[0]),
                    h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                 'warning')
-            return redirect(h.url('files_home',
+            raise HTTPFound(location=h.url('files_home',
                                   repo_name=repo_name, revision='tip'))
 
         # check if revision is a branch identifier- basically we cannot
@@ -316,7 +317,7 @@
         if revision not in _branches.keys() + _branches.values():
             h.flash(_('You can only delete files with revision '
                       'being a valid branch'), category='warning')
-            return redirect(h.url('files_home',
+            raise HTTPFound(location=h.url('files_home',
                                   repo_name=repo_name, revision='tip',
                                   f_path=f_path))
 
@@ -352,7 +353,7 @@
             except Exception:
                 log.error(traceback.format_exc())
                 h.flash(_('Error occurred during commit'), category='error')
-            return redirect(url('changeset_home',
+            raise HTTPFound(location=url('changeset_home',
                                 repo_name=c.repo_name, revision='tip'))
 
         return render('files/files_delete.html')
@@ -366,7 +367,7 @@
                 % (h.person_by_id(repo.locked[0]),
                    h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                 'warning')
-            return redirect(h.url('files_home',
+            raise HTTPFound(location=h.url('files_home',
                                   repo_name=repo_name, revision='tip'))
 
         # check if revision is a branch identifier- basically we cannot
@@ -376,7 +377,7 @@
         if revision not in _branches.keys() + _branches.values():
             h.flash(_('You can only edit files with revision '
                       'being a valid branch'), category='warning')
-            return redirect(h.url('files_home',
+            raise HTTPFound(location=h.url('files_home',
                                   repo_name=repo_name, revision='tip',
                                   f_path=f_path))
 
@@ -386,7 +387,7 @@
         c.file = self.__get_filenode(c.cs, f_path)
 
         if c.file.is_binary:
-            return redirect(url('files_home', repo_name=c.repo_name,
+            raise HTTPFound(location=url('files_home', repo_name=c.repo_name,
                             revision=c.cs.raw_id, f_path=f_path))
         c.default_message = _('Edited file %s via Kallithea') % (f_path)
         c.f_path = f_path
@@ -405,7 +406,7 @@
 
             if content == old_content:
                 h.flash(_('No changes'), category='warning')
-                return redirect(url('changeset_home', repo_name=c.repo_name,
+                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                     revision='tip'))
             try:
                 self.scm_model.commit_change(repo=c.db_repo_scm_instance,
@@ -418,7 +419,7 @@
             except Exception:
                 log.error(traceback.format_exc())
                 h.flash(_('Error occurred during commit'), category='error')
-            return redirect(url('changeset_home',
+            raise HTTPFound(location=url('changeset_home',
                                 repo_name=c.repo_name, revision='tip'))
 
         return render('files/files_edit.html')
@@ -433,7 +434,7 @@
                 % (h.person_by_id(repo.locked[0]),
                    h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                   'warning')
-            return redirect(h.url('files_home',
+            raise HTTPFound(location=h.url('files_home',
                                   repo_name=repo_name, revision='tip'))
 
         r_post = request.POST
@@ -462,11 +463,11 @@
 
             if not content:
                 h.flash(_('No content'), category='warning')
-                return redirect(url('changeset_home', repo_name=c.repo_name,
+                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                     revision='tip'))
             if not filename:
                 h.flash(_('No filename'), category='warning')
-                return redirect(url('changeset_home', repo_name=c.repo_name,
+                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                     revision='tip'))
             #strip all crap out of file, just leave the basename
             filename = os.path.basename(filename)
@@ -492,14 +493,14 @@
             except NonRelativePathError as e:
                 h.flash(_('Location must be relative path and must not '
                           'contain .. in path'), category='warning')
-                return redirect(url('changeset_home', repo_name=c.repo_name,
+                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                     revision='tip'))
             except (NodeError, NodeAlreadyExistsError) as e:
                 h.flash(_(e), category='error')
             except Exception:
                 log.error(traceback.format_exc())
                 h.flash(_('Error occurred during commit'), category='error')
-            return redirect(url('changeset_home',
+            raise HTTPFound(location=url('changeset_home',
                                 repo_name=c.repo_name, revision='tip'))
 
         return render('files/files_add.html')
@@ -620,7 +621,7 @@
                 _url = url('files_home', repo_name=c.repo_name,
                            revision=diff1, f_path=c.f_path)
 
-            return redirect(_url)
+            raise HTTPFound(location=_url)
         try:
             if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
                 c.changeset_1 = c.db_repo_scm_instance.get_changeset(diff1)
@@ -655,7 +656,7 @@
                 node2 = FileNode(f_path, '', changeset=c.changeset_2)
         except (RepositoryError, NodeError):
             log.error(traceback.format_exc())
-            return redirect(url('files_home', repo_name=c.repo_name,
+            raise HTTPFound(location=url('files_home', repo_name=c.repo_name,
                                 f_path=f_path))
 
         if c.action == 'download':
--- a/kallithea/controllers/followers.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/followers.py	Wed Jan 20 01:41:02 2016 +0100
@@ -49,7 +49,7 @@
     def followers(self, repo_name):
         p = safe_int(request.GET.get('page', 1), 1)
         repo_id = c.db_repo.repo_id
-        d = UserFollowing.get_repo_followers(repo_id)\
+        d = UserFollowing.get_repo_followers(repo_id) \
             .order_by(UserFollowing.follows_from)
         c.followers_pager = Page(d, page=p, items_per_page=20)
 
--- a/kallithea/controllers/forks.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/forks.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,8 +31,8 @@
 from formencode import htmlfill
 
 from pylons import tmpl_context as c, request, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound
 
 import kallithea.lib.helpers as h
 
@@ -77,11 +77,11 @@
 
         if c.repo_info is None:
             h.not_mapped_error(repo_name)
-            return redirect(url('repos'))
+            raise HTTPFound(location=url('repos'))
 
         c.default_user_id = User.get_default_user().user_id
-        c.in_public_journal = UserFollowing.query()\
-            .filter(UserFollowing.user_id == c.default_user_id)\
+        c.in_public_journal = UserFollowing.query() \
+            .filter(UserFollowing.user_id == c.default_user_id) \
             .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 
         if c.repo_info.stats:
@@ -137,7 +137,7 @@
         c.repo_info = Repository.get_by_repo_name(repo_name)
         if not c.repo_info:
             h.not_mapped_error(repo_name)
-            return redirect(url('home'))
+            raise HTTPFound(location=url('home'))
 
         defaults = self.__load_data(repo_name)
 
@@ -186,6 +186,6 @@
             h.flash(_('An error occurred during repository forking %s') %
                     repo_name, category='error')
 
-        return redirect(h.url('repo_creating_home',
+        raise HTTPFound(location=h.url('repo_creating_home',
                               repo_name=form_result['repo_name_full'],
                               task_id=task_id))
--- a/kallithea/controllers/home.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/home.py	Wed Jan 20 01:41:02 2016 +0100
@@ -57,9 +57,9 @@
         c.groups = self.scm_model.get_repo_groups()
         c.group = None
 
-        c.repos_list = Repository.query()\
-                        .filter(Repository.group_id == None)\
-                        .order_by(func.lower(Repository.repo_name))\
+        c.repos_list = Repository.query() \
+                        .filter(Repository.group_id == None) \
+                        .order_by(func.lower(Repository.repo_name)) \
                         .all()
 
         repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
@@ -130,6 +130,12 @@
                 'text': _('Branch'),
                 'children': [{'id': rev, 'text': name, 'type': 'branch'} for name, rev in _branches]
             })
+        _closed_branches = repo.closed_branches.items()
+        if _closed_branches:
+            res.append({
+                'text': _('Closed Branches'),
+                'children': [{'id': rev, 'text': name, 'type': 'closed-branch'} for name, rev in _closed_branches]
+            })
         _tags = repo.tags.items()
         if _tags:
             res.append({
--- a/kallithea/controllers/journal.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/journal.py	Wed Jan 20 01:41:02 2016 +0100
@@ -92,12 +92,12 @@
         if not repo_ids and user_ids:
             filtering_criterion = UserLog.user_id.in_(user_ids)
         if filtering_criterion is not None:
-            journal = self.sa.query(UserLog)\
-                .options(joinedload(UserLog.user))\
+            journal = self.sa.query(UserLog) \
+                .options(joinedload(UserLog.user)) \
                 .options(joinedload(UserLog.repository))
             #filter
             journal = _journal_filter(journal, c.search_term)
-            journal = journal.filter(filtering_criterion)\
+            journal = journal.filter(filtering_criterion) \
                         .order_by(UserLog.action_date.desc())
         else:
             journal = []
@@ -194,9 +194,9 @@
         # Return a rendered template
         p = safe_int(request.GET.get('page', 1), 1)
         c.user = User.get(self.authuser.user_id)
-        c.following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        c.following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
 
         journal = self._get_journal_data(c.following)
@@ -210,9 +210,9 @@
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
             return render('journal/journal_data.html')
 
-        repos_list = Session().query(Repository)\
+        repos_list = Session().query(Repository) \
                      .filter(Repository.user_id ==
-                             self.authuser.user_id)\
+                             self.authuser.user_id) \
                      .order_by(func.lower(Repository.repo_name)).all()
 
         repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
@@ -280,9 +280,9 @@
         """
         Produce an atom-1.0 feed via feedgenerator module
         """
-        following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
         return self._atom_feed(following, public=False)
 
@@ -292,9 +292,9 @@
         """
         Produce an rss feed via feedgenerator module
         """
-        following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
         return self._rss_feed(following, public=False)
 
@@ -330,9 +330,9 @@
         # Return a rendered template
         p = safe_int(request.GET.get('page', 1), 1)
 
-        c.following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        c.following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
 
         journal = self._get_journal_data(c.following)
@@ -351,9 +351,9 @@
         """
         Produce an atom-1.0 feed via feedgenerator module
         """
-        c.following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        c.following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
 
         return self._atom_feed(c.following)
@@ -363,9 +363,9 @@
         """
         Produce an rss2 feed via feedgenerator module
         """
-        c.following = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.user_id == self.authuser.user_id)\
-            .options(joinedload(UserFollowing.follows_repository))\
+        c.following = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.user_id == self.authuser.user_id) \
+            .options(joinedload(UserFollowing.follows_repository)) \
             .all()
 
         return self._rss_feed(c.following)
--- a/kallithea/controllers/login.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/login.py	Wed Jan 20 01:41:02 2016 +0100
@@ -31,10 +31,9 @@
 import formencode
 
 from formencode import htmlfill
+from pylons.i18n.translation import _
+from pylons import request, session, tmpl_context as c, url
 from webob.exc import HTTPFound, HTTPBadRequest
-from pylons.i18n.translation import _
-from pylons.controllers.util import redirect
-from pylons import request, session, tmpl_context as c, url
 
 import kallithea.lib.helpers as h
 from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator
@@ -79,11 +78,10 @@
         else:
             c.came_from = url('home')
 
-        not_default = self.authuser.username != User.DEFAULT_USER
         ip_allowed = AuthUser.check_ip_allowed(self.authuser, self.ip_addr)
 
         # redirect if already logged in
-        if self.authuser.is_authenticated and not_default and ip_allowed:
+        if self.authuser.is_authenticated and ip_allowed:
             raise HTTPFound(location=c.came_from)
 
         if request.POST:
@@ -121,7 +119,7 @@
     @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
                                'hg.register.manual_activate')
     def register(self):
-        c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\
+        c.auto_active = 'hg.register.auto_activate' in User.get_default_user() \
             .AuthUser.permissions['global']
 
         settings = Setting.get_app_settings()
@@ -152,7 +150,7 @@
                 h.flash(_('You have successfully registered into Kallithea'),
                         category='success')
                 Session().commit()
-                return redirect(url('login_home'))
+                raise HTTPFound(location=url('login_home'))
 
             except formencode.Invalid as errors:
                 return htmlfill.render(
@@ -196,7 +194,7 @@
                 redirect_link = UserModel().send_reset_password_email(form_result)
                 h.flash(_('A password reset confirmation code has been sent'),
                             category='success')
-                return redirect(redirect_link)
+                raise HTTPFound(location=redirect_link)
 
             except formencode.Invalid as errors:
                 return htmlfill.render(
@@ -249,12 +247,12 @@
 
         UserModel().reset_password(form_result['email'], form_result['password'])
         h.flash(_('Successfully updated password'), category='success')
-        return redirect(url('login_home'))
+        raise HTTPFound(location=url('login_home'))
 
     def logout(self):
         session.delete()
         log.info('Logging out and deleting session for user')
-        redirect(url('home'))
+        raise HTTPFound(location=url('home'))
 
     def authentication_token(self):
         """Return the CSRF protection token for the session - just like it
--- a/kallithea/controllers/pullrequests.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/pullrequests.py	Wed Jan 20 01:41:02 2016 +0100
@@ -30,16 +30,14 @@
 import formencode
 import re
 
-from webob.exc import HTTPNotFound, HTTPForbidden, HTTPBadRequest
-
 from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
 from pylons.i18n.translation import _
+from webob.exc import HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest
 
 from kallithea.lib.vcs.utils.hgcompat import unionrepo
 from kallithea.lib.compat import json
 from kallithea.lib.base import BaseRepoController, render
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
     NotAnonymous
 from kallithea.lib.helpers import Page
 from kallithea.lib import helpers as h
@@ -49,7 +47,7 @@
 from kallithea.lib.vcs.utils import safe_str
 from kallithea.lib.vcs.exceptions import EmptyRepositoryError
 from kallithea.lib.diffs import LimitedDiffContainer
-from kallithea.model.db import PullRequest, ChangesetStatus, ChangesetComment,\
+from kallithea.model.db import PullRequest, ChangesetStatus, ChangesetComment, \
     PullRequestReviewers, User
 from kallithea.model.pull_request import PullRequestModel
 from kallithea.model.meta import Session
@@ -212,15 +210,15 @@
                 s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
             return s
 
-        c.my_pull_requests = _filter(PullRequest.query()\
+        c.my_pull_requests = _filter(PullRequest.query() \
                                 .filter(PullRequest.user_id ==
-                                        self.authuser.user_id)\
+                                        self.authuser.user_id) \
                                 .all())
 
-        c.participate_in_pull_requests = _filter(PullRequest.query()\
-                                .join(PullRequestReviewers)\
+        c.participate_in_pull_requests = _filter(PullRequest.query() \
+                                .join(PullRequestReviewers) \
                                 .filter(PullRequestReviewers.user_id ==
-                                        self.authuser.user_id)\
+                                        self.authuser.user_id) \
                                                  )
 
         return render('/pullrequests/pullrequest_show_my.html')
@@ -237,7 +235,7 @@
         except EmptyRepositoryError as e:
             h.flash(h.literal(_('There are no changesets yet')),
                     category='warning')
-            redirect(url('summary_home', repo_name=org_repo.repo_name))
+            raise HTTPFound(location=url('summary_home', repo_name=org_repo.repo_name))
 
         org_rev = request.GET.get('rev_end')
         # rev_start is not directly useful - its parent could however be used
@@ -369,9 +367,9 @@
             h.flash(_('Error occurred while creating pull request'),
                     category='error')
             log.error(traceback.format_exc())
-            return redirect(url('pullrequest_home', repo_name=repo_name))
+            raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name))
 
-        return redirect(pull_request.url())
+        raise HTTPFound(location=pull_request.url())
 
     def create_update(self, old_pull_request, updaterev, title, description, reviewers_ids):
         org_repo = RepoModel()._get_repo(old_pull_request.org_repo.repo_name)
@@ -456,7 +454,7 @@
             h.flash(_('Error occurred while creating pull request'),
                     category='error')
             log.error(traceback.format_exc())
-            return redirect(old_pull_request.url())
+            raise HTTPFound(location=old_pull_request.url())
 
         ChangesetCommentsModel().create(
             text=_('Closed, replaced by %s .') % pull_request.url(canonical=True),
@@ -470,7 +468,7 @@
         h.flash(_('Pull request update created'),
                 category='success')
 
-        return redirect(pull_request.url())
+        raise HTTPFound(location=pull_request.url())
 
     # pullrequest_post for PR editing
     @LoginRequired()
@@ -513,7 +511,7 @@
         Session().commit()
         h.flash(_('Pull request updated'), category='success')
 
-        return redirect(pull_request.url())
+        raise HTTPFound(location=pull_request.url())
 
     @LoginRequired()
     @NotAnonymous()
@@ -528,7 +526,7 @@
             Session().commit()
             h.flash(_('Successfully deleted pull request'),
                     category='success')
-            return redirect(url('my_pullrequests'))
+            raise HTTPFound(location=url('my_pullrequests'))
         raise HTTPForbidden()
 
     @LoginRequired()
@@ -762,7 +760,7 @@
         Session().commit()
 
         if not request.environ.get('HTTP_X_PARTIAL_XHR'):
-            return redirect(pull_request.url())
+            raise HTTPFound(location=pull_request.url())
 
         data = {
            'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
--- a/kallithea/controllers/search.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/search.py	Wed Jan 20 01:41:02 2016 +0100
@@ -139,7 +139,7 @@
                 log.error('Empty Index data')
                 c.runtime = _('There is no index to search in. '
                               'Please run whoosh indexer')
-            except (Exception):
+            except Exception:
                 log.error(traceback.format_exc())
                 c.runtime = _('An error occurred during search operation.')
 
--- a/kallithea/controllers/summary.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/controllers/summary.py	Wed Jan 20 01:41:02 2016 +0100
@@ -44,7 +44,7 @@
 from kallithea.model.db import Statistics, CacheInvalidation, User
 from kallithea.lib.utils import jsonify
 from kallithea.lib.utils2 import safe_str
-from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
+from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
     NotAnonymous
 from kallithea.lib.base import BaseRepoController, render
 from kallithea.lib.vcs.backends.base import EmptyChangeset
@@ -114,8 +114,9 @@
     def index(self, repo_name):
         _load_changelog_summary()
 
-        username = ''
-        if self.authuser.username != User.DEFAULT_USER:
+        if self.authuser.is_default_user:
+            username = ''
+        else:
             username = safe_str(self.authuser.username)
 
         _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
@@ -134,8 +135,8 @@
         else:
             c.show_stats = False
 
-        stats = self.sa.query(Statistics)\
-            .filter(Statistics.repository == c.db_repo)\
+        stats = self.sa.query(Statistics) \
+            .filter(Statistics.repository == c.db_repo) \
             .scalar()
 
         c.stats_percentage = 0
@@ -192,8 +193,8 @@
         c.ts_min = ts_min_m
         c.ts_max = ts_max_y
 
-        stats = self.sa.query(Statistics)\
-            .filter(Statistics.repository == c.db_repo)\
+        stats = self.sa.query(Statistics) \
+            .filter(Statistics.repository == c.db_repo) \
             .scalar()
         c.stats_percentage = 0
         if stats and stats.languages:
@@ -210,7 +211,7 @@
                 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
             )
             last_rev = stats.stat_on_revision + 1
-            c.repo_last_rev = c.db_repo_scm_instance.count()\
+            c.repo_last_rev = c.db_repo_scm_instance.count() \
                 if c.db_repo_scm_instance.revisions else 0
             if last_rev == 0 or c.repo_last_rev == 0:
                 pass
--- a/kallithea/i18n/cs/LC_MESSAGES/kallithea.po	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/i18n/cs/LC_MESSAGES/kallithea.po	Wed Jan 20 01:41:02 2016 +0100
@@ -11,7 +11,7 @@
 "PO-Revision-Date: 2015-11-12 08:51+0000\n"
 "Last-Translator: Michal ÄŒihaÅ™ <michal@cihar.com>\n"
 "Language-Team: Czech "
-"<https://hosted.weblate.org/projects/kallithea/stable/cs/>\n"
+"<https://hosted.weblate.org/projects/kallithea/kallithea/cs/>\n"
 "Language: cs\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
--- a/kallithea/i18n/de/LC_MESSAGES/kallithea.po	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/i18n/de/LC_MESSAGES/kallithea.po	Wed Jan 20 01:41:02 2016 +0100
@@ -11,7 +11,7 @@
 "PO-Revision-Date: 2015-09-08 10:56+0200\n"
 "Last-Translator: Robert Rauch <mail@robertrauch.de>\n"
 "Language-Team: German "
-"<https://hosted.weblate.org/projects/kallithea/stable/de/>\n"
+"<https://hosted.weblate.org/projects/kallithea/kallithea/de/>\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
--- a/kallithea/i18n/ja/LC_MESSAGES/kallithea.po	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/i18n/ja/LC_MESSAGES/kallithea.po	Wed Jan 20 01:41:02 2016 +0100
@@ -16,7 +16,7 @@
 "PO-Revision-Date: 2016-01-07 01:53+0000\n"
 "Last-Translator: Takumi IINO <trot.thunder@gmail.com>\n"
 "Language-Team: Japanese "
-"<https://hosted.weblate.org/projects/kallithea/stable/ja/>\n"
+"<https://hosted.weblate.org/projects/kallithea/kallithea/ja/>\n"
 "Language: ja\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
--- a/kallithea/lib/annotate.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/annotate.py	Wed Jan 20 01:41:02 2016 +0100
@@ -68,7 +68,7 @@
         following function as ``annotate_from_changeset_func``::
 
             def changeset_to_anchor(changeset):
-                return '<a href="/changesets/%s/">%s</a>\n' %\
+                return '<a href="/changesets/%s/">%s</a>\n' % \
                        (changeset.id, changeset.id)
 
         :param annotate_from_changeset_func: see above
--- a/kallithea/lib/auth.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/auth.py	Wed Jan 20 01:41:02 2016 +0100
@@ -35,12 +35,12 @@
 from decorator import decorator
 
 from pylons import url, request, session
-from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
 from webhelpers.pylonslib import secure_form
 from sqlalchemy import or_
 from sqlalchemy.orm.exc import ObjectDeletedError
 from sqlalchemy.orm import joinedload
+from webob.exc import HTTPFound, HTTPBadRequest, HTTPForbidden, HTTPMethodNotAllowed
 
 from kallithea import __platform__, is_windows, is_unix
 from kallithea.lib.vcs.utils.lazy import LazyProperty
@@ -204,8 +204,8 @@
     #==================================================================
 
     # default global permissions taken from the default user
-    default_global_perms = UserToPerm.query()\
-        .filter(UserToPerm.user_id == default_user_id)\
+    default_global_perms = UserToPerm.query() \
+        .filter(UserToPerm.user_id == default_user_id) \
         .options(joinedload(UserToPerm.permission))
 
     for perm in default_global_perms:
@@ -251,15 +251,15 @@
 
     # USER GROUPS comes first
     # user group global permissions
-    user_perms_from_users_groups = Session().query(UserGroupToPerm)\
-        .options(joinedload(UserGroupToPerm.permission))\
+    user_perms_from_users_groups = Session().query(UserGroupToPerm) \
+        .options(joinedload(UserGroupToPerm.permission)) \
         .join((UserGroupMember, UserGroupToPerm.users_group_id ==
-               UserGroupMember.users_group_id))\
-        .filter(UserGroupMember.user_id == user_id)\
+               UserGroupMember.users_group_id)) \
+        .filter(UserGroupMember.user_id == user_id) \
         .join((UserGroup, UserGroupMember.users_group_id ==
-               UserGroup.users_group_id))\
-        .filter(UserGroup.users_group_active == True)\
-        .order_by(UserGroupToPerm.users_group_id)\
+               UserGroup.users_group_id)) \
+        .filter(UserGroup.users_group_active == True) \
+        .order_by(UserGroupToPerm.users_group_id) \
         .all()
     # need to group here by groups since user can be in more than
     # one group
@@ -273,20 +273,20 @@
         if not gr.inherit_default_permissions:
             # NEED TO IGNORE all configurable permissions and
             # replace them with explicitly set
-            permissions[GLOBAL] = permissions[GLOBAL]\
+            permissions[GLOBAL] = permissions[GLOBAL] \
                                             .difference(_configurable)
         for perm in perms:
             permissions[GLOBAL].add(perm.permission.permission_name)
 
     # user specific global permissions
-    user_perms = Session().query(UserToPerm)\
-            .options(joinedload(UserToPerm.permission))\
+    user_perms = Session().query(UserToPerm) \
+            .options(joinedload(UserToPerm.permission)) \
             .filter(UserToPerm.user_id == user_id).all()
 
     if not user_inherit_default_permissions:
         # NEED TO IGNORE all configurable permissions and
         # replace them with explicitly set
-        permissions[GLOBAL] = permissions[GLOBAL]\
+        permissions[GLOBAL] = permissions[GLOBAL] \
                                         .difference(_configurable)
 
         for perm in user_perms:
@@ -304,17 +304,17 @@
 
     # user group for repositories permissions
     user_repo_perms_from_users_groups = \
-     Session().query(UserGroupRepoToPerm, Permission, Repository,)\
+     Session().query(UserGroupRepoToPerm, Permission, Repository,) \
         .join((Repository, UserGroupRepoToPerm.repository_id ==
-               Repository.repo_id))\
+               Repository.repo_id)) \
         .join((Permission, UserGroupRepoToPerm.permission_id ==
-               Permission.permission_id))\
+               Permission.permission_id)) \
         .join((UserGroup, UserGroupRepoToPerm.users_group_id ==
-               UserGroup.users_group_id))\
-        .filter(UserGroup.users_group_active == True)\
+               UserGroup.users_group_id)) \
+        .filter(UserGroup.users_group_active == True) \
         .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
-               UserGroupMember.users_group_id))\
-        .filter(UserGroupMember.user_id == user_id)\
+               UserGroupMember.users_group_id)) \
+        .filter(UserGroupMember.user_id == user_id) \
         .all()
 
     multiple_counter = collections.defaultdict(int)
@@ -357,16 +357,16 @@
     #======================================================================
     # user group for repo groups permissions
     user_repo_group_perms_from_users_groups = \
-     Session().query(UserGroupRepoGroupToPerm, Permission, RepoGroup)\
-     .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
+     Session().query(UserGroupRepoGroupToPerm, Permission, RepoGroup) \
+     .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id)) \
      .join((Permission, UserGroupRepoGroupToPerm.permission_id
-            == Permission.permission_id))\
+            == Permission.permission_id)) \
      .join((UserGroup, UserGroupRepoGroupToPerm.users_group_id ==
-            UserGroup.users_group_id))\
-     .filter(UserGroup.users_group_active == True)\
+            UserGroup.users_group_id)) \
+     .filter(UserGroup.users_group_active == True) \
      .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
-            == UserGroupMember.users_group_id))\
-     .filter(UserGroupMember.user_id == user_id)\
+            == UserGroupMember.users_group_id)) \
+     .filter(UserGroupMember.user_id == user_id) \
      .all()
 
     multiple_counter = collections.defaultdict(int)
@@ -394,17 +394,17 @@
     #======================================================================
     # user group for user group permissions
     user_group_user_groups_perms = \
-     Session().query(UserGroupUserGroupToPerm, Permission, UserGroup)\
+     Session().query(UserGroupUserGroupToPerm, Permission, UserGroup) \
      .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
-            == UserGroup.users_group_id))\
+            == UserGroup.users_group_id)) \
      .join((Permission, UserGroupUserGroupToPerm.permission_id
-            == Permission.permission_id))\
+            == Permission.permission_id)) \
      .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
-            == UserGroupMember.users_group_id))\
-     .filter(UserGroupMember.user_id == user_id)\
+            == UserGroupMember.users_group_id)) \
+     .filter(UserGroupMember.user_id == user_id) \
      .join((UserGroup, UserGroupMember.users_group_id ==
-            UserGroup.users_group_id), aliased=True, from_joinpoint=True)\
-     .filter(UserGroup.users_group_active == True)\
+            UserGroup.users_group_id), aliased=True, from_joinpoint=True) \
+     .filter(UserGroup.users_group_active == True) \
      .all()
 
     multiple_counter = collections.defaultdict(int)
@@ -465,8 +465,7 @@
     access to Kallithea is enabled, the default user is loaded instead.
 
     `AuthUser` does not by itself authenticate users and the constructor
-    sets the `is_authenticated` field to False, except when falling back
-    to the default anonymous user (if enabled). It's up to other parts
+    sets the `is_authenticated` field to False. It's up to other parts
     of the code to check e.g. if a supplied password is correct, and if
     so, set `is_authenticated` to True.
 
@@ -508,9 +507,7 @@
         if not is_user_loaded:
             is_user_loaded =  self._fill_data(self.anonymous_user)
 
-        # The anonymous user is always "logged in".
-        if self.user_id == self.anonymous_user.user_id:
-            self.is_authenticated = True
+        self.is_default_user = (self.user_id == self.anonymous_user.user_id)
 
         if not self.username:
             self.username = 'None'
@@ -569,8 +566,8 @@
 
     def _get_api_keys(self):
         api_keys = [self.api_key]
-        for api_key in UserApiKeys.query()\
-                .filter(UserApiKeys.user_id == self.user_id)\
+        for api_key in UserApiKeys.query() \
+                .filter(UserApiKeys.user_id == self.user_id) \
                 .filter(or_(UserApiKeys.expires == -1,
                             UserApiKeys.expires >= time.time())).all():
             api_keys.append(api_key.api_key)
@@ -622,18 +619,13 @@
             return False
 
     def __repr__(self):
-        return "<AuthUser('id:%s[%s] auth:%s')>"\
-            % (self.user_id, self.username, self.is_authenticated)
-
-    def set_authenticated(self, authenticated=True):
-        if self.user_id != self.anonymous_user.user_id:
-            self.is_authenticated = authenticated
+        return "<AuthUser('id:%s[%s] auth:%s')>" \
+            % (self.user_id, self.username, (self.is_authenticated or self.is_default_user))
 
     def to_cookie(self):
         """ Serializes this login session to a cookie `dict`. """
         return {
             'user_id': self.user_id,
-            'is_authenticated': self.is_authenticated,
             'is_external_auth': self.is_external_auth,
         }
 
@@ -647,9 +639,7 @@
             user_id=cookie.get('user_id'),
             is_external_auth=cookie.get('is_external_auth', False),
         )
-        if not au.is_authenticated and au.user_id is not None:
-            # user is not authenticated and not empty
-            au.set_authenticated(cookie.get('is_authenticated'))
+        au.is_authenticated = True
         return au
 
     @classmethod
@@ -710,13 +700,16 @@
 # CHECK DECORATORS
 #==============================================================================
 
-def redirect_to_login(message=None):
+def _redirect_to_login(message=None):
+    """Return an exception that must be raised. It will redirect to the login
+    page which will redirect back to the current URL after authentication.
+    The optional message will be shown in a flash message."""
     from kallithea.lib import helpers as h
-    p = request.path_qs
     if message:
         h.flash(h.literal(message), category='warning')
+    p = request.path_qs
     log.debug('Redirecting to login page, origin: %s', p)
-    return redirect(url('login_home', came_from=p))
+    return HTTPFound(location=url('login_home', came_from=p))
 
 
 class LoginRequired(object):
@@ -741,7 +734,7 @@
         log.debug('Checking access for user %s @ %s', user, loc)
 
         if not AuthUser.check_ip_allowed(user, controller.ip_addr):
-            return redirect_to_login(_('IP %s not allowed') % controller.ip_addr)
+            raise _redirect_to_login(_('IP %s not allowed') % controller.ip_addr)
 
         # check if we used an API key and it's a valid one
         api_key = request.GET.get('api_key')
@@ -754,17 +747,17 @@
                     return func(*fargs, **fkwargs)
                 else:
                     log.warning('API key ****%s is NOT valid', api_key[-4:])
-                    return redirect_to_login(_('Invalid API key'))
+                    raise _redirect_to_login(_('Invalid API key'))
             else:
                 # controller does not allow API access
                 log.warning('API access to %s is not allowed', loc)
-                return abort(403)
+                raise HTTPForbidden()
 
         # Only allow the following HTTP request methods. (We sometimes use POST
         # requests with a '_method' set to 'PUT' or 'DELETE'; but that is only
         # used for the route lookup, and does not affect request.method.)
         if request.method not in ['GET', 'HEAD', 'POST', 'PUT']:
-            return abort(405)
+            raise HTTPMethodNotAllowed()
 
         # Make sure CSRF token never appears in the URL. If so, invalidate it.
         if secure_form.token_key in request.GET:
@@ -785,22 +778,22 @@
             token = request.POST.get(secure_form.token_key)
             if not token or token != secure_form.authentication_token():
                 log.error('CSRF check failed')
-                return abort(403)
+                raise HTTPForbidden()
 
         # WebOb already ignores request payload parameters for anything other
         # than POST/PUT, but double-check since other Kallithea code relies on
         # this assumption.
         if request.method not in ['POST', 'PUT'] and request.POST:
             log.error('%r request with payload parameters; WebOb should have stopped this', request.method)
-            return abort(400)
+            raise HTTPBadRequest()
 
         # regular user authentication
-        if user.is_authenticated:
+        if user.is_authenticated or user.is_default_user:
             log.info('user %s authenticated with regular auth @ %s', user, loc)
             return func(*fargs, **fkwargs)
         else:
             log.warning('user %s NOT authenticated with regular auth @ %s', user, loc)
-            return redirect_to_login()
+            raise _redirect_to_login()
 
 class NotAnonymous(object):
     """
@@ -816,11 +809,9 @@
 
         log.debug('Checking if user is not anonymous @%s', cls)
 
-        anonymous = self.user.username == User.DEFAULT_USER
-
-        if anonymous:
-            return redirect_to_login(_('You need to be a registered user to '
-                    'perform this action'))
+        if self.user.is_default_user:
+            raise _redirect_to_login(_('You need to be a registered user to '
+                                       'perform this action'))
         else:
             return func(*fargs, **fkwargs)
 
@@ -848,13 +839,10 @@
 
         else:
             log.debug('Permission denied for %s %s', cls, self.user)
-            anonymous = self.user.username == User.DEFAULT_USER
-
-            if anonymous:
-                return redirect_to_login(_('You need to be signed in to view this page'))
+            if self.user.is_default_user:
+                raise _redirect_to_login(_('You need to be signed in to view this page'))
             else:
-                # redirect with forbidden ret code
-                return abort(403)
+                raise HTTPForbidden()
 
     def check_permissions(self):
         """Dummy function for overriding"""
--- a/kallithea/lib/auth_modules/auth_container.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/auth_modules/auth_container.py	Wed Jan 20 01:41:02 2016 +0100
@@ -27,9 +27,9 @@
 
 import logging
 from kallithea.lib import auth_modules
-from kallithea.lib.utils2 import str2bool, safe_unicode
+from kallithea.lib.utils2 import str2bool, safe_unicode, safe_str
 from kallithea.lib.compat import hybrid_property
-from kallithea.model.db import User
+from kallithea.model.db import User, Setting
 
 log = logging.getLogger(__name__)
 
@@ -53,15 +53,39 @@
                 "name": "header",
                 "validator": self.validators.UnicodeString(strip=True, not_empty=True),
                 "type": "string",
-                "description": "Header to extract the user from",
+                "description": "Request header to extract the username from",
                 "default": "REMOTE_USER",
-                "formname": "Header"
+                "formname": "Username header"
+            },
+            {
+                "name": "email_header",
+                "validator": self.validators.UnicodeString(strip=True),
+                "type": "string",
+                "description": "Optional request header to extract the email from",
+                "default": "",
+                "formname": "Email header"
+            },
+            {
+                "name": "firstname_header",
+                "validator": self.validators.UnicodeString(strip=True),
+                "type": "string",
+                "description": "Optional request header to extract the first name from",
+                "default": "",
+                "formname": "Firstname header"
+            },
+            {
+                "name": "lastname_header",
+                "validator": self.validators.UnicodeString(strip=True),
+                "type": "string",
+                "description": "Optional request header to extract the last name from",
+                "default": "",
+                "formname": "Lastname header"
             },
             {
                 "name": "fallback_header",
                 "validator": self.validators.UnicodeString(strip=True),
                 "type": "string",
-                "description": "Header to extract the user from when main one fails",
+                "description": "Request header to extract the user from when main one fails",
                 "default": "HTTP_X_FORWARDED_USER",
                 "formname": "Fallback header"
             },
@@ -158,7 +182,7 @@
         # only way to log in is using environ
         username = None
         if userobj:
-            username = getattr(userobj, 'username')
+            username = safe_str(getattr(userobj, 'username'))
 
         if not username:
             # we don't have any objects in DB, user doesn't exist, extract
@@ -172,9 +196,9 @@
         # old attrs fetched from Kallithea database
         admin = getattr(userobj, 'admin', False)
         active = getattr(userobj, 'active', True)
-        email = getattr(userobj, 'email', '')
-        firstname = getattr(userobj, 'firstname', '')
-        lastname = getattr(userobj, 'lastname', '')
+        email = environ.get(settings.get('email_header'), getattr(userobj, 'email', ''))
+        firstname = environ.get(settings.get('firstname_header'), getattr(userobj, 'firstname', ''))
+        lastname = environ.get(settings.get('lastname_header'), getattr(userobj, 'lastname', ''))
 
         user_data = {
             'username': username,
@@ -192,4 +216,11 @@
         return user_data
 
     def get_managed_fields(self):
-        return ['username', 'password']
+        fields = ['username', 'password']
+        if(Setting.get_by_name('auth_container_email_header').app_settings_value):
+            fields.append('email')
+        if(Setting.get_by_name('auth_container_firstname_header').app_settings_value):
+            fields.append('firstname')
+        if(Setting.get_by_name('auth_container_lastname_header').app_settings_value):
+            fields.append('lastname')
+        return fields
--- a/kallithea/lib/auth_modules/auth_ldap.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/auth_modules/auth_ldap.py	Wed Jan 20 01:41:02 2016 +0100
@@ -356,7 +356,7 @@
         except (LdapUsernameError, LdapPasswordError, LdapImportError):
             log.error(traceback.format_exc())
             return None
-        except (Exception,):
+        except Exception:
             log.error(traceback.format_exc())
             return None
 
--- a/kallithea/lib/base.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/base.py	Wed Jan 20 01:41:02 2016 +0100
@@ -40,13 +40,12 @@
 
 from pylons import config, tmpl_context as c, request, session, url
 from pylons.controllers import WSGIController
-from pylons.controllers.util import redirect
 from pylons.templating import render_mako as render  # don't remove this import
 from pylons.i18n.translation import _
 
 from kallithea import __version__, BACKENDS
 
-from kallithea.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
+from kallithea.lib.utils2 import str2bool, safe_unicode, AttributeDict, \
     safe_str, safe_int
 from kallithea.lib import auth_modules
 from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
@@ -117,7 +116,9 @@
 
     auth_user = AuthUser(dbuser=user,
                          is_external_auth=is_external_auth)
-    auth_user.set_authenticated()
+    # It should not be possible to explicitly log in as the default user.
+    assert not auth_user.is_default_user
+    auth_user.is_authenticated = True
 
     # Start new session to prevent session fixation attacks.
     session.invalidate()
@@ -366,7 +367,7 @@
 
         c.repo_name = get_repo_slug(request)  # can be empty
         c.backends = BACKENDS.keys()
-        c.unread_notifications = NotificationModel()\
+        c.unread_notifications = NotificationModel() \
                         .get_unread_cnt_for_user(c.authuser.user_id)
 
         self.cut_off_limit = safe_int(config.get('cut_off_limit'))
@@ -392,7 +393,9 @@
         # Authenticate by session cookie
         # In ancient login sessions, 'authuser' may not be a dict.
         # In that case, the user will have to log in again.
-        if isinstance(session_authuser, dict):
+        # v0.3 and earlier included an 'is_authenticated' key; if present,
+        # this must be True.
+        if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
             try:
                 return AuthUser.from_cookie(session_authuser)
             except UserCreationError as e:
@@ -479,7 +482,7 @@
                 if route in ['repo_creating_home']:
                     return
                 check_url = url('repo_creating_home', repo_name=c.repo_name)
-                return redirect(check_url)
+                raise webob.exc.HTTPFound(location=check_url)
 
             dbr = c.db_repo = _dbr
             c.db_repo_scm_instance = c.db_repo.scm_instance
--- a/kallithea/lib/celerylib/tasks.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/celerylib/tasks.py	Wed Jan 20 01:41:02 2016 +0100
@@ -26,7 +26,7 @@
 :license: GPLv3, see LICENSE.md for more details.
 """
 
-from celery.decorators import task
+from celery.task import task
 
 import os
 import traceback
@@ -76,7 +76,7 @@
 
     index_location = config['index_dir']
     WhooshIndexingDaemon(index_location=index_location,
-                         repo_location=repo_location, sa=DBS)\
+                         repo_location=repo_location, sa=DBS) \
                          .run(full_index=full_index)
 
 
@@ -116,9 +116,9 @@
         last_cs = None
         timegetter = itemgetter('time')
 
-        dbrepo = DBS.query(Repository)\
+        dbrepo = DBS.query(Repository) \
             .filter(Repository.repo_name == repo_name).scalar()
-        cur_stats = DBS.query(Statistics)\
+        cur_stats = DBS.query(Statistics) \
             .filter(Statistics.repository == dbrepo).scalar()
 
         if cur_stats is not None:
@@ -176,7 +176,7 @@
                                     "changed": len(cs.changed),
                                     "removed": len(cs.removed),
                                    }
-                        co_day_auth_aggr[akc(cs.author)]['data']\
+                        co_day_auth_aggr[akc(cs.author)]['data'] \
                             .append(datadict)
 
             else:
--- a/kallithea/lib/colored_formatter.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/colored_formatter.py	Wed Jan 20 01:41:02 2016 +0100
@@ -42,19 +42,19 @@
 def format_sql(sql):
     sql = sql.replace('\n', '')
     sql = one_space_trim(sql)
-    sql = sql\
-        .replace(',', ',\n\t')\
-        .replace('SELECT', '\n\tSELECT \n\t')\
-        .replace('UPDATE', '\n\tUPDATE \n\t')\
-        .replace('DELETE', '\n\tDELETE \n\t')\
-        .replace('FROM', '\n\tFROM')\
-        .replace('ORDER BY', '\n\tORDER BY')\
-        .replace('LIMIT', '\n\tLIMIT')\
-        .replace('WHERE', '\n\tWHERE')\
-        .replace('AND', '\n\tAND')\
-        .replace('LEFT', '\n\tLEFT')\
-        .replace('INNER', '\n\tINNER')\
-        .replace('INSERT', '\n\tINSERT')\
+    sql = sql \
+        .replace(',', ',\n\t') \
+        .replace('SELECT', '\n\tSELECT \n\t') \
+        .replace('UPDATE', '\n\tUPDATE \n\t') \
+        .replace('DELETE', '\n\tDELETE \n\t') \
+        .replace('FROM', '\n\tFROM') \
+        .replace('ORDER BY', '\n\tORDER BY') \
+        .replace('LIMIT', '\n\tLIMIT') \
+        .replace('WHERE', '\n\tWHERE') \
+        .replace('AND', '\n\tAND') \
+        .replace('LEFT', '\n\tLEFT') \
+        .replace('INNER', '\n\tINNER') \
+        .replace('INSERT', '\n\tINSERT') \
         .replace('DELETE', '\n\tDELETE')
     return sql
 
--- a/kallithea/lib/compat.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/compat.py	Wed Jan 20 01:41:02 2016 +0100
@@ -540,7 +540,8 @@
                 return cmp(type(self), type(other))
             return cmp(list(self), list(other))
 
-        def __repr__(self, _track=[]):
+        def __repr__(self, _track=None):
+            _track = _track or []
             if id(self) in _track:
                 return '...'
             _track.append(id(self))
@@ -560,8 +561,9 @@
         def __copy__(self):
             return self.__class__(self)
 
-        def __deepcopy__(self, memo={}):
+        def __deepcopy__(self, memo=None):
             from copy import deepcopy
+            memo = memo or {}
             result = self.__class__()
             memo[id(self)] = result
             result.__init__(deepcopy(tuple(self), memo))
--- a/kallithea/lib/db_manage.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/db_manage.py	Wed Jan 20 01:41:02 2016 +0100
@@ -61,14 +61,14 @@
 
 
 class DbManage(object):
-    def __init__(self, log_sql, dbconf, root, tests=False, SESSION=None, cli_args={}):
+    def __init__(self, log_sql, dbconf, root, tests=False, SESSION=None, cli_args=None):
         self.dbname = dbconf.split('/')[-1]
         self.tests = tests
         self.root = root
         self.dburi = dbconf
         self.log_sql = log_sql
         self.db_exists = False
-        self.cli_args = cli_args
+        self.cli_args = cli_args or {}
         self.init_db(SESSION=SESSION)
 
         force_ask = self.cli_args.get('force_ask')
@@ -184,8 +184,8 @@
         Fixes a old kallithea version path into new one without a '*'
         """
 
-        paths = self.sa.query(Ui)\
-                .filter(Ui.ui_key == '/')\
+        paths = self.sa.query(Ui) \
+                .filter(Ui.ui_key == '/') \
                 .scalar()
 
         paths.ui_value = paths.ui_value.replace('*', '')
@@ -198,8 +198,8 @@
         Fixes a old default user with some 'nicer' default values,
         used mostly for anonymous access
         """
-        def_user = self.sa.query(User)\
-                .filter(User.username == User.DEFAULT_USER)\
+        def_user = self.sa.query(User) \
+                .filter(User.username == User.DEFAULT_USER) \
                 .one()
 
         def_user.name = 'Anonymous'
@@ -278,7 +278,7 @@
 
         #HOOKS
         hooks1_key = Ui.HOOK_UPDATE
-        hooks1_ = self.sa.query(Ui)\
+        hooks1_ = self.sa.query(Ui) \
             .filter(Ui.ui_key == hooks1_key).scalar()
 
         hooks1 = Ui() if hooks1_ is None else hooks1_
@@ -289,7 +289,7 @@
         self.sa.add(hooks1)
 
         hooks2_key = Ui.HOOK_REPO_SIZE
-        hooks2_ = self.sa.query(Ui)\
+        hooks2_ = self.sa.query(Ui) \
             .filter(Ui.ui_key == hooks2_key).scalar()
         hooks2 = Ui() if hooks2_ is None else hooks2_
         hooks2.ui_section = 'hooks'
@@ -390,9 +390,9 @@
             g.group_name = g.get_new_name(g.name)
             self.sa.add(g)
             # get default perm
-            default = UserRepoGroupToPerm.query()\
-                .filter(UserRepoGroupToPerm.group == g)\
-                .filter(UserRepoGroupToPerm.user == def_usr)\
+            default = UserRepoGroupToPerm.query() \
+                .filter(UserRepoGroupToPerm.group == g) \
+                .filter(UserRepoGroupToPerm.user == def_usr) \
                 .scalar()
 
             if default is None:
@@ -411,7 +411,7 @@
         if not default_user:
             return
 
-        u2p = UserToPerm.query()\
+        u2p = UserToPerm.query() \
             .filter(UserToPerm.user == default_user).all()
         fixed = False
         if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
@@ -522,7 +522,7 @@
     def create_user(self, username, password, email='', admin=False):
         log.info('creating user %s', username)
         UserModel().create_or_update(username, password, email,
-                                     firstname='Kallithea', lastname='Admin',
+                                     firstname=u'Kallithea', lastname=u'Admin',
                                      active=True, admin=admin,
                                      extern_type=EXTERN_TYPE_INTERNAL)
 
@@ -532,8 +532,8 @@
         user = UserModel().create_or_update(username=User.DEFAULT_USER,
                                             password=str(uuid.uuid1())[:20],
                                             email='anonymous@kallithea-scm.org',
-                                            firstname='Anonymous',
-                                            lastname='User')
+                                            firstname=u'Anonymous',
+                                            lastname=u'User')
         # based on configuration options activate/deactivate this user which
         # controls anonymous access
         if self.cli_args.get('public_access') is False:
--- a/kallithea/lib/dbmigrate/migrate/changeset/constraint.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/migrate/changeset/constraint.py	Wed Jan 20 01:41:02 2016 +0100
@@ -146,7 +146,7 @@
     Migrate's additional parameters:
 
     :param sqltext: Plain SQL text to check condition
-    :param columns: If not name is applied, you must supply this kw\
+    :param columns: If not name is applied, you must supply this kw \
     to autoname constraint
     :param table: If columns are passed as strings, this kw is required
     :type table: Table instance
--- a/kallithea/lib/dbmigrate/migrate/changeset/schema.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/migrate/changeset/schema.py	Wed Jan 20 01:41:02 2016 +0100
@@ -180,7 +180,7 @@
         * **current_col_name, \*p, \*\*kw**
             Table kw must specified.
 
-        :param table: Table at which current Column should be bound to.\
+        :param table: Table at which current Column should be bound to. \
         If table name is given, reflection will be used.
         :type table: string or Table instance
 
@@ -499,9 +499,9 @@
 
         :param table: Table instance to create on.
         :param index_name: Creates :class:`ChangesetIndex` on this column.
-        :param unique_name: Creates :class:\
+        :param unique_name: Creates :class: \
 `~migrate.changeset.constraint.UniqueConstraint` on this column.
-        :param primary_key_name: Creates :class:\
+        :param primary_key_name: Creates :class: \
 `~migrate.changeset.constraint.PrimaryKeyConstraint` on this column.
         :param populate_default: If True, created column will be \
 populated with defaults
--- a/kallithea/lib/dbmigrate/migrate/versioning/api.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/migrate/versioning/api.py	Wed Jan 20 01:41:02 2016 +0100
@@ -181,7 +181,7 @@
     You may preview the Python or SQL code to be executed, rather than
     actually executing it, using the appropriate 'preview' option.
     """
-    err = "Cannot upgrade a database of version %s to version %s. "\
+    err = "Cannot upgrade a database of version %s to version %s. " \
         "Try 'downgrade' instead."
     return _migrate(url, repository, version, upgrade=True, err=err, **opts)
 
@@ -197,7 +197,7 @@
     You may preview the Python or SQL code to be executed, rather than
     actually executing it, using the appropriate 'preview' option.
     """
-    err = "Cannot downgrade a database of version %s to version %s. "\
+    err = "Cannot downgrade a database of version %s to version %s. " \
         "Try 'upgrade' instead."
     return _migrate(url, repository, version, upgrade=False, err=err, **opts)
 
--- a/kallithea/lib/dbmigrate/migrate/versioning/repository.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/migrate/versioning/repository.py	Wed Jan 20 01:41:02 2016 +0100
@@ -238,7 +238,7 @@
         :param file_: Destination file to be written
         :param opts: Options that are passed to :func:`migrate.versioning.shell.main`
         """
-        mng_file = Template(opts.pop('templates_path', None))\
+        mng_file = Template(opts.pop('templates_path', None)) \
             .get_manage(theme=opts.pop('templates_theme', None))
 
         tmpl = open(mng_file).read()
--- a/kallithea/lib/dbmigrate/migrate/versioning/schema.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/migrate/versioning/schema.py	Wed Jan 20 01:41:02 2016 +0100
@@ -67,7 +67,7 @@
         else:
             try:
                 self.table.drop()
-            except (sa_exceptions.SQLError):
+            except sa_exceptions.SQLError:
                 raise exceptions.DatabaseNotControlledError(str(self.table))
 
     def changeset(self, version=None):
--- a/kallithea/lib/dbmigrate/schema/db_1_2_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_2_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -182,7 +182,7 @@
 
     @classmethod
     def get_by_name(cls, ldap_key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == ldap_key).scalar()
 
     @classmethod
@@ -204,7 +204,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -380,10 +380,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.users_group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.users_group_name == group_name)
         if cache:
             gr = gr.options(FromCache("sql_cache_short",
@@ -445,7 +445,7 @@
         try:
 
             # check if this group is not assigned to repo
-            assigned_groups = UserGroupRepoToPerm.query()\
+            assigned_groups = UserGroupRepoToPerm.query() \
                 .filter(UserGroupRepoToPerm.users_group_id ==
                         users_group_id).all()
 
@@ -526,8 +526,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session.query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.one()
 
@@ -616,7 +616,7 @@
         baseui._tcfg = config.config()
 
 
-        ret = Ui.query()\
+        ret = Ui.query() \
             .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 
         hg_ui = ret
@@ -758,10 +758,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache("sql_cache_short",
@@ -879,7 +879,7 @@
         if not isinstance(perm, Permission):
             raise Exception('perm needs to be an instance of Permission class')
 
-        return cls.query().filter(cls.user_id == user_id)\
+        return cls.query().filter(cls.user_id == user_id) \
             .filter(cls.permission == perm).scalar() is not None
 
     @classmethod
@@ -941,8 +941,8 @@
             raise Exception('perm needs to be an instance of Permission class')
 
         return cls.query().filter(cls.users_group_id ==
-                                         users_group_id)\
-                                         .filter(cls.permission == perm)\
+                                         users_group_id) \
+                                         .filter(cls.permission == perm) \
                                          .scalar() is not None
 
     @classmethod
@@ -1047,9 +1047,9 @@
 
         :param key:
         """
-        return cls.query()\
-                .filter(CacheInvalidation.cache_key == key)\
-                .filter(CacheInvalidation.cache_active == False)\
+        return cls.query() \
+                .filter(CacheInvalidation.cache_key == key) \
+                .filter(CacheInvalidation.cache_active == False) \
                 .scalar()
 
     @classmethod
@@ -1061,7 +1061,7 @@
         """
 
         log.debug('marking %s for invalidation', key)
-        inv_obj = Session.query(cls)\
+        inv_obj = Session.query(cls) \
             .filter(cls.cache_key == key).scalar()
         if inv_obj:
             inv_obj.cache_active = False
@@ -1083,7 +1083,7 @@
 
         :param key:
         """
-        inv_obj = Session.query(CacheInvalidation)\
+        inv_obj = Session.query(CacheInvalidation) \
             .filter(CacheInvalidation.cache_key == key).scalar()
         inv_obj.cache_active = True
         Session.add(inv_obj)
--- a/kallithea/lib/dbmigrate/schema/db_1_3_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_3_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -201,7 +201,7 @@
 
     @classmethod
     def get_by_name(cls, ldap_key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == ldap_key).scalar()
 
     @classmethod
@@ -223,7 +223,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -533,8 +533,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session.query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -549,7 +549,7 @@
 
         :param cls:
         """
-        q = Session.query(Ui)\
+        q = Session.query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -622,7 +622,7 @@
         baseui._ucfg = config.config()
         baseui._tcfg = config.config()
 
-        ret = Ui.query()\
+        ret = Ui.query() \
             .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
 
         hg_ui = ret
@@ -671,7 +671,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -783,10 +783,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -838,8 +838,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -887,18 +887,18 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session.query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session.query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session.query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1204,8 +1204,8 @@
         :param cls:
         :param revision:
         """
-        return Session.query(User)\
-                .filter(cls.revision == revision)\
+        return Session.query(User) \
+                .filter(cls.revision == revision) \
                 .join(ChangesetComment.author).all()
 
 
@@ -1234,7 +1234,7 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
+        return [x.user for x in UserNotification.query() \
                 .filter(UserNotification.notification == self).all()]
 
     @classmethod
--- a/kallithea/lib/dbmigrate/schema/db_1_4_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_4_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -191,7 +191,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -220,7 +220,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -672,8 +672,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -693,7 +693,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -762,9 +762,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -886,7 +886,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -903,8 +903,8 @@
         :type revisions: list
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1051,10 +1051,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1106,8 +1106,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1216,18 +1216,18 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1596,7 +1596,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -1753,8 +1753,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
--- a/kallithea/lib/dbmigrate/schema/db_1_5_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_5_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -194,7 +194,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -223,7 +223,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -233,7 +233,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -691,8 +691,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -712,7 +712,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -781,9 +781,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -905,7 +905,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -922,8 +922,8 @@
         :type revisions: list
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1070,10 +1070,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1125,8 +1125,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1243,18 +1243,18 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1623,7 +1623,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -1780,8 +1780,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
--- a/kallithea/lib/dbmigrate/schema/db_1_5_2.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_5_2.py	Wed Jan 20 01:41:02 2016 +0100
@@ -196,7 +196,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -225,7 +225,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -235,7 +235,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -757,8 +757,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -779,7 +779,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -848,9 +848,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1023,7 +1023,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1040,8 +1040,8 @@
         :type revisions: list
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1191,10 +1191,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1246,8 +1246,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1356,18 +1356,18 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1736,7 +1736,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -1901,8 +1901,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
--- a/kallithea/lib/dbmigrate/schema/db_1_6_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_6_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -196,7 +196,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -225,7 +225,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -235,7 +235,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -713,8 +713,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -826,8 +826,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -848,7 +848,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -917,9 +917,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1093,7 +1093,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1110,8 +1110,8 @@
         :type revisions: list
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1266,10 +1266,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1321,8 +1321,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1441,18 +1441,18 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1811,7 +1811,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -1980,8 +1980,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
--- a/kallithea/lib/dbmigrate/schema/db_1_7_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_7_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -201,7 +201,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -230,7 +230,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -240,7 +240,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -742,8 +742,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -855,8 +855,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -877,7 +877,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -946,9 +946,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1124,7 +1124,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1140,8 +1140,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1284,10 +1284,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1339,8 +1339,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1497,27 +1497,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1907,7 +1907,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2076,8 +2076,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2176,7 +2176,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_1_8_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_1_8_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -203,7 +203,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -232,7 +232,7 @@
 
     @classmethod
     def get_ldap_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
@@ -242,7 +242,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -772,8 +772,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -885,8 +885,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -907,7 +907,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -976,9 +976,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1154,7 +1154,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1170,8 +1170,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1314,10 +1314,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1369,8 +1369,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1543,27 +1543,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1953,7 +1953,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2123,8 +2123,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2223,7 +2223,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_0_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_0_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -218,7 +218,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -278,7 +278,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -288,7 +288,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -829,8 +829,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -942,8 +942,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -964,7 +964,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1033,9 +1033,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1211,7 +1211,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1227,8 +1227,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1371,10 +1371,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1426,8 +1426,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1600,27 +1600,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2013,7 +2013,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2183,8 +2183,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2283,7 +2283,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_0_1.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_0_1.py	Wed Jan 20 01:41:02 2016 +0100
@@ -221,7 +221,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -281,7 +281,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -291,7 +291,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -828,8 +828,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -941,8 +941,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -963,7 +963,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1032,9 +1032,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1210,7 +1210,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1226,8 +1226,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1372,10 +1372,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1427,8 +1427,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1601,27 +1601,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2014,7 +2014,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2184,8 +2184,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2284,7 +2284,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_0_2.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_0_2.py	Wed Jan 20 01:41:02 2016 +0100
@@ -221,7 +221,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -281,7 +281,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -291,7 +291,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -828,8 +828,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -958,8 +958,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -980,7 +980,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1049,9 +1049,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1230,7 +1230,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1246,8 +1246,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1393,10 +1393,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1448,8 +1448,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1622,27 +1622,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2035,7 +2035,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2205,8 +2205,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2305,7 +2305,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_1_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_1_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -224,7 +224,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -284,7 +284,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -294,7 +294,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -523,10 +523,10 @@
 
         if fallback and not res:
             #fallback to additional keys
-            _res = UserApiKeys.query()\
-                .filter(UserApiKeys.api_key == api_key)\
+            _res = UserApiKeys.query() \
+                .filter(UserApiKeys.api_key == api_key) \
                 .filter(or_(UserApiKeys.expires == -1,
-                            UserApiKeys.expires >= time.time()))\
+                            UserApiKeys.expires >= time.time())) \
                 .first()
             if _res:
                 res = _res.user
@@ -866,8 +866,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -997,8 +997,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -1019,7 +1019,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1088,9 +1088,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1269,7 +1269,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1285,8 +1285,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1432,10 +1432,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1487,8 +1487,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1661,27 +1661,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2074,7 +2074,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2244,8 +2244,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2344,7 +2344,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_2_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_2_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -225,7 +225,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -285,7 +285,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -295,7 +295,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -550,10 +550,10 @@
 
         if fallback and not res:
             #fallback to additional keys
-            _res = UserApiKeys.query()\
-                .filter(UserApiKeys.api_key == api_key)\
+            _res = UserApiKeys.query() \
+                .filter(UserApiKeys.api_key == api_key) \
                 .filter(or_(UserApiKeys.expires == -1,
-                            UserApiKeys.expires >= time.time()))\
+                            UserApiKeys.expires >= time.time())) \
                 .first()
             if _res:
                 res = _res.user
@@ -901,8 +901,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -1037,8 +1037,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -1059,7 +1059,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1128,9 +1128,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1315,7 +1315,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1331,8 +1331,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1482,10 +1482,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1537,8 +1537,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1714,27 +1714,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2127,7 +2127,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2297,8 +2297,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2401,7 +2401,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/schema/db_2_2_3.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/schema/db_2_2_3.py	Wed Jan 20 01:41:02 2016 +0100
@@ -225,7 +225,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -285,7 +285,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -295,7 +295,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -550,10 +550,10 @@
 
         if fallback and not res:
             #fallback to additional keys
-            _res = UserApiKeys.query()\
-                .filter(UserApiKeys.api_key == api_key)\
+            _res = UserApiKeys.query() \
+                .filter(UserApiKeys.api_key == api_key) \
                 .filter(or_(UserApiKeys.expires == -1,
-                            UserApiKeys.expires >= time.time()))\
+                            UserApiKeys.expires >= time.time())) \
                 .first()
             if _res:
                 res = _res.user
@@ -919,8 +919,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -1057,8 +1057,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -1079,7 +1079,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1148,9 +1148,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1342,7 +1342,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions:
             cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
@@ -1358,8 +1358,8 @@
         :param revisions: list of revisions to get statuses for
         """
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
             .filter(ChangesetStatus.version == 0)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
@@ -1509,10 +1509,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1564,8 +1564,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1741,27 +1741,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -2173,7 +2173,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision:
             q = q.filter(cls.revision == revision)
@@ -2343,8 +2343,8 @@
 
     @property
     def recipients(self):
-        return [x.user for x in UserNotification.query()\
-                .filter(UserNotification.notification == self)\
+        return [x.user for x in UserNotification.query() \
+                .filter(UserNotification.notification == self) \
                 .order_by(UserNotification.user_id.asc()).all()]
 
     @classmethod
@@ -2447,7 +2447,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
--- a/kallithea/lib/dbmigrate/versions/001_initial_release.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/versions/001_initial_release.py	Wed Jan 20 01:41:02 2016 +0100
@@ -77,7 +77,7 @@
             session.add(self)
             session.commit()
             log.debug('updated user %s lastlogin', self.username)
-        except (DatabaseError,):
+        except DatabaseError:
             session.rollback()
 
 
--- a/kallithea/lib/dbmigrate/versions/008_version_1_5_0.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/dbmigrate/versions/008_version_1_5_0.py	Wed Jan 20 01:41:02 2016 +0100
@@ -32,8 +32,8 @@
 
     _Session = meta.Session()
     ## after adding that column fix all usernames
-    users_log = _Session.query(db_1_5_0.UserLog)\
-            .options(joinedload(db_1_5_0.UserLog.user))\
+    users_log = _Session.query(db_1_5_0.UserLog) \
+            .options(joinedload(db_1_5_0.UserLog.user)) \
             .options(joinedload(db_1_5_0.UserLog.repository)).all()
 
     for entry in users_log:
--- a/kallithea/lib/diffs.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/diffs.py	Wed Jan 20 01:41:02 2016 +0100
@@ -364,7 +364,7 @@
         groups = match.groupdict()
         rest = diff_chunk[match.end():]
         if rest and not rest.startswith('@') and not rest.startswith('literal ') and not rest.startswith('delta '):
-            raise Exception('cannot parse diff header: %r followed by %r' % (diff_chunk[:match.end()], rest[:1000]))
+            raise Exception('cannot parse %s diff header: %r followed by %r' % (self.vcs, diff_chunk[:match.end()], rest[:1000]))
         difflines = imap(self._escaper, re.findall(r'.*\n|.+$', rest)) # don't split on \r as str.splitlines do
         return groups, difflines
 
--- a/kallithea/lib/helpers.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/helpers.py	Wed Jan 20 01:41:02 2016 +0100
@@ -54,7 +54,7 @@
 from kallithea.lib.annotate import annotate_highlight
 from kallithea.lib.utils import repo_name_slug, get_custom_lexer
 from kallithea.lib.utils2 import str2bool, safe_unicode, safe_str, \
-    get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict,\
+    get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict, \
     safe_int
 from kallithea.lib.markup_renderer import MarkupRenderer, url_re
 from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError
@@ -483,11 +483,6 @@
         user = User.get_by_email(email, case_insensitive=True, cache=True)
         if user is not None:
             return user
-
-    user = User.get_by_username(author_name(author), case_insensitive=True, cache=True)
-    if user is not None:
-        return user
-
     return None
 
 def email_or_none(author):
@@ -802,8 +797,8 @@
     if feed:
         action = action_str[0].replace('[', '').replace(']', '')
     else:
-        action = action_str[0]\
-            .replace('[', '<span class="journal_highlight">')\
+        action = action_str[0] \
+            .replace('[', '<span class="journal_highlight">') \
             .replace(']', '</span>')
 
     action_params_func = lambda: ""
@@ -879,10 +874,10 @@
 
         tmpl = _gravatar_url
         parsed_url = urlparse.urlparse(url.current(qualified=True))
-        tmpl = tmpl.replace('{email}', email_address)\
+        tmpl = tmpl.replace('{email}', email_address) \
                    .replace('{md5email}', _md5(safe_str(email_address).lower())) \
-                   .replace('{netloc}', parsed_url.netloc)\
-                   .replace('{scheme}', parsed_url.scheme)\
+                   .replace('{netloc}', parsed_url.netloc) \
+                   .replace('{scheme}', parsed_url.scheme) \
                    .replace('{size}', safe_str(size))
         return tmpl
 
@@ -979,18 +974,17 @@
         show_if_single_page=False, separator=' ', onclick=None,
         symbol_first='<<', symbol_last='>>',
         symbol_previous='<', symbol_next='>',
-        link_attr={'class': 'pager_link', 'rel': 'prerender'},
-        curpage_attr={'class': 'pager_curpage'},
-        dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
-
-        self.curpage_attr = curpage_attr
+        link_attr=None,
+        curpage_attr=None,
+        dotdot_attr=None, **kwargs):
+        self.curpage_attr = curpage_attr or {'class': 'pager_curpage'}
         self.separator = separator
         self.pager_kwargs = kwargs
         self.page_param = page_param
         self.partial_param = partial_param
         self.onclick = onclick
-        self.link_attr = link_attr
-        self.dotdot_attr = dotdot_attr
+        self.link_attr = link_attr or {'class': 'pager_link', 'rel': 'prerender'}
+        self.dotdot_attr = dotdot_attr or {'class': 'pager_dotdot'}
 
         # Don't show navigator if there is no more than one page
         if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
--- a/kallithea/lib/indexers/daemon.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/indexers/daemon.py	Wed Jan 20 01:41:02 2016 +0100
@@ -41,7 +41,7 @@
 project_path = dn(dn(dn(dn(os.path.realpath(__file__)))))
 sys.path.append(project_path)
 
-from kallithea.config.conf import INDEX_EXTENSIONS
+from kallithea.config.conf import INDEX_EXTENSIONS, INDEX_FILENAMES
 from kallithea.model.scm import ScmModel
 from kallithea.model.db import Repository
 from kallithea.lib.utils2 import safe_unicode, safe_str
@@ -162,6 +162,13 @@
         node = cs.get_node(node_path)
         return node
 
+    def is_indexable_node(self, node):
+        """
+        Just index the content of chosen files, skipping binary files
+        """
+        return (node.extension in INDEX_EXTENSIONS or node.name in INDEX_FILENAMES) and \
+               not node.is_binary
+
     def get_node_mtime(self, node):
         return mktime(node.last_changeset.date.timetuple())
 
@@ -177,8 +184,7 @@
             return 0, 0
 
         indexed = indexed_w_content = 0
-        # we just index the content of chosen files, and skip binary files
-        if node.extension in INDEX_EXTENSIONS and not node.is_binary:
+        if self.is_indexable_node(node):
             u_content = node.content
             if not isinstance(u_content, unicode):
                 log.warning('  >> %s Could not get this content as unicode '
--- a/kallithea/lib/middleware/simplegit.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/middleware/simplegit.py	Wed Jan 20 01:41:02 2016 +0100
@@ -38,7 +38,7 @@
     HTTPNotAcceptable
 from kallithea.model.db import User, Ui
 
-from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url,\
+from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url, \
     _set_extras
 from kallithea.lib.base import BaseVCSController, WSGIResultCloseCallback
 from kallithea.lib.utils import make_ui, is_valid_repo
@@ -295,12 +295,11 @@
         if action == 'pull' and _hooks.get(Ui.HOOK_PULL):
             log_pull_action(ui=baseui, repo=_repo._repo)
 
-    def __inject_extras(self, repo_path, baseui, extras={}):
+    def __inject_extras(self, repo_path, baseui, extras=None):
         """
         Injects some extra params into baseui instance
 
         :param baseui: baseui instance
         :param extras: dict with extra params to put into baseui
         """
-
-        _set_extras(extras)
+        _set_extras(extras or {})
--- a/kallithea/lib/middleware/simplehg.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/middleware/simplehg.py	Wed Jan 20 01:41:02 2016 +0100
@@ -37,7 +37,7 @@
     HTTPNotAcceptable
 from kallithea.model.db import User
 
-from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url,\
+from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url, \
     _set_extras
 from kallithea.lib.base import BaseVCSController, WSGIResultCloseCallback
 from kallithea.lib.utils import make_ui, is_valid_repo, ui_sections
@@ -275,7 +275,7 @@
         raise Exception('Unable to detect pull/push action !!'
                         'Are you using non standard command or client ?')
 
-    def __inject_extras(self, repo_path, baseui, extras={}):
+    def __inject_extras(self, repo_path, baseui, extras=None):
         """
         Injects some extra params into baseui instance
 
@@ -294,4 +294,4 @@
             for section in ui_sections:
                 for k, v in repoui.configitems(section):
                     baseui.setconfig(section, k, v)
-        _set_extras(extras)
+        _set_extras(extras or {})
--- a/kallithea/lib/paster_commands/cache_keys.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/cache_keys.py	Wed Jan 20 01:41:02 2016 +0100
@@ -29,7 +29,6 @@
 
 import os
 import sys
-import logging
 
 from kallithea.model.meta import Session
 from kallithea.lib.utils import BasePasterCommand
@@ -40,8 +39,6 @@
 rc_path = dn(dn(dn(os.path.realpath(__file__))))
 sys.path.append(rc_path)
 
-log = logging.getLogger(__name__)
-
 
 class Command(BasePasterCommand):
 
@@ -57,6 +54,7 @@
     def command(self):
         #get SqlAlchemy session
         self._init_session()
+
         _caches = CacheInvalidation.query().order_by(CacheInvalidation.cache_key).all()
         if self.options.show:
             for c_obj in _caches:
@@ -64,11 +62,10 @@
         elif self.options.cleanup:
             for c_obj in _caches:
                 Session().delete(c_obj)
-                print 'removing key:%s' % (c_obj.cache_key)
+                print 'Removing key: %s' % (c_obj.cache_key)
                 Session().commit()
         else:
-            print 'nothing done exiting...'
-        sys.exit(0)
+            print 'Nothing done, exiting...'
 
     def update_parser(self):
         self.parser.add_option(
--- a/kallithea/lib/paster_commands/cleanup.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/cleanup.py	Wed Jan 20 01:41:02 2016 +0100
@@ -22,7 +22,7 @@
 Original author and date, and relevant copyright and licensing information is below:
 :created_on: Jul 14, 2012
 :author: marcink
-:copyright: (c) 2013 RhodeCode GmbH.
+:copyright: (c) 2013 RhodeCode GmbH, and others.
 :license: GPLv3, see LICENSE.md for more details.
 """
 
@@ -31,7 +31,6 @@
 import sys
 import re
 import shutil
-import logging
 import datetime
 
 from kallithea.lib.utils import BasePasterCommand, ask_ok, REMOVED_REPO_PAT
@@ -43,8 +42,6 @@
 rc_path = dn(dn(dn(os.path.realpath(__file__))))
 sys.path.append(rc_path)
 
-log = logging.getLogger(__name__)
-
 
 class Command(BasePasterCommand):
 
@@ -110,27 +107,25 @@
                     to_remove_filtered.append([name, date_])
 
             to_remove = to_remove_filtered
-            print >> sys.stdout, 'removing %s deleted repos older than %s (%s)' \
+            print 'Removing %s deleted repos older than %s (%s)' \
                 % (len(to_remove), older_than, older_than_date)
         else:
-            print >> sys.stdout, 'removing all [%s] deleted repos' \
-                % len(to_remove)
+            print 'Removing all %s deleted repos' % len(to_remove)
         if self.options.dont_ask or not to_remove:
             # don't ask just remove !
             remove = True
         else:
             remove = ask_ok('the following repositories will be deleted completely:\n%s\n'
                             'are you sure you want to remove them [y/n]?'
-                            % ', \n'.join(['%s removed on %s'
-                    % (safe_str(x[0]), safe_str(x[1])) for x in to_remove]))
+                            % '\n'.join(['%s removed on %s' % (safe_str(x[0]), safe_str(x[1]))
+                                         for x in to_remove]))
 
         if remove:
             for path, date_ in to_remove:
-                print >> sys.stdout, 'removing repository %s' % path
+                print 'Removing repository %s' % path
                 shutil.rmtree(path)
         else:
-            print 'nothing done exiting...'
-            sys.exit(0)
+            print 'Nothing done, exiting...'
 
     def update_parser(self):
         self.parser.add_option(
--- a/kallithea/lib/paster_commands/install_iis.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/install_iis.py	Wed Jan 20 01:41:02 2016 +0100
@@ -1,3 +1,24 @@
+# -*- coding: utf-8 -*-
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+kallithea.lib.paster_commands.install_iis
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+IIS installation tools for Kallithea
+"""
+
+
 import os
 import sys
 from paste.script.appinstall import AbstractInstallCommand
@@ -37,7 +58,9 @@
         except ImportError:
             raise BadCommand('missing requirement: isapi-wsgi not installed')
 
-        file = '''import sys
+        file = '''\
+# Created by Kallithea install_iis
+import sys
 
 if hasattr(sys, "isapidllhandle"):
     import win32traceutil
@@ -78,8 +101,8 @@
 
         dispatchfile = os.path.join(os.getcwd(), 'dispatch.py')
         self.ensure_file(dispatchfile, outdata, False)
-        print 'generating', dispatchfile
+        print 'Generating %s' % (dispatchfile,)
 
-        print ('run \'python "%s" install\' with administrative privileges '
+        print ('Run \'python "%s" install\' with administrative privileges '
             'to generate the _dispatch.dll file and install it into the '
             'default web site') % (dispatchfile,)
--- a/kallithea/lib/paster_commands/ishell.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/ishell.py	Wed Jan 20 01:41:02 2016 +0100
@@ -28,7 +28,6 @@
 
 import os
 import sys
-import logging
 
 from kallithea.lib.utils import BasePasterCommand
 
@@ -37,8 +36,6 @@
 rc_path = dn(dn(dn(os.path.realpath(__file__))))
 sys.path.append(rc_path)
 
-log = logging.getLogger(__name__)
-
 
 class Command(BasePasterCommand):
 
@@ -55,7 +52,7 @@
         #get SqlAlchemy session
         self._init_session()
 
-        # imports, used in ipython shell
+        # imports, used in IPython shell
         import os
         import sys
         import time
@@ -70,7 +67,7 @@
             cfg.InteractiveShellEmbed.confirm_exit = False
             embed(config=cfg, banner1="Kallithea IShell.")
         except ImportError:
-            print 'ipython installation required for ishell'
+            print 'IPython installation is required for ishell'
             sys.exit(-1)
 
     def update_parser(self):
--- a/kallithea/lib/paster_commands/make_index.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/make_index.py	Wed Jan 20 01:41:02 2016 +0100
@@ -23,13 +23,11 @@
 :author: marcink
 :copyright: (c) 2013 RhodeCode GmbH, and others.
 :license: GPLv3, see LICENSE.md for more details.
-
 """
 
 
 import os
 import sys
-import logging
 
 from string import strip
 from kallithea.model.repo import RepoModel
@@ -53,7 +51,6 @@
     summary = "Creates or updates full text search index"
 
     def command(self):
-        logging.config.fileConfig(self.path_to_ini_file)
         #get SqlAlchemy session
         self._init_session()
         from pylons import config
@@ -79,7 +76,7 @@
             WhooshIndexingDaemon(index_location=index_location,
                                  repo_location=repo_location,
                                  repo_list=repo_list,
-                                 repo_update_list=repo_update_list)\
+                                 repo_update_list=repo_update_list) \
                 .run(full_index=self.options.full_index)
             l.release()
         except LockHeld:
--- a/kallithea/lib/paster_commands/make_rcextensions.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/make_rcextensions.py	Wed Jan 20 01:41:02 2016 +0100
@@ -23,7 +23,6 @@
 :author: marcink
 :copyright: (c) 2013 RhodeCode GmbH, and others.
 :license: GPLv3, see LICENSE.md for more details.
-
 """
 
 
@@ -67,7 +66,7 @@
             msg = ('Extension file already exists, do you want '
                    'to overwrite it ? [y/n]')
             if not ask_ok(msg):
-                print 'Nothing done...'
+                print 'Nothing done, exiting...'
                 return
 
         dirname = os.path.dirname(ext_file)
--- a/kallithea/lib/paster_commands/repo_scan.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/repo_scan.py	Wed Jan 20 01:41:02 2016 +0100
@@ -28,7 +28,6 @@
 
 import os
 import sys
-import logging
 
 from kallithea.model.scm import ScmModel
 from kallithea.lib.utils import BasePasterCommand, repo2db_mapper
@@ -38,8 +37,6 @@
 rc_path = dn(dn(dn(os.path.realpath(__file__))))
 sys.path.append(rc_path)
 
-log = logging.getLogger(__name__)
-
 
 class Command(BasePasterCommand):
 
--- a/kallithea/lib/paster_commands/setup_db.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/setup_db.py	Wed Jan 20 01:41:02 2016 +0100
@@ -1,3 +1,24 @@
+# -*- coding: utf-8 -*-
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+kallithea.lib.paster_commands.setup_db
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Databaset setup paster command for Kallithea
+"""
+
+
 import os
 import sys
 from paste.script.appinstall import AbstractInstallCommand
@@ -20,11 +41,10 @@
     group_name = "Kallithea"
 
     description = """\
-
-    Setup Kallithea according to its configuration file.  This is
-    the second part of a two-phase web application installation
-    process (the first phase is prepare-app).  The setup process
-    consist of things like setting up databases, creating super user
+        Setup Kallithea according to its configuration file.  This is
+        the second part of a two-phase web application installation
+        process (the first phase is prepare-app).  The setup process
+        consist of things like setting up databases, creating super user
     """
 
     parser = AbstractInstallCommand.standard_parser(
@@ -74,6 +94,7 @@
                        dest='public_access',
                        default=None,
                        help='Disable public access on this installation ')
+
     def command(self):
         config_spec = self.args[0]
         section = self.options.section_name
@@ -100,7 +121,7 @@
         dist = conf.context.distribution
         if dist is None:
             raise BadCommand(
-                "The section %r is not the application (probably a filter).  "
+                "The section %r is not the application (probably a filter). "
                 "You should add #section_name, where section_name is the "
                 "section that configures your application" % plain_section)
         installer = self.get_installer(dist, ep_group, ep_name)
--- a/kallithea/lib/paster_commands/update_repoinfo.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/paster_commands/update_repoinfo.py	Wed Jan 20 01:41:02 2016 +0100
@@ -28,7 +28,6 @@
 
 import os
 import sys
-import logging
 import string
 
 from kallithea.lib.utils import BasePasterCommand
@@ -41,8 +40,6 @@
 rc_path = dn(dn(dn(os.path.realpath(__file__))))
 sys.path.append(rc_path)
 
-log = logging.getLogger(__name__)
-
 
 class Command(BasePasterCommand):
 
@@ -64,7 +61,7 @@
                                if self.options.repo_update_list else None
 
         if repo_update_list is not None:
-            repo_list = list(Repository.query()\
+            repo_list = list(Repository.query() \
                 .filter(Repository.repo_name.in_(repo_update_list)))
         else:
             repo_list = Repository.getAll()
--- a/kallithea/lib/rcmail/smtp_mailer.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/rcmail/smtp_mailer.py	Wed Jan 20 01:41:02 2016 +0100
@@ -60,9 +60,9 @@
         self.debug = debug
         self.auth = smtp_auth
 
-    def send(self, recipients=[], subject='', body='', html='',
+    def send(self, recipients=None, subject='', body='', html='',
              attachment_files=None, headers=None):
-
+        recipients = recipients or []
         if isinstance(recipients, basestring):
             recipients = [recipients]
         if headers is None:
--- a/kallithea/lib/utils.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/utils.py	Wed Jan 20 01:41:02 2016 +0100
@@ -186,7 +186,7 @@
         repo_obj = Repository.get_by_repo_name(repo_name)
     else:
         repo_obj = None
-        repo_name = ''
+        repo_name = u''
 
     user_log = UserLog()
     user_log.user_id = user_obj.user_id
@@ -418,6 +418,21 @@
                                                         'utf8'), sep=',')
 
 
+def set_indexer_config(config):
+    """
+    Update Whoosh index mapping
+
+    :param config: kallithea.CONFIG
+    """
+    from kallithea.config import conf
+
+    log.debug('adding extra into INDEX_EXTENSIONS')
+    conf.INDEX_EXTENSIONS.extend(re.split('\s+', config.get('index.extensions', '')))
+
+    log.debug('adding extra into INDEX_FILENAMES')
+    conf.INDEX_FILENAMES.extend(re.split('\s+', config.get('index.filenames', '')))
+
+
 def map_groups(path):
     """
     Given a full path to a repository, create all nested groups that this
@@ -436,7 +451,7 @@
     rgm = RepoGroupModel(sa)
     owner = User.get_first_admin()
     for lvl, group_name in enumerate(groups):
-        group_name = '/'.join(groups[:lvl] + [group_name])
+        group_name = u'/'.join(groups[:lvl] + [group_name])
         group = RepoGroup.get_by_group_name(group_name)
         desc = '%s group' % group_name
 
@@ -639,7 +654,7 @@
     try:
         l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
         WhooshIndexingDaemon(index_location=index_location,
-                             repo_location=repo_location)\
+                             repo_location=repo_location) \
             .run(full_index=full_index)
         l.release()
     except LockHeld:
@@ -775,11 +790,10 @@
         Inits SqlAlchemy Session
         """
         logging.config.fileConfig(self.path_to_ini_file)
+
         from pylons import config
         from kallithea.model import init_model
         from kallithea.lib.utils2 import engine_from_config
-
-        #get to remove repos !!
         add_cache(config)
         engine = engine_from_config(config, 'sqlalchemy.db1.')
         init_model(engine)
--- a/kallithea/lib/utils2.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/utils2.py	Wed Jan 20 01:41:02 2016 +0100
@@ -78,6 +78,25 @@
     return dict(d)
 
 
+def __get_index_filenames():
+    """
+    Get list of known indexable filenames from pygment lexer internals
+    """
+    from pygments import lexers
+    from itertools import ifilter
+
+    filenames = []
+
+    def likely_filename(s):
+        return s.find('*') == -1 and s.find('[') == -1
+
+    for lx, t in sorted(lexers.LEXERS.items()):
+        for f in ifilter(likely_filename, t[-2]):
+            filenames.append(f)
+
+    return filenames
+
+
 def str2bool(_str):
     """
     returs True/False value from given string, it tries to translate the
--- a/kallithea/lib/vcs/backends/git/inmemory.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/backends/git/inmemory.py	Wed Jan 20 01:41:02 2016 +0100
@@ -40,7 +40,7 @@
         ENCODING = "UTF-8"
 
         # Create tree and populates it with blobs
-        commit_tree = self.parents[0] and repo[self.parents[0]._commit.tree] or\
+        commit_tree = self.parents[0] and repo[self.parents[0]._commit.tree] or \
             objects.Tree()
         for node in self.added + self.changed:
             # Compute subdirs if needed
--- a/kallithea/lib/vcs/backends/hg/repository.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/backends/hg/repository.py	Wed Jan 20 01:41:02 2016 +0100
@@ -361,10 +361,10 @@
             return localrepository(self.baseui, self.path, create=create)
         except (Abort, RepoError) as err:
             if create:
-                msg = "Cannot create repository at %s. Original error was %s"\
+                msg = "Cannot create repository at %s. Original error was %s" \
                     % (self.path, err)
             else:
-                msg = "Not valid repository at %s. Original error was %s"\
+                msg = "Not valid repository at %s. Original error was %s" \
                     % (self.path, err)
             raise RepositoryError(msg)
 
--- a/kallithea/lib/vcs/subprocessio.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/subprocessio.py	Wed Jan 20 01:41:02 2016 +0100
@@ -156,8 +156,8 @@
     """
 
     def __init__(self, source, buffer_size=65536, chunk_size=4096,
-                 starting_values=[], bottomless=False):
-
+                 starting_values=None, bottomless=False):
+        starting_values = starting_values or []
         if bottomless:
             maxlen = int(buffer_size / chunk_size)
         else:
@@ -326,7 +326,7 @@
     """
 
     def __init__(self, cmd, inputstream=None, buffer_size=65536,
-                 chunk_size=4096, starting_values=[], **kwargs):
+                 chunk_size=4096, starting_values=None, **kwargs):
         """
         Initializes SubprocessIOChunker
 
@@ -336,7 +336,7 @@
         :param chunk_size: (Default: 4096) A max size of a chunk. Actual chunk may be smaller.
         :param starting_values: (Default: []) An array of strings to put in front of output que.
         """
-
+        starting_values = starting_values or []
         if inputstream:
             input_streamer = StreamFeeder(inputstream)
             input_streamer.start()
--- a/kallithea/lib/vcs/utils/__init__.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/utils/__init__.py	Wed Jan 20 01:41:02 2016 +0100
@@ -171,9 +171,9 @@
                               r"""0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]"""
                               r"""*[a-z0-9])?""", re.IGNORECASE)
         m = re.findall(email_re, author)
-        return m[0] if m else ''
+        return safe_str(m[0]) if m else ''
 
-    return author[l + 1:r].strip()
+    return safe_str(author[l + 1:r].strip())
 
 
 def author_name(author):
@@ -186,5 +186,5 @@
         return ''
     if not '@' in author:
         return author
-    return author.replace(author_email(author), '').replace('<', '')\
+    return author.replace(author_email(author), '').replace('<', '') \
         .replace('>', '').strip()
--- a/kallithea/lib/vcs/utils/annotate.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/utils/annotate.py	Wed Jan 20 01:41:02 2016 +0100
@@ -41,7 +41,7 @@
         following function as ``annotate_from_changeset_func``::
 
             def changeset_to_anchor(changeset):
-                return '<a href="/changesets/%s/">%s</a>\n' %\
+                return '<a href="/changesets/%s/">%s</a>\n' % \
                        (changeset.id, changeset.id)
 
         :param annotate_from_changeset_func: see above
--- a/kallithea/lib/vcs/utils/compat.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/utils/compat.py	Wed Jan 20 01:41:02 2016 +0100
@@ -120,7 +120,8 @@
                 return cmp(type(self), type(other))
             return cmp(list(self), list(other))
 
-        def __repr__(self, _track=[]):
+        def __repr__(self, _track=None):
+            _track = _track or []
             if id(self) in _track:
                 return '...'
             _track.append(id(self))
@@ -140,8 +141,9 @@
         def __copy__(self):
             return self.__class__(self)
 
-        def __deepcopy__(self, memo={}):
+        def __deepcopy__(self, memo=None):
             from copy import deepcopy
+            memo = memo or {}
             result = self.__class__()
             memo[id(self)] = result
             result.__init__(deepcopy(tuple(self), memo))
--- a/kallithea/lib/vcs/utils/diffs.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/utils/diffs.py	Wed Jan 20 01:41:02 2016 +0100
@@ -389,15 +389,15 @@
         diff_lines = self.prepare()
         _html_empty = True
         _html = []
-        _html.append('''<table class="%(table_class)s">\n''' \
-                                            % {'table_class': table_class})
+        _html.append('''<table class="%(table_class)s">\n'''
+                     % {'table_class': table_class})
         for diff in diff_lines:
             for line in diff['chunks']:
                 _html_empty = False
                 for change in line:
-                    _html.append('''<tr class="%(line_class)s %(action)s">\n''' \
-                        % {'line_class': line_class,
-                           'action': change['action']})
+                    _html.append('''<tr class="%(line_class)s %(action)s">\n'''
+                                 % {'line_class': line_class,
+                                    'action': change['action']})
                     anchor_old_id = ''
                     anchor_new_id = ''
                     anchor_old = "%(filename)s_o%(oldline_no)s" % \
@@ -417,35 +417,32 @@
                     ###########################################################
                     # OLD LINE NUMBER
                     ###########################################################
-                    _html.append('''\t<td %(a_id)s class="%(old_lineno_cls)s">''' \
-                                    % {'a_id': anchor_old_id,
-                                       'old_lineno_cls': old_lineno_class})
+                    _html.append('''\t<td %(a_id)s class="%(old_lineno_cls)s">'''
+                                  % {'a_id': anchor_old_id,
+                                     'old_lineno_cls': old_lineno_class})
 
-                    _html.append('''<pre>%(link)s</pre>''' \
-                        % {'link':
-                        _link_to_if(cond_old, change['old_lineno'], '#%s' \
-                                                                % anchor_old)})
+                    _html.append('''<pre>%(link)s</pre>'''
+                                 % {'link':
+                                    _link_to_if(cond_old, change['old_lineno'], '#%s' % anchor_old)})
                     _html.append('''</td>\n''')
                     ###########################################################
                     # NEW LINE NUMBER
                     ###########################################################
 
-                    _html.append('''\t<td %(a_id)s class="%(new_lineno_cls)s">''' \
-                                    % {'a_id': anchor_new_id,
-                                       'new_lineno_cls': new_lineno_class})
+                    _html.append('''\t<td %(a_id)s class="%(new_lineno_cls)s">'''
+                                  % {'a_id': anchor_new_id,
+                                     'new_lineno_cls': new_lineno_class})
 
-                    _html.append('''<pre>%(link)s</pre>''' \
-                        % {'link':
-                        _link_to_if(cond_new, change['new_lineno'], '#%s' \
-                                                                % anchor_new)})
+                    _html.append('''<pre>%(link)s</pre>'''
+                                 % {'link': _link_to_if(cond_new, change['new_lineno'], '#%s' % anchor_new)})
                     _html.append('''</td>\n''')
                     ###########################################################
                     # CODE
                     ###########################################################
-                    _html.append('''\t<td class="%(code_class)s">''' \
-                                                % {'code_class': code_class})
-                    _html.append('''\n\t\t<pre>%(code)s</pre>\n''' \
-                                                % {'code': change['line']})
+                    _html.append('''\t<td class="%(code_class)s">'''
+                                 % {'code_class': code_class})
+                    _html.append('''\n\t\t<pre>%(code)s</pre>\n'''
+                                 % {'code': change['line']})
                     _html.append('''\t</td>''')
                     _html.append('''\n</tr>\n''')
         _html.append('''</table>''')
--- a/kallithea/lib/vcs/utils/imports.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/lib/vcs/utils/imports.py	Wed Jan 20 01:41:02 2016 +0100
@@ -19,7 +19,7 @@
     try:
         class_mod = __import__(mod_path, {}, {}, [class_name])
     except ImportError as err:
-        msg = "There was problem while trying to import backend class. "\
+        msg = "There was problem while trying to import backend class. " \
             "Original error was:\n%s" % err
         raise VCSError(msg)
     cls = getattr(class_mod, class_name)
--- a/kallithea/model/api_key.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/api_key.py	Wed Jan 20 01:41:02 2016 +0100
@@ -73,10 +73,10 @@
 
     def get_api_keys(self, user, show_expired=True):
         user = self._get_user(user)
-        user_api_keys = UserApiKeys.query()\
+        user_api_keys = UserApiKeys.query() \
             .filter(UserApiKeys.user_id == user.user_id)
         if not show_expired:
-            user_api_keys = user_api_keys\
+            user_api_keys = user_api_keys \
                 .filter(or_(UserApiKeys.expires == -1,
                             UserApiKeys.expires >= time.time()))
         return user_api_keys
--- a/kallithea/model/changeset_status.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/changeset_status.py	Wed Jan 20 01:41:02 2016 +0100
@@ -49,7 +49,7 @@
                           with_revisions=False):
         repo = self._get_repo(repo)
 
-        q = ChangesetStatus.query()\
+        q = ChangesetStatus.query() \
             .filter(ChangesetStatus.repo == repo)
         if not with_revisions:
             q = q.filter(ChangesetStatus.version == 0)
--- a/kallithea/model/comment.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/comment.py	Wed Jan 20 01:41:02 2016 +0100
@@ -210,7 +210,7 @@
                 email_kwargs=email_kwargs,
             )
 
-            mention_recipients = set(self._extract_mentions(body))\
+            mention_recipients = set(self._extract_mentions(body)) \
                                     .difference(recipients)
             if mention_recipients:
                 email_kwargs['is_mention'] = True
@@ -260,16 +260,16 @@
         q = Session().query(ChangesetComment)
 
         if inline:
-            q = q.filter(ChangesetComment.line_no != None)\
+            q = q.filter(ChangesetComment.line_no != None) \
                 .filter(ChangesetComment.f_path != None)
         else:
-            q = q.filter(ChangesetComment.line_no == None)\
+            q = q.filter(ChangesetComment.line_no == None) \
                 .filter(ChangesetComment.f_path == None)
 
-        if revision:
-            q = q.filter(ChangesetComment.revision == revision)\
+        if revision is not None:
+            q = q.filter(ChangesetComment.revision == revision) \
                 .filter(ChangesetComment.repo_id == repo_id)
-        elif pull_request:
+        elif pull_request is not None:
             pull_request = self.__get_pull_request(pull_request)
             q = q.filter(ChangesetComment.pull_request == pull_request)
         else:
--- a/kallithea/model/db.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/db.py	Wed Jan 20 01:41:02 2016 +0100
@@ -158,13 +158,16 @@
         return '<DB:%s>' % (self.__class__.__name__)
 
 
+_table_args_default_dict = {'extend_existing': True,
+                            'mysql_engine': 'InnoDB',
+                            'mysql_charset': 'utf8',
+                            'sqlite_autoincrement': True,
+                           }
+
 class Setting(Base, BaseModel):
     __tablename__ = DB_PREFIX + 'settings'
-
     __table_args__ = (
-        UniqueConstraint('app_settings_name'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
 
     SETTINGS_TYPES = {
@@ -176,10 +179,10 @@
     }
     DEFAULT_UPDATE_URL = ''
 
-    app_settings_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    app_settings_name = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    _app_settings_value = Column("app_settings_value", String(4096, convert_unicode=False), nullable=True, unique=None, default=None)
-    _app_settings_type = Column("app_settings_type", String(255, convert_unicode=False), nullable=True, unique=None, default=None)
+    app_settings_id = Column(Integer(), unique=True, primary_key=True)
+    app_settings_name = Column(String(255), nullable=False, unique=True)
+    _app_settings_value = Column("app_settings_value", Unicode(4096), nullable=False)
+    _app_settings_type = Column("app_settings_type", String(255), nullable=True) # FIXME: not nullable?
 
     def __init__(self, key='', val='', type='unicode'):
         self.app_settings_name = key
@@ -226,7 +229,7 @@
 
     @classmethod
     def get_by_name(cls, key):
-        return cls.query()\
+        return cls.query() \
             .filter(cls.app_settings_name == key).scalar()
 
     @classmethod
@@ -286,7 +289,7 @@
 
     @classmethod
     def get_auth_settings(cls, cache=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('auth_')).all()
         fd = {}
         for row in ret:
@@ -295,7 +298,7 @@
 
     @classmethod
     def get_default_repo_settings(cls, cache=False, strip_prefix=False):
-        ret = cls.query()\
+        ret = cls.query() \
                 .filter(cls.app_settings_name.startswith('default_')).all()
         fd = {}
         for row in ret:
@@ -327,9 +330,11 @@
 class Ui(Base, BaseModel):
     __tablename__ = DB_PREFIX + 'ui'
     __table_args__ = (
+        # FIXME: ui_key as key is wrong and should be removed when the corresponding
+        # Ui.get_by_key has been replaced by the composite key
         UniqueConstraint('ui_key'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        UniqueConstraint('ui_section', 'ui_key'),
+        _table_args_default_dict,
     )
 
     HOOK_UPDATE = 'changegroup.update'
@@ -339,16 +344,11 @@
     HOOK_PULL = 'outgoing.pull_logger'
     HOOK_PRE_PULL = 'preoutgoing.pre_pull'
 
-    ui_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    ui_section = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    ui_key = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    ui_value = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    ui_active = Column(Boolean(), nullable=True, unique=None, default=True)
-
-    # def __init__(self, section='', key='', value=''):
-    #     self.ui_section = section
-    #     self.ui_key = key
-    #     self.ui_value = value
+    ui_id = Column(Integer(), unique=True, primary_key=True)
+    ui_section = Column(String(255), nullable=False)
+    ui_key = Column(String(255), nullable=False)
+    ui_value = Column(String(255), nullable=True) # FIXME: not nullable?
+    ui_active = Column(Boolean(), nullable=False, default=True)
 
     @classmethod
     def get_by_key(cls, key):
@@ -393,30 +393,29 @@
 class User(Base, BaseModel):
     __tablename__ = 'users'
     __table_args__ = (
-        UniqueConstraint('username'), UniqueConstraint('email'),
         Index('u_username_idx', 'username'),
         Index('u_email_idx', 'email'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
+
     DEFAULT_USER = 'default'
     DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
 
-    user_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    username = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    password = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    active = Column(Boolean(), nullable=True, unique=None, default=True)
-    admin = Column(Boolean(), nullable=True, unique=None, default=False)
-    name = Column("firstname", String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    lastname = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    _email = Column("email", String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    last_login = Column(DateTime(timezone=False), nullable=True, unique=None, default=None)
-    extern_type = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    extern_name = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    api_key = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    inherit_default_permissions = Column(Boolean(), nullable=False, unique=None, default=True)
+    user_id = Column(Integer(), unique=True, primary_key=True)
+    username = Column(String(255), nullable=False, unique=True)
+    password = Column(String(255), nullable=False)
+    active = Column(Boolean(), nullable=False, default=True)
+    admin = Column(Boolean(), nullable=False, default=False)
+    name = Column("firstname", Unicode(255), nullable=False)
+    lastname = Column(Unicode(255), nullable=False)
+    _email = Column("email", String(255), nullable=True, unique=True) # FIXME: not nullable?
+    last_login = Column(DateTime(timezone=False), nullable=True)
+    extern_type = Column(String(255), nullable=True) # FIXME: not nullable?
+    extern_name = Column(String(255), nullable=True) # FIXME: not nullable?
+    api_key = Column(String(255), nullable=False)
+    inherit_default_permissions = Column(Boolean(), nullable=False, default=True)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
-    _user_data = Column("user_data", LargeBinary(), nullable=True)  # JSON data
+    _user_data = Column("user_data", LargeBinary(), nullable=True)  # JSON data # FIXME: not nullable?
 
     user_log = relationship('UserLog')
     user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
@@ -575,10 +574,10 @@
 
         if fallback and not res:
             #fallback to additional keys
-            _res = UserApiKeys.query()\
-                .filter(UserApiKeys.api_key == api_key)\
+            _res = UserApiKeys.query() \
+                .filter(UserApiKeys.api_key == api_key) \
                 .filter(or_(UserApiKeys.expires == -1,
-                            UserApiKeys.expires >= time.time()))\
+                            UserApiKeys.expires >= time.time())) \
                 .first()
             if _res:
                 res = _res.user
@@ -693,16 +692,14 @@
     __table_args__ = (
         Index('uak_api_key_idx', 'api_key'),
         Index('uak_api_key_expires_idx', 'api_key', 'expires'),
-        UniqueConstraint('api_key'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
     __mapper_args__ = {}
 
-    user_api_key_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
-    api_key = Column(String(255, convert_unicode=False), nullable=False, unique=True)
-    description = Column(UnicodeText(1024))
+    user_api_key_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    api_key = Column(String(255), nullable=False, unique=True)
+    description = Column(UnicodeText(1024), nullable=False)
     expires = Column(Float(53), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
@@ -719,15 +716,13 @@
     __tablename__ = 'user_email_map'
     __table_args__ = (
         Index('uem_email_idx', 'email'),
-        UniqueConstraint('email'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
     __mapper_args__ = {}
 
-    email_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
-    _email = Column("email", String(255, convert_unicode=False), nullable=True, unique=False, default=None)
+    email_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    _email = Column("email", String(255), nullable=False, unique=True)
     user = relationship('User')
 
     @validates('_email')
@@ -751,15 +746,14 @@
     __tablename__ = 'user_ip_map'
     __table_args__ = (
         UniqueConstraint('user_id', 'ip_addr'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
     __mapper_args__ = {}
 
-    ip_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
-    ip_addr = Column(String(255, convert_unicode=False), nullable=True, unique=False, default=None)
-    active = Column(Boolean(), nullable=True, unique=None, default=True)
+    ip_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    ip_addr = Column(String(255), nullable=False)
+    active = Column(Boolean(), nullable=False, default=True)
     user = relationship('User')
 
     @classmethod
@@ -781,17 +775,17 @@
 class UserLog(Base, BaseModel):
     __tablename__ = 'user_logs'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
-    user_log_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
-    username = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
+
+    user_log_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
+    username = Column(String(255), nullable=False)
     repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True)
-    repository_name = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    user_ip = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    action = Column(UnicodeText(1200000, convert_unicode=False), nullable=True, unique=None, default=None)
-    action_date = Column(DateTime(timezone=False), nullable=True, unique=None, default=None)
+    repository_name = Column(Unicode(255), nullable=False)
+    user_ip = Column(String(255), nullable=True)
+    action = Column(UnicodeText(1200000), nullable=False)
+    action_date = Column(DateTime(timezone=False), nullable=False)
 
     def __unicode__(self):
         return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
@@ -809,18 +803,17 @@
 class UserGroup(Base, BaseModel):
     __tablename__ = 'users_groups'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
 
-    users_group_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    users_group_name = Column(String(255, convert_unicode=False), nullable=False, unique=True, default=None)
-    user_group_description = Column(String(10000, convert_unicode=False), nullable=True, unique=None, default=None)
-    users_group_active = Column(Boolean(), nullable=True, unique=None, default=None)
-    inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
+    users_group_id = Column(Integer(), unique=True, primary_key=True)
+    users_group_name = Column(Unicode(255), nullable=False, unique=True)
+    user_group_description = Column(Unicode(10000), nullable=True) # FIXME: not nullable?
+    users_group_active = Column(Boolean(), nullable=False)
+    inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, default=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
-    _group_data = Column("group_data", LargeBinary(), nullable=True)  # JSON data
+    _group_data = Column("group_data", LargeBinary(), nullable=True)  # JSON data # FIXME: not nullable?
 
     members = relationship('UserGroupMember', cascade="all, delete-orphan")
     users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
@@ -899,13 +892,12 @@
 class UserGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
 
-    users_group_member_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
+    users_group_member_id = Column(Integer(), unique=True, primary_key=True)
+    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
     user = relationship('User')
     users_group = relationship('UserGroup')
@@ -919,18 +911,18 @@
     __tablename__ = 'repositories_fields'
     __table_args__ = (
         UniqueConstraint('repository_id', 'field_key'),  # no-multi field
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
+
     PREFIX = 'ex_'  # prefix used in form to not conflict with already existing fields
 
-    repo_field_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
-    field_key = Column(String(250, convert_unicode=False))
-    field_label = Column(String(1024, convert_unicode=False), nullable=False)
-    field_value = Column(String(10000, convert_unicode=False), nullable=False)
-    field_desc = Column(String(1024, convert_unicode=False), nullable=False)
-    field_type = Column(String(255), nullable=False, unique=None)
+    repo_field_id = Column(Integer(), unique=True, primary_key=True)
+    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
+    field_key = Column(String(250), nullable=False)
+    field_label = Column(String(1024), nullable=False)
+    field_value = Column(String(10000), nullable=False)
+    field_desc = Column(String(1024), nullable=False)
+    field_type = Column(String(255), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
     repository = relationship('Repository')
@@ -947,8 +939,8 @@
 
     @classmethod
     def get_by_key_name(cls, key, repo):
-        row = cls.query()\
-                .filter(cls.repository == repo)\
+        row = cls.query() \
+                .filter(cls.repository == repo) \
                 .filter(cls.field_key == key).scalar()
         return row
 
@@ -956,11 +948,10 @@
 class Repository(Base, BaseModel):
     __tablename__ = 'repositories'
     __table_args__ = (
-        UniqueConstraint('repo_name'),
         Index('r_repo_name_idx', 'repo_name'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
+
     DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
     DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
 
@@ -968,26 +959,26 @@
     STATE_PENDING = 'repo_state_pending'
     STATE_ERROR = 'repo_state_error'
 
-    repo_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    repo_name = Column(String(255, convert_unicode=False), nullable=False, unique=True, default=None)
-    repo_state = Column(String(255), nullable=True)
-
-    clone_uri = Column(String(255, convert_unicode=False), nullable=True, unique=False, default=None)
-    repo_type = Column(String(255, convert_unicode=False), nullable=False, unique=False, default=None)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
-    private = Column(Boolean(), nullable=True, unique=None, default=None)
-    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
-    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
-    description = Column(String(10000, convert_unicode=False), nullable=True, unique=None, default=None)
-    created_on = Column(DateTime(timezone=False), nullable=False, unique=None, default=datetime.datetime.now)
-    updated_on = Column(DateTime(timezone=False), nullable=False, unique=None, default=datetime.datetime.now)
-    _landing_revision = Column("landing_revision", String(255, convert_unicode=False), nullable=False, unique=False, default=None)
-    enable_locking = Column(Boolean(), nullable=False, unique=None, default=False)
-    _locked = Column("locked", String(255, convert_unicode=False), nullable=True, unique=False, default=None)
-    _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
-
-    fork_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
-    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
+    repo_id = Column(Integer(), unique=True, primary_key=True)
+    repo_name = Column(Unicode(255), nullable=False, unique=True)
+    repo_state = Column(String(255), nullable=False)
+
+    clone_uri = Column(String(255), nullable=True) # FIXME: not nullable?
+    repo_type = Column(String(255), nullable=False)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    private = Column(Boolean(), nullable=False)
+    enable_statistics = Column("statistics", Boolean(), nullable=False, default=True)
+    enable_downloads = Column("downloads", Boolean(), nullable=False, default=True)
+    description = Column(Unicode(10000), nullable=False)
+    created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    updated_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
+    _landing_revision = Column("landing_revision", String(255), nullable=False)
+    enable_locking = Column(Boolean(), nullable=False, default=False)
+    _locked = Column("locked", String(255), nullable=True) # FIXME: not nullable?
+    _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) # JSON data # FIXME: not nullable?
+
+    fork_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True)
+    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=True)
 
     user = relationship('User')
     fork = relationship('Repository', remote_side=repo_id)
@@ -1083,8 +1074,8 @@
     @classmethod
     def get_by_repo_name(cls, repo_name):
         q = Session().query(cls).filter(cls.repo_name == repo_name)
-        q = q.options(joinedload(Repository.fork))\
-                .options(joinedload(Repository.user))\
+        q = q.options(joinedload(Repository.fork)) \
+                .options(joinedload(Repository.user)) \
                 .options(joinedload(Repository.group))
         return q.scalar()
 
@@ -1105,7 +1096,7 @@
 
         :param cls:
         """
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == cls.url_sep())
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
@@ -1174,9 +1165,9 @@
         """
         Returns associated cache keys for that repo
         """
-        return CacheInvalidation.query()\
-            .filter(CacheInvalidation.cache_args == self.repo_name)\
-            .order_by(CacheInvalidation.cache_key)\
+        return CacheInvalidation.query() \
+            .filter(CacheInvalidation.cache_args == self.repo_name) \
+            .order_by(CacheInvalidation.cache_key) \
             .all()
 
     def get_new_name(self, repo_name):
@@ -1378,7 +1369,7 @@
 
         :param revisions: filter query by revisions only
         """
-        cmts = ChangesetComment.query()\
+        cmts = ChangesetComment.query() \
             .filter(ChangesetComment.repo == self)
         if revisions is not None:
             if not revisions:
@@ -1399,9 +1390,9 @@
         if not revisions:
             return {}
 
-        statuses = ChangesetStatus.query()\
-            .filter(ChangesetStatus.repo == self)\
-            .filter(ChangesetStatus.version == 0)\
+        statuses = ChangesetStatus.query() \
+            .filter(ChangesetStatus.repo == self) \
+            .filter(ChangesetStatus.version == 0) \
             .filter(ChangesetStatus.revision.in_(revisions))
 
         grouped = {}
@@ -1479,19 +1470,18 @@
     __table_args__ = (
         UniqueConstraint('group_name', 'group_parent_id'),
         CheckConstraint('group_id != group_parent_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
     __mapper_args__ = {'order_by': 'group_name'}
 
     SEP = ' &raquo; '
 
-    group_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    group_name = Column(String(255, convert_unicode=False), nullable=False, unique=True, default=None)
-    group_parent_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
-    group_description = Column(String(10000, convert_unicode=False), nullable=True, unique=None, default=None)
-    enable_locking = Column(Boolean(), nullable=False, unique=None, default=False)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
+    group_id = Column(Integer(), unique=True, primary_key=True)
+    group_name = Column(Unicode(255), nullable=False, unique=True)
+    group_parent_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=True)
+    group_description = Column(Unicode(10000), nullable=False)
+    enable_locking = Column(Boolean(), nullable=False, default=False)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
     repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
@@ -1528,10 +1518,10 @@
     @classmethod
     def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
         if case_insensitive:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name.ilike(group_name))
         else:
-            gr = cls.query()\
+            gr = cls.query() \
                 .filter(cls.group_name == group_name)
         if cache:
             gr = gr.options(FromCache(
@@ -1583,8 +1573,8 @@
 
     @property
     def repositories(self):
-        return Repository.query()\
-                .filter(Repository.group == self)\
+        return Repository.query() \
+                .filter(Repository.group == self) \
                 .order_by(Repository.repo_name)
 
     @property
@@ -1659,9 +1649,9 @@
     __tablename__ = 'permissions'
     __table_args__ = (
         Index('p_perm_name_idx', 'permission_name'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
+
     PERMS = [
         ('hg.admin', _('Kallithea Administrator')),
 
@@ -1747,9 +1737,8 @@
         'hg.create.repository': 1
     }
 
-    permission_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    permission_name = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
-    permission_longname = Column(String(255, convert_unicode=False), nullable=True, unique=None, default=None)
+    permission_id = Column(Integer(), unique=True, primary_key=True)
+    permission_name = Column(String(255), nullable=False)
 
     def __unicode__(self):
         return u"<%s('%s:%s')>" % (
@@ -1762,27 +1751,27 @@
 
     @classmethod
     def get_default_perms(cls, default_user_id):
-        q = Session().query(UserRepoToPerm, Repository, cls)\
-         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
-         .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoToPerm, Repository, cls) \
+         .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id)) \
+         .join((cls, UserRepoToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_group_perms(cls, default_user_id):
-        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
-         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
-         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserRepoGroupToPerm, RepoGroup, cls) \
+         .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id)) \
+         .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserRepoGroupToPerm.user_id == default_user_id)
 
         return q.all()
 
     @classmethod
     def get_default_user_group_perms(cls, default_user_id):
-        q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
-         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
-         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
+        q = Session().query(UserUserGroupToPerm, UserGroup, cls) \
+         .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id)) \
+         .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id)) \
          .filter(UserUserGroupToPerm.user_id == default_user_id)
 
         return q.all()
@@ -1792,13 +1781,13 @@
     __tablename__ = 'repo_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'repository_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    repo_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
-    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
+
+    repo_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
+    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 
     user = relationship('User')
     repository = relationship('Repository')
@@ -1821,13 +1810,13 @@
     __tablename__ = 'user_user_group_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    user_user_group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
-    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+
+    user_user_group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
+    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
     user = relationship('User')
     user_group = relationship('UserGroup')
@@ -1850,12 +1839,12 @@
     __tablename__ = 'user_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    user_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    user_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
     user = relationship('User')
     permission = relationship('Permission')
@@ -1868,13 +1857,13 @@
     __tablename__ = 'users_group_repo_to_perm'
     __table_args__ = (
         UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    users_group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
-    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
+
+    users_group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
+    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
 
     users_group = relationship('UserGroup')
     permission = relationship('Permission')
@@ -1898,13 +1887,13 @@
     __table_args__ = (
         UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
         CheckConstraint('target_user_group_id != user_group_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    user_group_user_group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    target_user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
-    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
+
+    user_group_user_group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    target_user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
+    user_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
 
     target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
     user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
@@ -1927,12 +1916,12 @@
     __tablename__ = 'users_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'permission_id',),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
-    users_group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+
+    users_group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
     users_group = relationship('UserGroup')
     permission = relationship('Permission')
@@ -1942,14 +1931,13 @@
     __tablename__ = 'user_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('user_id', 'group_id', 'permission_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
 
-    group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
-    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
     user = relationship('User')
     group = relationship('RepoGroup')
@@ -1969,14 +1957,13 @@
     __tablename__ = 'users_group_repo_group_to_perm'
     __table_args__ = (
         UniqueConstraint('users_group_id', 'group_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
 
-    users_group_repo_group_to_perm_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
-    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
-    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
+    users_group_repo_group_to_perm_id = Column(Integer(), unique=True, primary_key=True)
+    users_group_id = Column(Integer(), ForeignKey('users_groups.users_group_id'), nullable=False)
+    group_id = Column(Integer(), ForeignKey('groups.group_id'), nullable=False)
+    permission_id = Column(Integer(), ForeignKey('permissions.permission_id'), nullable=False)
 
     users_group = relationship('UserGroup')
     permission = relationship('Permission')
@@ -1995,12 +1982,11 @@
 class Statistics(Base, BaseModel):
     __tablename__ = 'statistics'
     __table_args__ = (
-         UniqueConstraint('repository_id'),
-         {'extend_existing': True, 'mysql_engine': 'InnoDB',
-          'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+         _table_args_default_dict,
     )
-    stat_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
+
+    stat_id = Column(Integer(), unique=True, primary_key=True)
+    repository_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True)
     stat_on_revision = Column(Integer(), nullable=False)
     commit_activity = Column(LargeBinary(1000000), nullable=False)#JSON data
     commit_activity_combined = Column(LargeBinary(), nullable=False)#JSON data
@@ -2014,15 +2000,14 @@
     __table_args__ = (
         UniqueConstraint('user_id', 'follows_repository_id'),
         UniqueConstraint('user_id', 'follows_user_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
 
-    user_following_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
-    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
-    follows_user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
-    follows_from = Column(DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
+    user_following_id = Column(Integer(), unique=True, primary_key=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
+    follows_user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
+    follows_from = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
     user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 
@@ -2037,20 +2022,19 @@
 class CacheInvalidation(Base, BaseModel):
     __tablename__ = 'cache_invalidation'
     __table_args__ = (
-        UniqueConstraint('cache_key'),
         Index('key_idx', 'cache_key'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
+
     # cache_id, not used
-    cache_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
+    cache_id = Column(Integer(), unique=True, primary_key=True)
     # cache_key as created by _get_cache_key
-    cache_key = Column(String(255, convert_unicode=False))
+    cache_key = Column(Unicode(255), nullable=False, unique=True)
     # cache_args is a repo_name
-    cache_args = Column(String(255, convert_unicode=False))
+    cache_args = Column(Unicode(255), nullable=False)
     # instance sets cache_active True when it is caching, other instances set
     # cache_active to False to indicate that this cache is invalid
-    cache_active = Column(Boolean(), nullable=True, unique=None, default=False)
+    cache_active = Column(Boolean(), nullable=False, default=False)
 
     def __init__(self, cache_key, repo_name=''):
         self.cache_key = cache_key
@@ -2104,7 +2088,7 @@
         return "%s%s" % (prefix, key)
 
     @classmethod
-    def set_invalidate(cls, repo_name, delete=False):
+    def set_invalidate(cls, repo_name):
         """
         Mark all caches of a repo as invalid in the database.
         """
@@ -2115,11 +2099,7 @@
         for inv_obj in inv_objs:
             log.debug('marking %s key for invalidation based on repo_name=%s',
                       inv_obj, safe_str(repo_name))
-            if delete:
-                Session().delete(inv_obj)
-            else:
-                inv_obj.cache_active = False
-                Session().add(inv_obj)
+            Session().delete(inv_obj)
         Session().commit()
 
     @classmethod
@@ -2169,15 +2149,15 @@
     __table_args__ = (
         Index('cc_revision_idx', 'revision'),
         Index('cc_pull_request_id_idx', 'pull_request_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
-    comment_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
+
+    comment_id = Column(Integer(), unique=True, primary_key=True)
     repo_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
-    revision = Column(String(40))
-    pull_request_id = Column(Integer(), ForeignKey('pull_requests.pull_request_id'))
-    line_no = Column(Unicode(10))
-    f_path = Column(Unicode(1000))
+    revision = Column(String(40), nullable=True)
+    pull_request_id = Column(Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
+    line_no = Column(Unicode(10), nullable=True)
+    f_path = Column(Unicode(1000), nullable=True)
     user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
     text = Column(UnicodeText(25000), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
@@ -2201,7 +2181,7 @@
         :param cls:
         :param revision:
         """
-        q = Session().query(User)\
+        q = Session().query(User) \
                 .join(ChangesetComment.author)
         if revision is not None:
             q = q.filter(cls.revision == revision)
@@ -2226,9 +2206,9 @@
         Index('cs_changeset_comment_id_idx', 'changeset_comment_id'),
         Index('cs_pull_request_id_user_id_version_idx', 'pull_request_id', 'user_id', 'version'),
         UniqueConstraint('repo_id', 'revision', 'version'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
+
     STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
     STATUS_APPROVED = 'approved'
     STATUS_REJECTED = 'rejected'
@@ -2241,10 +2221,10 @@
         (STATUS_UNDER_REVIEW, _("Under review")),
     ]
 
-    changeset_status_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
+    changeset_status_id = Column(Integer(), unique=True, primary_key=True)
     repo_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
-    revision = Column(String(40), nullable=False)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    revision = Column(String(40), nullable=True)
     status = Column(String(128), nullable=False, default=DEFAULT)
     changeset_comment_id = Column(Integer(), ForeignKey('changeset_comments.comment_id'), nullable=False)
     modified_at = Column(DateTime(), nullable=False, default=datetime.datetime.now)
@@ -2276,22 +2256,21 @@
     __table_args__ = (
         Index('pr_org_repo_id_idx', 'org_repo_id'),
         Index('pr_other_repo_id_idx', 'other_repo_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
 
     # values for .status
     STATUS_NEW = u'new'
     STATUS_CLOSED = u'closed'
 
-    pull_request_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    title = Column(Unicode(255), nullable=True)
-    description = Column(UnicodeText(10240))
+    pull_request_id = Column(Integer(), unique=True, primary_key=True)
+    title = Column(Unicode(255), nullable=False)
+    description = Column(UnicodeText(10240), nullable=False)
     status = Column(Unicode(255), nullable=False, default=STATUS_NEW) # only for closedness, not approve/reject/etc
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
     updated_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
-    _revisions = Column('revisions', UnicodeText(20500))  # 500 revisions max
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
+    _revisions = Column('revisions', UnicodeText(20500), nullable=False)  # 500 revisions max
     org_repo_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
     org_ref = Column(Unicode(255), nullable=False)
     other_repo_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=False)
@@ -2328,10 +2307,10 @@
     def user_review_status(self, user_id):
         """Return the user's latest status votes on PR"""
         # note: no filtering on repo - that would be redundant
-        status = ChangesetStatus.query()\
-            .filter(ChangesetStatus.pull_request == self)\
-            .filter(ChangesetStatus.user_id == user_id)\
-            .order_by(ChangesetStatus.version)\
+        status = ChangesetStatus.query() \
+            .filter(ChangesetStatus.pull_request == self) \
+            .filter(ChangesetStatus.user_id == user_id) \
+            .order_by(ChangesetStatus.version) \
             .first()
         return str(status.status) if status else ''
 
@@ -2367,17 +2346,16 @@
 class PullRequestReviewers(Base, BaseModel):
     __tablename__ = 'pull_request_reviewers'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
 
     def __init__(self, user=None, pull_request=None):
         self.user = user
         self.pull_request = pull_request
 
-    pull_requests_reviewers_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
+    pull_requests_reviewers_id = Column(Integer(), unique=True, primary_key=True)
     pull_request_id = Column(Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
-    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
+    user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
 
     user = relationship('User')
     pull_request = relationship('PullRequest')
@@ -2387,8 +2365,7 @@
     __tablename__ = 'notifications'
     __table_args__ = (
         Index('notification_type_idx', 'type'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
 
     TYPE_CHANGESET_COMMENT = u'cs_comment'
@@ -2398,12 +2375,12 @@
     TYPE_PULL_REQUEST = u'pull_request'
     TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
 
-    notification_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    subject = Column(Unicode(512), nullable=True)
-    body = Column(UnicodeText(50000), nullable=True)
-    created_by = Column(Integer(), ForeignKey('users.user_id'), nullable=True)
+    notification_id = Column(Integer(), unique=True, primary_key=True)
+    subject = Column(Unicode(512), nullable=False)
+    body = Column(UnicodeText(50000), nullable=False)
+    created_by = Column(Integer(), ForeignKey('users.user_id'), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
-    type_ = Column('type', Unicode(255))
+    type_ = Column('type', Unicode(255), nullable=False)
 
     created_by_user = relationship('User')
     notifications_to_users = relationship('UserNotification', cascade="all, delete-orphan")
@@ -2426,11 +2403,15 @@
         notification.type_ = type_
         notification.created_on = datetime.datetime.now()
 
-        for u in recipients:
-            assoc = UserNotification()
-            assoc.notification = notification
-            assoc.user_id = u.user_id
-            Session().add(assoc)
+        for recipient in recipients:
+            un = UserNotification()
+            un.notification = notification
+            un.user_id = recipient.user_id
+            # Mark notifications to self "pre-read" - should perhaps just be skipped
+            if recipient == created_by:
+                un.read = True
+            Session().add(un)
+
         Session().add(notification)
         Session().flush() # assign notificaiton.notification_id
         return notification
@@ -2445,13 +2426,13 @@
     __tablename__ = 'user_to_notification'
     __table_args__ = (
         UniqueConstraint('user_id', 'notification_id'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
+
     user_id = Column(Integer(), ForeignKey('users.user_id'), primary_key=True)
     notification_id = Column(Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
-    read = Column(Boolean, default=False)
-    sent_on = Column(DateTime(timezone=False), nullable=True, unique=None)
+    read = Column(Boolean, nullable=False, default=False)
+    sent_on = Column(DateTime(timezone=False), nullable=True) # FIXME: not nullable?
 
     user = relationship('User')
     notification = relationship('Notification')
@@ -2466,17 +2447,17 @@
     __table_args__ = (
         Index('g_gist_access_id_idx', 'gist_access_id'),
         Index('g_created_on_idx', 'created_on'),
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True}
+        _table_args_default_dict,
     )
+
     GIST_PUBLIC = u'public'
     GIST_PRIVATE = u'private'
     DEFAULT_FILENAME = u'gistfile1.txt'
 
-    gist_id = Column(Integer(), nullable=False, unique=True, primary_key=True)
-    gist_access_id = Column(Unicode(250))
-    gist_description = Column(UnicodeText(1024))
-    gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
+    gist_id = Column(Integer(), unique=True, primary_key=True)
+    gist_access_id = Column(Unicode(250), nullable=False)
+    gist_description = Column(UnicodeText(1024), nullable=False)
+    gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
     gist_expires = Column(Float(53), nullable=False)
     gist_type = Column(Unicode(128), nullable=False)
     created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
@@ -2515,7 +2496,7 @@
         :param cls:
         """
         from kallithea.model.gist import GIST_STORE_LOC
-        q = Session().query(Ui)\
+        q = Session().query(Ui) \
             .filter(Ui.ui_key == URL_SEP)
         q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return os.path.join(q.one().ui_value, GIST_STORE_LOC)
@@ -2554,9 +2535,9 @@
 class DbMigrateVersion(Base, BaseModel):
     __tablename__ = 'db_migrate_version'
     __table_args__ = (
-        {'extend_existing': True, 'mysql_engine': 'InnoDB',
-         'mysql_charset': 'utf8', 'sqlite_autoincrement': True},
+        _table_args_default_dict,
     )
-    repository_id = Column(String(250), nullable=False, unique=True, primary_key=True)
-    repository_path = Column(Text)
-    version = Column(Integer)
+
+    repository_id = Column(String(250), unique=True, primary_key=True)
+    repository_path = Column(Text, nullable=False)
+    version = Column(Integer, nullable=False)
--- a/kallithea/model/forms.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/forms.py	Wed Jan 20 01:41:02 2016 +0100
@@ -86,7 +86,8 @@
     return _PasswordChangeForm
 
 
-def UserForm(edit=False, old_data={}):
+def UserForm(edit=False, old_data=None):
+    old_data = old_data or {}
     class _UserForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
@@ -125,7 +126,9 @@
     return _UserForm
 
 
-def UserGroupForm(edit=False, old_data={}, available_members=[]):
+def UserGroupForm(edit=False, old_data=None, available_members=None):
+    old_data = old_data or {}
+    available_members = available_members or []
     class _UserGroupForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
@@ -148,8 +151,10 @@
     return _UserGroupForm
 
 
-def RepoGroupForm(edit=False, old_data={}, repo_groups=[],
+def RepoGroupForm(edit=False, old_data=None, repo_groups=None,
                    can_create_in_root=False):
+    old_data = old_data or {}
+    repo_groups = repo_groups or []
     repo_group_ids = [rg[0] for rg in repo_groups]
     class _RepoGroupForm(formencode.Schema):
         allow_extra_fields = True
@@ -178,7 +183,7 @@
     return _RepoGroupForm
 
 
-def RegisterForm(edit=False, old_data={}):
+def RegisterForm(edit=False, old_data=None):
     class _RegisterForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
@@ -227,8 +232,11 @@
                                                     'password_confirm')]
     return _PasswordResetConfirmationForm
 
-def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
-             repo_groups=[], landing_revs=[]):
+def RepoForm(edit=False, old_data=None, supported_backends=BACKENDS.keys(),
+             repo_groups=None, landing_revs=None):
+    old_data = old_data or {}
+    repo_groups = repo_groups or []
+    landing_revs = landing_revs or []
     repo_group_ids = [rg[0] for rg in repo_groups]
     class _RepoForm(formencode.Schema):
         allow_extra_fields = True
@@ -302,8 +310,11 @@
     return _RepoFieldForm
 
 
-def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
-                 repo_groups=[], landing_revs=[]):
+def RepoForkForm(edit=False, old_data=None, supported_backends=BACKENDS.keys(),
+                 repo_groups=None, landing_revs=None):
+    old_data = old_data or {}
+    repo_groups = repo_groups or []
+    landing_revs = landing_revs or []
     repo_group_ids = [rg[0] for rg in repo_groups]
     class _RepoForkForm(formencode.Schema):
         allow_extra_fields = True
@@ -421,7 +432,7 @@
     return _CustomDefaultPermissionsForm
 
 
-def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
+def DefaultsForm(edit=False, old_data=None, supported_backends=BACKENDS.keys()):
     class _DefaultsForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
--- a/kallithea/model/notification.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/notification.py	Wed Jan 20 01:41:02 2016 +0100
@@ -59,7 +59,7 @@
 
     def create(self, created_by, subject, body, recipients=None,
                type_=Notification.TYPE_MESSAGE, with_email=True,
-               email_kwargs={}):
+               email_kwargs=None):
         """
 
         Creates notification of given type
@@ -75,7 +75,7 @@
         :param email_kwargs: additional dict to pass as args to email template
         """
         from kallithea.lib.celerylib import tasks, run_task
-
+        email_kwargs = email_kwargs or {}
         if recipients and not getattr(recipients, '__iter__', False):
             raise Exception('recipients must be a list or iterable')
 
@@ -137,11 +137,11 @@
 
             html_kwargs.update(email_kwargs)
             txt_kwargs.update(email_kwargs)
-            email_subject = EmailNotificationModel()\
+            email_subject = EmailNotificationModel() \
                                 .get_email_description(type_, **txt_kwargs)
-            email_txt_body = EmailNotificationModel()\
+            email_txt_body = EmailNotificationModel() \
                                 .get_email_tmpl(type_, 'txt', **txt_kwargs)
-            email_html_body = EmailNotificationModel()\
+            email_html_body = EmailNotificationModel() \
                                 .get_email_tmpl(type_, 'html', **html_kwargs)
 
             run_task(tasks.send_email, [rec.email], email_subject, email_txt_body,
@@ -155,10 +155,10 @@
             notification = self.__get_notification(notification)
             user = self._get_user(user)
             if notification and user:
-                obj = UserNotification.query()\
-                        .filter(UserNotification.user == user)\
+                obj = UserNotification.query() \
+                        .filter(UserNotification.user == user) \
                         .filter(UserNotification.notification
-                                == notification)\
+                                == notification) \
                         .one()
                 Session().delete(obj)
                 return True
@@ -175,12 +175,12 @@
         """
         user = self._get_user(user)
 
-        q = UserNotification.query()\
-            .filter(UserNotification.user == user)\
+        q = UserNotification.query() \
+            .filter(UserNotification.user == user) \
             .join((Notification, UserNotification.notification_id ==
-                                 Notification.notification_id))\
-            .options(joinedload('notification'))\
-            .options(subqueryload('notification.created_by_user'))\
+                                 Notification.notification_id)) \
+            .options(joinedload('notification')) \
+            .options(subqueryload('notification.created_by_user')) \
             .order_by(Notification.created_on.desc())
 
         if filter_:
@@ -193,10 +193,10 @@
             notification = self.__get_notification(notification)
             user = self._get_user(user)
             if notification and user:
-                obj = UserNotification.query()\
-                        .filter(UserNotification.user == user)\
+                obj = UserNotification.query() \
+                        .filter(UserNotification.user == user) \
                         .filter(UserNotification.notification
-                                == notification)\
+                                == notification) \
                         .one()
                 obj.read = True
                 Session().add(obj)
@@ -207,9 +207,9 @@
 
     def mark_all_read_for_user(self, user, filter_=None):
         user = self._get_user(user)
-        q = UserNotification.query()\
-            .filter(UserNotification.user == user)\
-            .filter(UserNotification.read == False)\
+        q = UserNotification.query() \
+            .filter(UserNotification.user == user) \
+            .filter(UserNotification.read == False) \
             .join((Notification, UserNotification.notification_id ==
                                  Notification.notification_id))
         if filter_:
@@ -223,22 +223,22 @@
 
     def get_unread_cnt_for_user(self, user):
         user = self._get_user(user)
-        return UserNotification.query()\
-                .filter(UserNotification.read == False)\
+        return UserNotification.query() \
+                .filter(UserNotification.read == False) \
                 .filter(UserNotification.user == user).count()
 
     def get_unread_for_user(self, user):
         user = self._get_user(user)
-        return [x.notification for x in UserNotification.query()\
-                .filter(UserNotification.read == False)\
+        return [x.notification for x in UserNotification.query() \
+                .filter(UserNotification.read == False) \
                 .filter(UserNotification.user == user).all()]
 
     def get_user_notification(self, user, notification):
         user = self._get_user(user)
         notification = self.__get_notification(notification)
 
-        return UserNotification.query()\
-            .filter(UserNotification.notification == notification)\
+        return UserNotification.query() \
+            .filter(UserNotification.notification == notification) \
             .filter(UserNotification.user == user).scalar()
 
     def make_description(self, notification, show_age=True):
--- a/kallithea/model/permission.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/permission.py	Wed Jan 20 01:41:02 2016 +0100
@@ -32,7 +32,7 @@
 from sqlalchemy.exc import DatabaseError
 
 from kallithea.model import BaseModel
-from kallithea.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
+from kallithea.model.db import User, Permission, UserToPerm, UserRepoToPerm, \
     UserRepoGroupToPerm, UserUserGroupToPerm
 from kallithea.lib.utils2 import str2bool
 
@@ -54,7 +54,6 @@
             if not Permission.get_by_key(p[0]):
                 new_perm = Permission()
                 new_perm.permission_name = p[0]
-                new_perm.permission_longname = p[0]  #translation err with p[1]
                 self.sa.add(new_perm)
 
     def create_default_permissions(self, user, force=False):
@@ -116,8 +115,8 @@
             # clear current entries, to make this function idempotent
             # it will fix even if we define more permissions or permissions
             # are somehow missing
-            u2p = self.sa.query(UserToPerm)\
-                .filter(UserToPerm.user == perm_user)\
+            u2p = self.sa.query(UserToPerm) \
+                .filter(UserToPerm.user == perm_user) \
                 .all()
             for p in u2p:
                 self.sa.delete(p)
@@ -140,8 +139,8 @@
                 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
                 _def = Permission.get_by_key('repository.' + _def_name)
                 # repos
-                for r2p in self.sa.query(UserRepoToPerm)\
-                               .filter(UserRepoToPerm.user == perm_user)\
+                for r2p in self.sa.query(UserRepoToPerm) \
+                               .filter(UserRepoToPerm.user == perm_user) \
                                .all():
 
                     #don't reset PRIVATE repositories
@@ -153,8 +152,8 @@
                 _def_name = form_result['default_group_perm'].split('group.')[-1]
                 # groups
                 _def = Permission.get_by_key('group.' + _def_name)
-                for g2p in self.sa.query(UserRepoGroupToPerm)\
-                               .filter(UserRepoGroupToPerm.user == perm_user)\
+                for g2p in self.sa.query(UserRepoGroupToPerm) \
+                               .filter(UserRepoGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
                     self.sa.add(g2p)
@@ -163,8 +162,8 @@
                 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
                 # groups
                 _def = Permission.get_by_key('usergroup.' + _def_name)
-                for g2p in self.sa.query(UserUserGroupToPerm)\
-                               .filter(UserUserGroupToPerm.user == perm_user)\
+                for g2p in self.sa.query(UserUserGroupToPerm) \
+                               .filter(UserUserGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
                     self.sa.add(g2p)
--- a/kallithea/model/pull_request.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/pull_request.py	Wed Jan 20 01:41:02 2016 +0100
@@ -34,7 +34,7 @@
 from kallithea.lib import helpers as h
 from kallithea.lib.exceptions import UserInvalidException
 from kallithea.model import BaseModel
-from kallithea.model.db import PullRequest, PullRequestReviewers, Notification,\
+from kallithea.model.db import PullRequest, PullRequestReviewers, Notification, \
     ChangesetStatus, User
 from kallithea.model.notification import NotificationModel
 from kallithea.lib.utils2 import extract_mentioned_users, safe_unicode
@@ -51,10 +51,10 @@
         return self._get_instance(PullRequest, pull_request)
 
     def get_pullrequest_cnt_for_user(self, user):
-        return PullRequest.query()\
-                                .join(PullRequestReviewers)\
-                                .filter(PullRequestReviewers.user_id == user)\
-                                .filter(PullRequest.status != PullRequest.STATUS_CLOSED)\
+        return PullRequest.query() \
+                                .join(PullRequestReviewers) \
+                                .filter(PullRequestReviewers.user_id == user) \
+                                .filter(PullRequest.status != PullRequest.STATUS_CLOSED) \
                                 .count()
 
     def get_all(self, repo_name, from_=False, closed=False):
@@ -184,9 +184,9 @@
     def update_reviewers(self, user, pull_request, reviewers_ids):
         reviewers_ids = set(reviewers_ids)
         pull_request = self.__get_pull_request(pull_request)
-        current_reviewers = PullRequestReviewers.query()\
+        current_reviewers = PullRequestReviewers.query() \
                             .filter(PullRequestReviewers.pull_request==
-                                   pull_request)\
+                                   pull_request) \
                             .all()
         current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
 
@@ -198,9 +198,9 @@
 
         log.debug("Removing %s reviewers", to_remove)
         for uid in to_remove:
-            reviewer = PullRequestReviewers.query()\
+            reviewer = PullRequestReviewers.query() \
                     .filter(PullRequestReviewers.user_id==uid,
-                            PullRequestReviewers.pull_request==pull_request)\
+                            PullRequestReviewers.pull_request==pull_request) \
                     .scalar()
             if reviewer:
                 Session().delete(reviewer)
--- a/kallithea/model/repo_group.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/repo_group.py	Wed Jan 20 01:41:02 2016 +0100
@@ -455,9 +455,9 @@
         permission = self._get_perm(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserRepoGroupToPerm)\
-            .filter(UserRepoGroupToPerm.user == user)\
-            .filter(UserRepoGroupToPerm.group == repo_group)\
+        obj = self.sa.query(UserRepoGroupToPerm) \
+            .filter(UserRepoGroupToPerm.user == user) \
+            .filter(UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is None:
             # create new !
@@ -481,9 +481,9 @@
         repo_group = self._get_repo_group(repo_group)
         user = self._get_user(user)
 
-        obj = self.sa.query(UserRepoGroupToPerm)\
-            .filter(UserRepoGroupToPerm.user == user)\
-            .filter(UserRepoGroupToPerm.group == repo_group)\
+        obj = self.sa.query(UserRepoGroupToPerm) \
+            .filter(UserRepoGroupToPerm.user == user) \
+            .filter(UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is not None:
             self.sa.delete(obj)
@@ -505,9 +505,9 @@
         permission = self._get_perm(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserGroupRepoGroupToPerm)\
-            .filter(UserGroupRepoGroupToPerm.group == repo_group)\
-            .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
+        obj = self.sa.query(UserGroupRepoGroupToPerm) \
+            .filter(UserGroupRepoGroupToPerm.group == repo_group) \
+            .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
 
         if obj is None:
@@ -533,9 +533,9 @@
         repo_group = self._get_repo_group(repo_group)
         group_name = self._get_user_group(group_name)
 
-        obj = self.sa.query(UserGroupRepoGroupToPerm)\
-            .filter(UserGroupRepoGroupToPerm.group == repo_group)\
-            .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
+        obj = self.sa.query(UserGroupRepoGroupToPerm) \
+            .filter(UserGroupRepoGroupToPerm.group == repo_group) \
+            .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
         if obj is not None:
             self.sa.delete(obj)
--- a/kallithea/model/scm.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/scm.py	Wed Jan 20 01:41:02 2016 +0100
@@ -46,9 +46,9 @@
 
 from kallithea import BACKENDS
 from kallithea.lib import helpers as h
-from kallithea.lib.utils2 import safe_str, safe_unicode, get_server_url,\
+from kallithea.lib.utils2 import safe_str, safe_unicode, get_server_url, \
     _set_extras
-from kallithea.lib.auth import HasRepoPermissionAny, HasRepoGroupPermissionAny,\
+from kallithea.lib.auth import HasRepoPermissionAny, HasRepoGroupPermissionAny, \
     HasUserGroupPermissionAny, HasPermissionAny, HasPermissionAll
 from kallithea.lib.utils import get_filesystem_repos, make_ui, \
     action_logger
@@ -311,8 +311,8 @@
         :param simple: use SimpleCachedList - one without the SCM info
         """
         if all_repos is None:
-            all_repos = self.sa.query(Repository)\
-                        .filter(Repository.group_id == None)\
+            all_repos = self.sa.query(Repository) \
+                        .filter(Repository.group_id == None) \
                         .order_by(func.lower(Repository.repo_name)).all()
         if simple:
             repo_iter = SimpleCachedRepoList(all_repos,
@@ -327,25 +327,25 @@
 
     def get_repo_groups(self, all_groups=None):
         if all_groups is None:
-            all_groups = RepoGroup.query()\
+            all_groups = RepoGroup.query() \
                 .filter(RepoGroup.group_parent_id == None).all()
         return [x for x in RepoGroupList(all_groups)]
 
-    def mark_for_invalidation(self, repo_name, delete=False):
+    def mark_for_invalidation(self, repo_name):
         """
         Mark caches of this repo invalid in the database.
 
         :param repo_name: the repo for which caches should be marked invalid
         """
-        CacheInvalidation.set_invalidate(repo_name, delete=delete)
+        CacheInvalidation.set_invalidate(repo_name)
         repo = Repository.get_by_repo_name(repo_name)
         if repo is not None:
             repo.update_changeset_cache()
 
     def toggle_following_repo(self, follow_repo_id, user_id):
 
-        f = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.follows_repo_id == follow_repo_id)\
+        f = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.follows_repo_id == follow_repo_id) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
@@ -373,8 +373,8 @@
             raise
 
     def toggle_following_user(self, follow_user_id, user_id):
-        f = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.follows_user_id == follow_user_id)\
+        f = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.follows_user_id == follow_user_id) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
@@ -395,11 +395,11 @@
             raise
 
     def is_following_repo(self, repo_name, user_id, cache=False):
-        r = self.sa.query(Repository)\
+        r = self.sa.query(Repository) \
             .filter(Repository.repo_name == repo_name).scalar()
 
-        f = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.follows_repository == r)\
+        f = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.follows_repository == r) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         return f is not None
@@ -407,8 +407,8 @@
     def is_following_user(self, username, user_id, cache=False):
         u = User.get_by_username(username)
 
-        f = self.sa.query(UserFollowing)\
-            .filter(UserFollowing.follows_user == u)\
+        f = self.sa.query(UserFollowing) \
+            .filter(UserFollowing.follows_user == u) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         return f is not None
@@ -416,18 +416,18 @@
     def get_followers(self, repo):
         repo = self._get_repo(repo)
 
-        return self.sa.query(UserFollowing)\
+        return self.sa.query(UserFollowing) \
                 .filter(UserFollowing.follows_repository == repo).count()
 
     def get_forks(self, repo):
         repo = self._get_repo(repo)
-        return self.sa.query(Repository)\
+        return self.sa.query(Repository) \
                 .filter(Repository.fork == repo).count()
 
     def get_pull_requests(self, repo):
         repo = self._get_repo(repo)
-        return self.sa.query(PullRequest)\
-                .filter(PullRequest.other_repo == repo)\
+        return self.sa.query(PullRequest) \
+                .filter(PullRequest.other_repo == repo) \
                 .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
 
     def mark_as_fork(self, repo, fork, user):
--- a/kallithea/model/user.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/user.py	Wed Jan 20 01:41:02 2016 +0100
@@ -38,7 +38,7 @@
 from sqlalchemy.exc import DatabaseError
 
 from kallithea import EXTERN_TYPE_INTERNAL
-from kallithea.lib.utils2 import safe_unicode, generate_api_key, get_current_authuser
+from kallithea.lib.utils2 import safe_str, generate_api_key, get_current_authuser
 from kallithea.lib.caching_query import FromCache
 from kallithea.model import BaseModel
 from kallithea.model.db import User, UserToPerm, Notification, \
@@ -100,8 +100,8 @@
         log_create_user(new_user.get_dict(), cur_user)
         return new_user
 
-    def create_or_update(self, username, password, email, firstname='',
-                         lastname='', active=True, admin=False,
+    def create_or_update(self, username, password, email, firstname=u'',
+                         lastname=u'', active=True, admin=False,
                          extern_type=None, extern_name=None, cur_user=None):
         """
         Creates a new instance if not found, or updates current one
@@ -148,9 +148,9 @@
             new_user.admin = admin
             new_user.email = email
             new_user.active = active
-            new_user.extern_name = safe_unicode(extern_name) \
+            new_user.extern_name = safe_str(extern_name) \
                 if extern_name else None
-            new_user.extern_type = safe_unicode(extern_type) \
+            new_user.extern_type = safe_str(extern_type) \
                 if extern_type else None
             new_user.name = firstname
             new_user.lastname = lastname
@@ -191,7 +191,7 @@
         # notification to admins
         subject = _('New user registration')
         body = (
-            'New user registration\n'
+            u'New user registration\n'
             '---------------------\n'
             '- Username: {user.username}\n'
             '- Full Name: {user.full_name}\n'
@@ -206,9 +206,9 @@
                                    type_=Notification.TYPE_REGISTRATION,
                                    email_kwargs=email_kwargs)
 
-    def update(self, user_id, form_data, skip_attrs=[]):
+    def update(self, user_id, form_data, skip_attrs=None):
         from kallithea.lib.auth import get_crypt_password
-
+        skip_attrs = skip_attrs or []
         user = self.get(user_id, cache=False)
         if user.username == User.DEFAULT_USER:
             raise DefaultUserException(
@@ -278,6 +278,11 @@
         from kallithea.lib.hooks import log_delete_user
         log_delete_user(user.get_dict(), cur_user)
 
+    def can_change_password(self, user):
+        from kallithea.lib import auth_modules
+        managed_fields = auth_modules.get_managed_fields(user)
+        return 'password' not in managed_fields
+
     def get_reset_password_token(self, user, timestamp, session_id):
         """
         The token is a 40-digit hexstring, calculated as a HMAC-SHA1.
@@ -332,18 +337,21 @@
         user = User.get_by_email(user_email)
         timestamp = int(time.time())
         if user is not None:
-            log.debug('password reset user %s found', user)
-            token = self.get_reset_password_token(user,
-                                                  timestamp,
-                                                  h.authentication_token())
-            # URL must be fully qualified; but since the token is locked to
-            # the current browser session, we must provide a URL with the
-            # current scheme and hostname, rather than the canonical_url.
-            link = h.url('reset_password_confirmation', qualified=True,
-                         email=user_email,
-                         timestamp=timestamp,
-                         token=token)
-
+            if self.can_change_password(user):
+                log.debug('password reset user %s found', user)
+                token = self.get_reset_password_token(user,
+                                                      timestamp,
+                                                      h.authentication_token())
+                # URL must be fully qualified; but since the token is locked to
+                # the current browser session, we must provide a URL with the
+                # current scheme and hostname, rather than the canonical_url.
+                link = h.url('reset_password_confirmation', qualified=True,
+                             email=user_email,
+                             timestamp=timestamp,
+                             token=token)
+            else:
+                log.debug('password reset user %s found but was managed', user)
+                token = link = None
             reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
             body = EmailNotificationModel().get_email_tmpl(
                 reg_type, 'txt',
@@ -397,6 +405,8 @@
         from kallithea.lib import auth
         user = User.get_by_email(user_email)
         if user is not None:
+            if not self.can_change_password(user):
+                raise Exception('trying to change password for external user')
             user.password = auth.get_crypt_password(new_passwd)
             Session().add(user)
             Session().commit()
@@ -415,7 +425,7 @@
         perm = self._get_perm(perm)
         user = self._get_user(user)
 
-        return UserToPerm.query().filter(UserToPerm.user == user)\
+        return UserToPerm.query().filter(UserToPerm.user == user) \
             .filter(UserToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, user, perm):
@@ -428,9 +438,9 @@
         user = self._get_user(user)
         perm = self._get_perm(perm)
         # if this permission is already granted skip it
-        _perm = UserToPerm.query()\
-            .filter(UserToPerm.user == user)\
-            .filter(UserToPerm.permission == perm)\
+        _perm = UserToPerm.query() \
+            .filter(UserToPerm.user == user) \
+            .filter(UserToPerm.permission == perm) \
             .scalar()
         if _perm:
             return
--- a/kallithea/model/user_group.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/user_group.py	Wed Jan 20 01:41:02 2016 +0100
@@ -28,10 +28,10 @@
 import traceback
 
 from kallithea.model import BaseModel
-from kallithea.model.db import UserGroupMember, UserGroup,\
-    UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm,\
+from kallithea.model.db import UserGroupMember, UserGroup, \
+    UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm, \
     UserGroupUserGroupToPerm
-from kallithea.lib.exceptions import UserGroupsAssignedException,\
+from kallithea.lib.exceptions import UserGroupsAssignedException, \
     RepoGroupAssignmentError
 
 log = logging.getLogger(__name__)
@@ -162,7 +162,7 @@
         user_group = self._get_user_group(user_group)
         try:
             # check if this group is not assigned to repo
-            assigned_groups = UserGroupRepoToPerm.query()\
+            assigned_groups = UserGroupRepoToPerm.query() \
                 .filter(UserGroupRepoToPerm.users_group == user_group).all()
             assigned_groups = [x.repository.repo_name for x in assigned_groups]
 
@@ -224,8 +224,8 @@
         user_group = self._get_user_group(user_group)
         perm = self._get_perm(perm)
 
-        return UserGroupToPerm.query()\
-            .filter(UserGroupToPerm.users_group == user_group)\
+        return UserGroupToPerm.query() \
+            .filter(UserGroupToPerm.users_group == user_group) \
             .filter(UserGroupToPerm.permission == perm).scalar() is not None
 
     def grant_perm(self, user_group, perm):
@@ -233,9 +233,9 @@
         perm = self._get_perm(perm)
 
         # if this permission is already granted skip it
-        _perm = UserGroupToPerm.query()\
-            .filter(UserGroupToPerm.users_group == user_group)\
-            .filter(UserGroupToPerm.permission == perm)\
+        _perm = UserGroupToPerm.query() \
+            .filter(UserGroupToPerm.users_group == user_group) \
+            .filter(UserGroupToPerm.permission == perm) \
             .scalar()
         if _perm:
             return
@@ -250,8 +250,8 @@
         user_group = self._get_user_group(user_group)
         perm = self._get_perm(perm)
 
-        obj = UserGroupToPerm.query()\
-            .filter(UserGroupToPerm.users_group == user_group)\
+        obj = UserGroupToPerm.query() \
+            .filter(UserGroupToPerm.users_group == user_group) \
             .filter(UserGroupToPerm.permission == perm).scalar()
         if obj is not None:
             self.sa.delete(obj)
@@ -272,9 +272,9 @@
         permission = self._get_perm(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserUserGroupToPerm)\
-            .filter(UserUserGroupToPerm.user == user)\
-            .filter(UserUserGroupToPerm.user_group == user_group)\
+        obj = self.sa.query(UserUserGroupToPerm) \
+            .filter(UserUserGroupToPerm.user == user) \
+            .filter(UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
@@ -298,9 +298,9 @@
         user_group = self._get_user_group(user_group)
         user = self._get_user(user)
 
-        obj = self.sa.query(UserUserGroupToPerm)\
-            .filter(UserUserGroupToPerm.user == user)\
-            .filter(UserUserGroupToPerm.user_group == user_group)\
+        obj = self.sa.query(UserUserGroupToPerm) \
+            .filter(UserUserGroupToPerm.user == user) \
+            .filter(UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
             self.sa.delete(obj)
@@ -323,9 +323,9 @@
                                            'assigned to itself' % target_user_group)
 
         # check if we have that permission already
-        obj = self.sa.query(UserGroupUserGroupToPerm)\
-            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
-            .filter(UserGroupUserGroupToPerm.user_group == user_group)\
+        obj = self.sa.query(UserGroupUserGroupToPerm) \
+            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
+            .filter(UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
@@ -347,9 +347,9 @@
         target_user_group = self._get_user_group(target_user_group)
         user_group = self._get_user_group(user_group)
 
-        obj = self.sa.query(UserGroupUserGroupToPerm)\
-            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
-            .filter(UserGroupUserGroupToPerm.user_group == user_group)\
+        obj = self.sa.query(UserGroupUserGroupToPerm) \
+            .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
+            .filter(UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
             self.sa.delete(obj)
@@ -375,7 +375,7 @@
         for gr in set(groups):
             existing_group = UserGroup.get_by_group_name(gr)
             if not existing_group:
-                desc = 'Automatically created from plugin:%s' % extern_type
+                desc = u'Automatically created from plugin:%s' % extern_type
                 # we use first admin account to set the owner of the group
                 existing_group = UserGroupModel().create(gr, desc, owner,
                                         group_data={'extern_type': extern_type})
--- a/kallithea/model/validators.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/model/validators.py	Wed Jan 20 01:41:02 2016 +0100
@@ -89,7 +89,8 @@
     return _UniqueListFromString
 
 
-def ValidUsername(edit=False, old_data={}):
+def ValidUsername(edit=False, old_data=None):
+    old_data = old_data or {}
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'username_exists': _('Username "%(username)s" already exists'),
@@ -135,7 +136,7 @@
 
         def validate_python(self, value, state):
             try:
-                User.query().filter(User.active == True)\
+                User.query().filter(User.active == True) \
                     .filter(User.username == value).one()
             except sqlalchemy.exc.InvalidRequestError: # NoResultFound/MultipleResultsFound
                 msg = M(self, 'invalid_username', state, username=value)
@@ -146,7 +147,8 @@
     return _validator
 
 
-def ValidUserGroup(edit=False, old_data={}):
+def ValidUserGroup(edit=False, old_data=None):
+    old_data = old_data or {}
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'invalid_group': _('Invalid user group name'),
@@ -187,7 +189,9 @@
     return _validator
 
 
-def ValidRepoGroup(edit=False, old_data={}):
+def ValidRepoGroup(edit=False, old_data=None):
+    old_data = old_data or {}
+
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'group_parent_id': _('Cannot assign this group as parent'),
@@ -222,9 +226,9 @@
             if old_gname != group_name or not edit:
 
                 # check group
-                gr = RepoGroup.query()\
-                      .filter(RepoGroup.group_name == slug)\
-                      .filter(RepoGroup.group_parent_id == group_parent_id)\
+                gr = RepoGroup.query() \
+                      .filter(RepoGroup.group_name == slug) \
+                      .filter(RepoGroup.group_parent_id == group_parent_id) \
                       .scalar()
 
                 if gr is not None:
@@ -234,8 +238,8 @@
                     )
 
                 # check for same repo
-                repo = Repository.query()\
-                      .filter(Repository.repo_name == slug)\
+                repo = Repository.query() \
+                      .filter(Repository.repo_name == slug) \
                       .scalar()
 
                 if repo is not None:
@@ -338,7 +342,9 @@
     return _validator
 
 
-def ValidRepoName(edit=False, old_data={}):
+def ValidRepoName(edit=False, old_data=None):
+    old_data = old_data or {}
+
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'invalid_repo_name':
@@ -373,7 +379,6 @@
             return value
 
         def validate_python(self, value, state):
-
             repo_name = value.get('repo_name')
             repo_name_full = value.get('repo_name_full')
             group_path = value.get('group_path')
@@ -483,7 +488,9 @@
     return _validator
 
 
-def ValidForkType(old_data={}):
+def ValidForkType(old_data=None):
+    old_data = old_data or {}
+
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'invalid_fork_type': _('Fork has to be the same type as parent')
@@ -644,12 +651,12 @@
             for k, v, t in perms_new:
                 try:
                     if t is 'user':
-                        self.user_db = User.query()\
-                            .filter(User.active == True)\
+                        self.user_db = User.query() \
+                            .filter(User.active == True) \
                             .filter(User.username == k).one()
                     if t is 'users_group':
-                        self.user_db = UserGroup.query()\
-                            .filter(UserGroup.users_group_active == True)\
+                        self.user_db = UserGroup.query() \
+                            .filter(UserGroup.users_group_active == True) \
                             .filter(UserGroup.users_group_name == k).one()
 
                 except Exception:
@@ -699,7 +706,9 @@
     return _validator
 
 
-def UniqSystemEmail(old_data={}):
+def UniqSystemEmail(old_data=None):
+    old_data = old_data or {}
+
     class _validator(formencode.validators.FancyValidator):
         messages = {
             'email_taken': _('This email address is already in use')
--- a/kallithea/public/css/contextbar.css	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/public/css/contextbar.css	Wed Jan 20 01:41:02 2016 +0100
@@ -71,6 +71,10 @@
     vertical-align: text-bottom;
 }
 
+#content #context-bar li span {
+    margin: 0;
+}
+
 ul.horizontal-list {
     display: block;
 }
--- a/kallithea/public/css/style.css	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/public/css/style.css	Wed Jan 20 01:41:02 2016 +0100
@@ -4346,9 +4346,6 @@
     color: #666;
     font-size: 16px;
 }
-.inline-comments-button .add-comment {
-    margin: 2px 0px 8px 5px !important
-}
 
 input.status_change_radio {
     margin: 2px 0 5px 15px;
@@ -4557,6 +4554,19 @@
     overflow: hidden;
 }
 
+.compare-revision-selector {
+    font-weight: bold;
+    font-size: 14px;
+}
+.compare-revision-selector > div {
+    display: inline-block;
+    margin-left: 8px;
+    vertical-align: middle;
+}
+.compare-revision-selector .btn {
+    margin-bottom: 0;
+}
+
 
 div.diffblock {
     overflow: auto;
@@ -4572,6 +4582,7 @@
 div.diffblock.margined {
     margin: 0px 20px 0px 20px;
 }
+.compare-revision-selector,
 div.diffblock .code-header {
     border-bottom: 1px solid #CCCCCC;
     background: #EEEEEE;
--- a/kallithea/public/js/base.js	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/public/js/base.js	Wed Jan 20 01:41:02 2016 +0100
@@ -377,15 +377,16 @@
         ;
 };
 
-var ajaxGET = function(url,success) {
+var ajaxGET = function(url, success, failure) {
+    if(failure === undefined) {
+        failure = function(jqXHR, textStatus, errorThrown) {
+                if (textStatus != "abort")
+                    alert("Ajax GET error: " + textStatus);
+            };
+    }
     return $.ajax({url: url, headers: {'X-PARTIAL-XHR': '1'}, cache: false})
         .done(success)
-        .fail(function(jqXHR, textStatus, errorThrown) {
-                if (textStatus == "abort")
-                    return;
-                alert("Ajax GET error: " + textStatus);
-        })
-        ;
+        .fail(failure);
 };
 
 var ajaxPOST = function(url, postData, success, failure) {
@@ -913,14 +914,14 @@
             $('#editor_container').show();
             $('#upload_file_container').hide();
             $('#filename_container').show();
-            $('#set_mode_header').show();
+            $('#mimetype_header').show();
         });
 
     $('#upload_file_enable').click(function(){
             $('#editor_container').hide();
             $('#upload_file_container').show();
             $('#filename_container').hide();
-            $('#set_mode_header').hide();
+            $('#mimetype_header').hide();
         });
 
     return myCodeMirror
@@ -1859,8 +1860,8 @@
             }
 
             // Put prefix matches before matches in the line
-            var aPos = a.text.indexOf(query.term),
-                bPos = b.text.indexOf(query.term);
+            var aPos = a.text.toLowerCase().indexOf(query.term.toLowerCase()),
+                bPos = b.text.toLowerCase().indexOf(query.term.toLowerCase());
             if (aPos === 0 && bPos !== 0) {
                 return -1;
             }
@@ -1881,19 +1882,33 @@
     return results;
 };
 
-// global hooks after DOM is loaded
+var prefixFirstSort = function(results, container, query) {
+    if (query.term) {
+        return results.sort(function (a, b) {
+            // if parent node, no sorting
+            if (a.children != undefined || b.children != undefined) {
+                return 0;
+            }
 
-$(document).ready(function(){
-    $('.diff-collapse-button').click(function(e) {
-        var $button = $(e.currentTarget);
-        var $target = $('#' + $button.attr('target'));
-        if($target.hasClass('hidden')){
-            $target.removeClass('hidden');
-            $button.html("&uarr; {0} &uarr;".format(_TM['Collapse Diff']));
-        }
-        else if(!$target.hasClass('hidden')){
-            $target.addClass('hidden');
-            $button.html("&darr; {0} &darr;".format(_TM['Expand Diff']));
-        }
-    });
-});
+            // Put prefix matches before matches in the line
+            var aPos = a.text.toLowerCase().indexOf(query.term.toLowerCase()),
+                bPos = b.text.toLowerCase().indexOf(query.term.toLowerCase());
+            if (aPos === 0 && bPos !== 0) {
+                return -1;
+            }
+            if (bPos === 0 && aPos !== 0) {
+                return 1;
+            }
+
+            // Default sorting
+            if (a.text > b.text) {
+                return 1;
+            }
+            if (a.text < b.text) {
+                return -1;
+            }
+            return 0;
+        });
+    }
+    return results;
+};
--- a/kallithea/templates/about.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/about.html	Wed Jan 20 01:41:02 2016 +0100
@@ -49,6 +49,7 @@
   <li>Copyright &copy; 2015, Étienne Gilli</li>
   <li>Copyright &copy; 2015, Grzegorz Krason</li>
   <li>Copyright &copy; 2015, Jan Heylen</li>
+  <li>Copyright &copy; 2015, Jiří Suchan</li>
   <li>Copyright &copy; 2015, Kazunari Kobayashi</li>
   <li>Copyright &copy; 2015, Kevin Bullock</li>
   <li>Copyright &copy; 2015, kobanari</li>
--- a/kallithea/templates/admin/gists/edit.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/gists/edit.html	Wed Jan 20 01:41:02 2016 +0100
@@ -81,62 +81,63 @@
 
                 ## dynamic edit box.
                 <script type="text/javascript">
-                var myCodeMirror = initCodeMirror("editor_${h.FID('f',file.path)}", "${request.script_name}", '');
+                    $(document).ready(function(){
+                        var myCodeMirror = initCodeMirror("editor_${h.FID('f',file.path)}", "${request.script_name}", '');
+
+                        //inject new modes
+                        var $mimetype_select = $('#mimetype_${h.FID('f',file.path)}');
+                        $mimetype_select.each(function(){
+                            var modes_select = this;
+                            var index = 1;
+                            for(var i=0;i<CodeMirror.modeInfo.length;i++) {
+                                var m = CodeMirror.modeInfo[i];
+                                var opt = new Option(m.name, m.mime);
+                                $(opt).attr('mode', m.mode);
+                                if (m.mime == 'text/plain') {
+                                    // default plain text
+                                    $(opt).prop('selected', true);
+                                    modes_select.options[0] = opt;
+                                } else {
+                                    modes_select.options[index++] = opt;
+                                }
+                            }
+                        });
 
-                //inject new modes
-                var $modes_select = $('#mimetype_${h.FID('f',file.path)}');
-                $modes_select.each(function(){
-                    var modes_select = this;
-                    var index = 1;
-                    for(var i=0;i<CodeMirror.modeInfo.length;i++) {
-                        var m = CodeMirror.modeInfo[i];
-                        var opt = new Option(m.name, m.mime);
-                        $(opt).attr('mode', m.mode);
-                        if (m.mime == 'text/plain') {
-                            // default plain text
-                            $(opt).prop('selected', true);
-                            modes_select.options[0] = opt;
-                        } else {
-                            modes_select.options[index++] = opt;
-                        }
-                    }
-                });
+                        var $filename_input = $('#filename_${h.FID('f',file.path)}');
+                        // on select change set new mode
+                        $mimetype_select.change(function(e){
+                            var selected = e.currentTarget;
+                            var node = selected.options[selected.selectedIndex];
+                            var detected_mode = CodeMirror.findModeByMIME(node.value);
+                            setCodeMirrorMode(myCodeMirror, detected_mode);
+
+                            var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
+                            var file_data = CodeMirror.getFilenameAndExt($filename_input.val());
+                            var filename = file_data['filename'] || 'filename1';
+                            $filename_input.val(filename + '.' + proposed_ext);
+                        });
 
-                var $filename = $('#filename_${h.FID('f',file.path)}');
-                // on select change set new mode
-                $modes_select.change(function(e){
-                    var selected = e.currentTarget;
-                    var node = selected.options[selected.selectedIndex];
-                    var detected_mode = CodeMirror.findModeByMIME(node.value);
-                    setCodeMirrorMode(myCodeMirror, detected_mode);
+                        // on type the new filename set mode
+                        $filename_input.keyup(function(e){
+                            var file_data = CodeMirror.getFilenameAndExt(this.value);
+                            if(file_data['ext'] != null){
+                                var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
 
-                    var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
-                    var file_data = CodeMirror.getFilenameAndExt($filename.val());
-                    var filename = file_data['filename'] || 'filename1';
-                    $filename.val(filename + '.' + proposed_ext);
-                });
+                                if (detected_mode){
+                                    setCodeMirrorMode(myCodeMirror, detected_mode);
+                                    $mimetype_select.val(detected_mode.mime);
+                                }
+                            }
+                        });
 
-                // on type the new filename set mode
-                $filename.keyup(function(e){
-                    var file_data = CodeMirror.getFilenameAndExt(this.value);
-                    if(file_data['ext'] != null){
-                        var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
+                        // set mode on page load
+                        var detected_mode = CodeMirror.findModeByExtension("${file.extension}");
 
                         if (detected_mode){
                             setCodeMirrorMode(myCodeMirror, detected_mode);
-                            $modes_select.val(detected_mode.mime);
+                            $mimetype_select.val(detected_mode.mime);
                         }
-                    }
-                });
-
-                // set mode on page load
-                var detected_mode = CodeMirror.findModeByExtension("${file.extension}");
-
-                if (detected_mode){
-                    setCodeMirrorMode(myCodeMirror, detected_mode);
-                    $modes_select.val(detected_mode.mime);
-                }
-
+                    });
                 </script>
 
             %endfor
--- a/kallithea/templates/admin/gists/new.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/gists/new.html	Wed Jan 20 01:41:02 2016 +0100
@@ -59,51 +59,53 @@
             </div>
           ${h.end_form()}
           <script type="text/javascript">
-            var myCodeMirror = initCodeMirror('editor', "${request.script_name}", '');
+            $(document).ready(function(){
+                var myCodeMirror = initCodeMirror('editor', "${request.script_name}", '');
 
-            //inject new modes
-            var $modes_select = $('#mimetype');
-            $modes_select.each(function(){
-                var modes_select = this;
-                var index = 1;
-                for(var i=0;i<CodeMirror.modeInfo.length;i++) {
-                    var m = CodeMirror.modeInfo[i];
-                    var opt = new Option(m.name, m.mime);
-                    $(opt).attr('mode', m.mode);
-                    if (m.mime == 'text/plain') {
-                        // default plain text
-                        $(opt).prop('selected', true);
-                        modes_select.options[0] = opt;
-                    } else {
-                        modes_select.options[index++] = opt;
+                //inject new modes
+                var $mimetype_select = $('#mimetype');
+                $mimetype_select.each(function(){
+                    var modes_select = this;
+                    var index = 1;
+                    for(var i=0;i<CodeMirror.modeInfo.length;i++) {
+                        var m = CodeMirror.modeInfo[i];
+                        var opt = new Option(m.name, m.mime);
+                        $(opt).attr('mode', m.mode);
+                        if (m.mime == 'text/plain') {
+                            // default plain text
+                            $(opt).prop('selected', true);
+                            modes_select.options[0] = opt;
+                        } else {
+                            modes_select.options[index++] = opt;
+                        }
                     }
-                }
-            });
+                });
 
-            var $filename = $('#filename');
-            // on select change set new mode
-            $modes_select.change(function(e){
-                var selected = e.currentTarget;
-                var node = selected.options[selected.selectedIndex];
-                var detected_mode = CodeMirror.findModeByMIME(node.value);
-                setCodeMirrorMode(myCodeMirror, detected_mode);
+                var $filename_input = $('#filename');
+                // on select change set new mode
+                $mimetype_select.change(function(e){
+                    var selected = e.currentTarget;
+                    var node = selected.options[selected.selectedIndex];
+                    var detected_mode = CodeMirror.findModeByMIME(node.value);
+                    setCodeMirrorMode(myCodeMirror, detected_mode);
 
-                var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
-                var file_data = CodeMirror.getFilenameAndExt($filename.val());
-                var filename = file_data['filename'] || 'filename1';
-                $filename.val(filename + '.' + proposed_ext);
-            });
+                    var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
+                    var file_data = CodeMirror.getFilenameAndExt($filename_input.val());
+                    var filename = file_data['filename'] || 'filename1';
+                    $filename_input.val(filename + '.' + proposed_ext);
+                });
 
-            // on type the new filename set mode
-            $filename.keyup(function(e){
-                var file_data = CodeMirror.getFilenameAndExt(this.value);
-                if(file_data['ext'] != null){
-                    var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
-                    if (detected_mode){
-                        setCodeMirrorMode(myCodeMirror, detected_mode);
-                        $modes_select.val(detected_mode.mime);
+                // on type the new filename set mode
+                $filename_input.keyup(function(e){
+                    var file_data = CodeMirror.getFilenameAndExt(this.value);
+                    if(file_data['ext'] != null){
+                        var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
+                        if (detected_mode){
+                            setCodeMirrorMode(myCodeMirror, detected_mode);
+                            $mimetype_select.val(detected_mode.mime);
+                        }
                     }
-                }
+                });
             });
           </script>
         </div>
--- a/kallithea/templates/admin/repo_groups/repo_group_edit_perms.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/repo_groups/repo_group_edit_perms.html	Wed Jan 20 01:41:02 2016 +0100
@@ -75,7 +75,7 @@
                 %endfor
 
                 <%
-                _tmpl = h.literal("""' \
+                _tmpl = h.literal("""'\
                     <td><input type="radio" value="group.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="group.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="group.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
--- a/kallithea/templates/admin/repos/repo_edit_caches.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/repos/repo_edit_caches.html	Wed Jan 20 01:41:02 2016 +0100
@@ -1,7 +1,7 @@
 ${h.form(url('edit_repo_caches', repo_name=c.repo_name), method='put')}
 <div class="form">
    <div class="fields">
-       ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate Repository Cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate repository cache.')+"');")}
+       ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate Repository Cache'),class_="btn btn-small")}
       <div class="field" style="border:none;color:#888">
       <ul>
           <li>${_('Manually invalidate cache for this repository. On first access, the repository will be cached again.')}
--- a/kallithea/templates/admin/repos/repo_edit_permissions.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/repos/repo_edit_permissions.html	Wed Jan 20 01:41:02 2016 +0100
@@ -72,7 +72,7 @@
                 %endfor
 
                 <%
-                _tmpl = h.literal("""' \
+                _tmpl = h.literal("""'\
                     <td><input type="radio" value="repository.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="repository.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="repository.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
--- a/kallithea/templates/admin/user_groups/user_group_edit_perms.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/admin/user_groups/user_group_edit_perms.html	Wed Jan 20 01:41:02 2016 +0100
@@ -75,7 +75,7 @@
                 %endfor
 
                 <%
-                _tmpl = h.literal("""' \
+                _tmpl = h.literal("""'\
                     <td><input type="radio" value="usergroup.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="usergroup.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
                     <td><input type="radio" value="usergroup.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
--- a/kallithea/templates/base/base.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/base/base.html	Wed Jan 20 01:41:02 2016 +0100
@@ -127,20 +127,17 @@
       </div>
       -->
       <ul id="context-pages" class="horizontal-list">
-        <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-doc-text"></i> ${_('Summary')}</a></li>
+        <li ${is_current('summary')} data-context="summary"><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-doc-text"></i> ${_('Summary')}</a></li>
         %if rev:
-        <li ${is_current('changelog')}><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-clock"></i> ${_('Changelog')}</a></li>
+        <li ${is_current('changelog')} data-context="changelog"><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-clock"></i> ${_('Changelog')}</a></li>
         %else:
-        <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-clock"></i> ${_('Changelog')}</a></li>
+        <li ${is_current('changelog')} data-context="changelog"><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-clock"></i> ${_('Changelog')}</a></li>
         %endif
-        <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-doc-inv"></i> ${_('Files')}</a></li>
-        <li ${is_current('switch-to')}>
-          <a href="#" id="branch_tag_switcher_2" class="dropdown"><i class="icon-exchange"></i> ${_('Switch To')}</a>
-          <ul id="switch_to_list_2" class="switch_to submenu">
-            <li><a href="#">${_('Loading...')}</a></li>
-          </ul>
+        <li ${is_current('files')} data-context="files"><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-doc-inv"></i> ${_('Files')}</a></li>
+        <li ${is_current('switch-to')} data-context="switch-to">
+          <input id="branch_switcher" name="branch_switcher" type="hidden">
         </li>
-        <li ${is_current('options')}>
+        <li ${is_current('options')} data-context="options">
              %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
                <a href="${h.url('edit_repo',repo_name=c.repo_name)}" class="dropdown"><i class="icon-wrench"></i> ${_('Options')}</a>
              %else:
@@ -179,7 +176,7 @@
               %endif
              </ul>
         </li>
-        <li ${is_current('showpullrequest')}>
+        <li ${is_current('showpullrequest')} data-context="showpullrequest">
           <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> <i class="icon-git-pull-request"></i> ${_('Pull Requests')}
             %if c.repository_pull_requests:
               <span>${c.repository_pull_requests}</span>
@@ -189,15 +186,102 @@
       </ul>
   </div>
   <script type="text/javascript">
-      YUE.on('branch_tag_switcher_2','mouseover',function(){
-         var $branch_tag_switcher_2 = $('#branch_tag_switcher_2');
-         var loaded = $branch_tag_switcher_2.hasClass('loaded');
-         if(!loaded){
-             $branch_tag_switcher_2.addClass('loaded');
-             asynchtml("${h.url('branch_tag_switcher',repo_name=c.repo_name)}", $('#switch_to_list_2'));
-         }
-         return false;
+    $(document).ready(function() {
+      var bcache = {};
+
+      $("#branch_switcher").select2({
+          placeholder: '<i class="icon-exchange"></i> ${_('Switch To')}',
+          dropdownAutoWidth: true,
+          sortResults: prefixFirstSort,
+          formatResult: function(obj) {
+              return obj.text;
+          },
+          formatSelection: function(obj) {
+              return obj.text;
+          },
+          formatNoMatches: function(term) {
+              return "${_('No matches found')}";
+          },
+          escapeMarkup: function(m) {
+              // don't escape our custom placeholder
+              if (m.substr(0, 29) == '<i class="icon-exchange"></i>') {
+                  return m;
+              }
+
+              return Select2.util.escapeMarkup(m);
+          },
+          containerCssClass: "repo-switcher",
+          dropdownCssClass: "repo-switcher-dropdown",
+          query: function(query) {
+              var key = 'cache';
+              var cached = bcache[key];
+              if (cached) {
+                  var data = {
+                      results: []
+                  };
+                  // filter results
+                  $.each(cached.results, function() {
+                      var section = this.text;
+                      var children = [];
+                      $.each(this.children, function() {
+                          if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
+                              children.push({
+                                  'id': this.id,
+                                  'text': this.text,
+                                  'type': this.type,
+                                  'obj': this.obj
+                              });
+                          }
+                      });
+                      if (children.length !== 0) {
+                          data.results.push({
+                              'text': section,
+                              'children': children
+                          });
+                      }
+
+                  });
+                  query.callback(data);
+              } else {
+                  $.ajax({
+                      url: pyroutes.url('repo_refs_data', {
+                          'repo_name': '${c.repo_name}'
+                      }),
+                      data: {},
+                      dataType: 'json',
+                      type: 'GET',
+                      success: function(data) {
+                          bcache[key] = data;
+                          query.callback(data);
+                      }
+                  });
+              }
+          }
       });
+
+      $("#branch_switcher").on('select2-selecting', function(e) {
+          e.preventDefault();
+          var context = $('#context-bar .current').data('context');
+          if (context == 'files') {
+              window.location = pyroutes.url('files_home', {
+                  'repo_name': REPO_NAME,
+                  'revision': e.choice.id,
+                  'f_path': '',
+                  'at': e.choice.text
+              });
+          } else if (context == 'changelog') {
+              if (e.choice.type == 'tag' || e.choice.type == 'book') {
+                  $("#branch_filter").append($('<option/>').val(e.choice.text));
+              }
+              $("#branch_filter").val(e.choice.text).change();
+          } else {
+              window.location = pyroutes.url('changelog_home', {
+                  'repo_name': '${c.repo_name}',
+                  'branch': e.choice.text
+              });
+          }
+      });
+    });
   </script>
   <!--- END CONTEXT BAR -->
 </%def>
@@ -353,95 +437,98 @@
     </li>
 
     <script type="text/javascript">
-        var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
-        var cache = {}
-        /*format the look of items in the list*/
-        var format = function(state){
-            if (!state.id){
-              return state.text; // optgroup
-            }
-            var obj_dict = state.obj;
-            var tmpl = '';
-
-            if(obj_dict && state.type == 'repo'){
-                tmpl += '<span class="repo-icons">';
-                if(obj_dict['repo_type'] === 'hg'){
-                    tmpl += '<span class="repotag">hg</span> ';
+        $(document).ready(function(){
+            var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
+            var cache = {}
+            /*format the look of items in the list*/
+            var format = function(state){
+                if (!state.id){
+                  return state.text; // optgroup
                 }
-                else if(obj_dict['repo_type'] === 'git'){
-                    tmpl += '<span class="repotag">git</span> ';
-                }
-                if(obj_dict['private']){
-                    tmpl += '<i class="icon-keyhole-circled"></i> ';
-                }
-                else if(visual_show_public_icon){
-                    tmpl += '<i class="icon-globe"></i> ';
-                }
-                tmpl += '</span>';
-            }
-            if(obj_dict && state.type == 'group'){
-                    tmpl += '<i class="icon-folder"></i> ';
-            }
-            tmpl += state.text;
-            return tmpl;
-        }
+                var obj_dict = state.obj;
+                var tmpl = '';
 
-        $("#repo_switcher").select2({
-            placeholder: '<i class="icon-database"></i> ${_('Repositories')}',
-            dropdownAutoWidth: true,
-            formatResult: format,
-            formatSelection: format,
-            formatNoMatches: function(term){
-                return "${_('No matches found')}";
-            },
-            containerCssClass: "repo-switcher",
-            dropdownCssClass: "repo-switcher-dropdown",
-            escapeMarkup: function(m){
-                // don't escape our custom placeholder
-                if(m.substr(0,29) == '<i class="icon-database"></i>'){
-                    return m;
+                if(obj_dict && state.type == 'repo'){
+                    tmpl += '<span class="repo-icons">';
+                    if(obj_dict['repo_type'] === 'hg'){
+                        tmpl += '<span class="repotag">hg</span> ';
+                    }
+                    else if(obj_dict['repo_type'] === 'git'){
+                        tmpl += '<span class="repotag">git</span> ';
+                    }
+                    if(obj_dict['private']){
+                        tmpl += '<i class="icon-keyhole-circled"></i> ';
+                    }
+                    else if(visual_show_public_icon){
+                        tmpl += '<i class="icon-globe"></i> ';
+                    }
+                    tmpl += '</span>';
                 }
+                if(obj_dict && state.type == 'group'){
+                        tmpl += '<i class="icon-folder"></i> ';
+                }
+                tmpl += state.text;
+                return tmpl;
+            }
 
-                return Select2.util.escapeMarkup(m);
-            },
-            query: function(query){
-              var key = 'cache';
-              var cached = cache[key] ;
-              if(cached) {
-                var data = {results: []};
-                //filter results
-                $.each(cached.results, function(){
-                    var section = this.text;
-                    var children = [];
-                    $.each(this.children, function(){
-                        if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
-                            children.push({'id': this.id, 'text': this.text, 'type': this.type, 'obj': this.obj});
-                        }
-                    });
-                    if(children.length !== 0){
-                        data.results.push({'text': section, 'children': children});
+            $("#repo_switcher").select2({
+                placeholder: '<i class="icon-database"></i> ${_('Repositories')}',
+                dropdownAutoWidth: true,
+                sortResults: prefixFirstSort,
+                formatResult: format,
+                formatSelection: format,
+                formatNoMatches: function(term){
+                    return "${_('No matches found')}";
+                },
+                containerCssClass: "repo-switcher",
+                dropdownCssClass: "repo-switcher-dropdown",
+                escapeMarkup: function(m){
+                    // don't escape our custom placeholder
+                    if(m.substr(0,29) == '<i class="icon-database"></i>'){
+                        return m;
                     }
 
-                });
-                query.callback(data);
-              }else{
-                  $.ajax({
-                    url: "${h.url('repo_switcher_data')}",
-                    data: {},
-                    dataType: 'json',
-                    type: 'GET',
-                    success: function(data) {
-                      cache[key] = data;
-                      query.callback({results: data.results});
-                    }
-                  });
-              }
-            }
-        });
+                    return Select2.util.escapeMarkup(m);
+                },
+                query: function(query){
+                  var key = 'cache';
+                  var cached = cache[key] ;
+                  if(cached) {
+                    var data = {results: []};
+                    //filter results
+                    $.each(cached.results, function(){
+                        var section = this.text;
+                        var children = [];
+                        $.each(this.children, function(){
+                            if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
+                                children.push({'id': this.id, 'text': this.text, 'type': this.type, 'obj': this.obj});
+                            }
+                        });
+                        if(children.length !== 0){
+                            data.results.push({'text': section, 'children': children});
+                        }
 
-        $("#repo_switcher").on('select2-selecting', function(e){
-            e.preventDefault();
-            window.location = pyroutes.url('summary_home', {'repo_name': e.val});
+                    });
+                    query.callback(data);
+                  }else{
+                      $.ajax({
+                        url: "${h.url('repo_switcher_data')}",
+                        data: {},
+                        dataType: 'json',
+                        type: 'GET',
+                        success: function(data) {
+                          cache[key] = data;
+                          query.callback({results: data.results});
+                        }
+                      });
+                  }
+                }
+            });
+
+            $("#repo_switcher").on('select2-selecting', function(e){
+                e.preventDefault();
+                window.location = pyroutes.url('summary_home', {'repo_name': e.val});
+            });
         });
 
         ## Global mouse bindings ##
--- a/kallithea/templates/changeset/changeset.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/changeset/changeset.html	Wed Jan 20 01:41:02 2016 +0100
@@ -209,21 +209,6 @@
     ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
     <script type="text/javascript">
       $(document).ready(function(){
-          $('.show-inline-comments').change(function(e){
-              var target = e.currentTarget;
-              if(target == null){
-                  target = this;
-              }
-              var boxid = $(target).attr('id_for');
-              if(target.checked){
-                  $('#{0} .inline-comments'.format(boxid)).show();
-                  $('#{0} .inline-comments-button'.format(boxid)).show();
-              }else{
-                  $('#{0} .inline-comments'.format(boxid)).hide();
-                  $('#{0} .inline-comments-button'.format(boxid)).hide();
-              }
-          });
-
           $('.code-difftable').on('click', '.add-bubble', function(e){
               show_comment_form($(this));
           });
--- a/kallithea/templates/changeset/diff_block.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/changeset/diff_block.html	Wed Jan 20 01:41:02 2016 +0100
@@ -8,122 +8,104 @@
     <span target="${'diff-container-%s' % (id(change))}" class="diff-collapse-button">&uarr; ${_('Collapse Diff')} &uarr;</span>
 </div>
 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
-%for FID,(cs1, cs2, change, path, diff, stats) in change.iteritems():
-    <div id="${FID}_target" style="clear:both;margin-top:25px"></div>
-    <div id="${FID}" class="diffblock  margined comm">
+%for id_fid, (a_rev, cs_rev, op, filename, diff, stats) in change.iteritems():
+    ${diff_block_diffblock(id_fid, h.FID(cs_rev, filename), op, filename, diff,
+        c.repo_name, a_rev, 'rev', a_rev,
+        c.repo_name, cs_rev, 'rev', cs_rev)}
+%endfor
+</div>
+</%def>
+
+<%def name="diff_block_simple(files, changes)">
+<div class="diff-collapse">
+    <span target="${'diff-container-%s' % (id(changes))}" class="diff-collapse-button">&uarr; ${_('Collapse Diff')} &uarr;</span>
+</div>
+<div class="diff-container" id="${'diff-container-%s' % (id(changes))}">
+  %for fid, ch, f, stat in files:
+    <%
+    op, filename, diff = changes[fid]
+    %>
+    ${diff_block_diffblock(h.FID('', filename), None, op, filename, diff,
+        c.a_repo.repo_name, c.a_rev, c.a_ref_type, c.a_ref_name,
+        c.cs_repo.repo_name, c.cs_rev, c.cs_ref_type, c.cs_ref_name)}
+  %endfor
+</div>
+</%def>
+
+<%def name="diff_block_diffblock(id_fid, url_fid, op, filename, diff,
+    a_repo_name, a_rev, a_ref_type, a_ref_name,
+    cs_repo_name, cs_rev, cs_ref_type, cs_ref_name)"
+>
+    <div id="${id_fid}_target" style="clear:both;margin-top:25px"></div>
+    <div id="${id_fid}" class="diffblock margined comm">
         <div class="code-header">
             <div class="changeset_header">
                 <div class="changeset_file">
-                    ${h.link_to_if(change!='D',h.safe_unicode(path),h.url('files_home',repo_name=c.repo_name,
-                    revision=cs2,f_path=h.safe_unicode(path)))}
+                    ${h.safe_unicode(filename)} |
+                    ## TODO: link to ancestor and head of other instead of exactly other
+                    %if op == 'A':
+                      ${_('Added')}
+                      <a class="spantag" href="${h.url('files_home', repo_name=cs_repo_name, f_path=filename, revision=cs_rev)}">${h.short_ref(cs_ref_type, cs_ref_name)}</a>
+                    %elif op == 'M':
+                      <a class="spantag" href="${h.url('files_home', repo_name=a_repo_name, f_path=filename, revision=a_rev)}">${h.short_ref(a_ref_type, a_ref_name)}</a>
+                      <i class="icon-right"></i>
+                      <a class="spantag" href="${h.url('files_home', repo_name=cs_repo_name, f_path=filename, revision=cs_rev)}">${h.short_ref(cs_ref_type, cs_ref_name)}</a>
+                    %elif op == 'D':
+                      ${_('Deleted')}
+                      <a class="spantag" href="${h.url('files_home', repo_name=a_repo_name, f_path=filename, revision=a_rev)}">${h.short_ref(a_ref_type, a_ref_name)}</a>
+                    %elif op == 'R':
+                      ${_('Renamed')}
+                      <a class="spantag" href="${h.url('files_home', repo_name=a_repo_name, f_path=filename, revision=a_rev)}">${h.short_ref(a_ref_type, a_ref_name)}</a>
+                      <i class="icon-right"></i>
+                      <a class="spantag" href="${h.url('files_home', repo_name=cs_repo_name, f_path=filename, revision=cs_rev)}">${h.short_ref(cs_ref_type, cs_ref_name)}</a>
+                    %else:
+                      ${op}???
+                    %endif
                 </div>
                 <div class="diff-actions">
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${_('Show full diff for this file')}">
+                  <a href="${h.url('files_diff_home',repo_name=cs_repo_name,f_path=h.safe_unicode(filename),diff2=cs_rev,diff1=a_rev,diff='diff',fulldiff=1)}" class="tooltip" title="${_('Show full diff for this file')}">
                       <i class="icon-file-code"></i>
                   </a>
-                  <a href="${h.url('files_diff_2way_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" class="tooltip" title="${_('Show full side-by-side diff for this file')}">
+                  <a href="${h.url('files_diff_2way_home',repo_name=cs_repo_name,f_path=h.safe_unicode(filename),diff2=cs_rev,diff1=a_rev,diff='diff',fulldiff=1)}" class="tooltip" title="${_('Show full side-by-side diff for this file')}">
                       <i class="icon-docs"></i>
                   </a>
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='raw')}" class="tooltip" title="${_('Raw diff')}">
+                  <a href="${h.url('files_diff_home',repo_name=cs_repo_name,f_path=h.safe_unicode(filename),diff2=cs_rev,diff1=a_rev,diff='raw')}" class="tooltip" title="${_('Raw diff')}">
                       <i class="icon-diff"></i>
                   </a>
-                  <a href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(path),diff2=cs2,diff1=cs1,diff='download')}" class="tooltip" title="${_('Download diff')}">
+                  <a href="${h.url('files_diff_home',repo_name=cs_repo_name,f_path=h.safe_unicode(filename),diff2=cs_rev,diff1=a_rev,diff='download')}" class="tooltip" title="${_('Download diff')}">
                       <i class="icon-floppy"></i>
                   </a>
-                  ${c.ignorews_url(request.GET, h.FID(cs2,path))}
-                  ${c.context_url(request.GET, h.FID(cs2,path))}
+                  ${c.ignorews_url(request.GET, url_fid)}
+                  ${c.context_url(request.GET, url_fid)}
                 </div>
                 <span style="float:right;margin-top:-3px">
-                  <label>
-                  ${_('Show inline comments')}
-                  ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(cs2,path))}
-                  </label>
+                    <label>
+                        ${_('Show inline comments')}
+                        ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=url_fid)}
+                    </label>
                 </span>
             </div>
         </div>
-        <div class="code-body full_f_path" data-f_path="${h.safe_unicode(path)}">
+        <div class="code-body full_f_path" data-f_path="${h.safe_unicode(filename)}">
             ${diff|n}
-            %if path.rsplit('.')[-1] in ['png', 'gif', 'jpg', 'bmp']:
+            %if filename.rsplit('.')[-1] in ['png', 'gif', 'jpg', 'bmp']:
               <div class="btn btn-image-diff-show">Show images</div>
-              %if change =='M':
-                <div id="${FID}_image-diff" class="btn btn-image-diff-swap" style="display:none">Press to swap images</div>
+              %if op == 'M':
+                <div id="${id_fid}_image-diff" class="btn btn-image-diff-swap" style="display:none">Press to swap images</div>
               %endif
               <div style="font-size: 0">
-                %if change == 'M':
-                  <img id="${FID}_image-diff-img-a" class="img-diff img-diff-swapable" style="display:none"
-                      realsrc="${h.url('files_raw_home',repo_name=c.repo_name,revision=cs1,f_path=path)}" />
+                %if op in 'DM':
+                  <img id="${id_fid}_image-diff-img-a" class="img-diff img-diff-swapable" style="display:none"
+                      realsrc="${h.url('files_raw_home',repo_name=a_repo_name,revision=a_rev,f_path=filename)}" />
                 %endif
-                %if change in 'AM':
-                  <img id="${FID}_image-diff-img-b" class="img-diff img-diff-swapable" style="display:none"
-                      realsrc="${h.url('files_raw_home',repo_name=c.repo_name,revision=cs2,f_path=path)}" />
+                %if op in 'AM':
+                  <img id="${id_fid}_image-diff-img-b" class="img-diff img-diff-swapable" style="display:none"
+                      realsrc="${h.url('files_raw_home',repo_name=cs_repo_name,revision=cs_rev,f_path=filename)}" />
                 %endif
               </div>
             %endif
         </div>
     </div>
-%endfor
-</div>
-</%def>
-
-<%def name="diff_block_simple(change)">
-
-  %for op,filenode_path,diff in change:
-    <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
-    <div id="${h.FID('',filenode_path)}" class="diffblock  margined comm">
-      <div class="code-header">
-          <div class="changeset_header">
-              <div class="changeset_file">
-                  ${h.safe_unicode(filenode_path)} |
-                  ## TODO: link to ancestor and head of other instead of exactly other
-                  %if op == 'A':
-                    ${_('Added')}
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a>
-                  %elif op == 'M':
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a>
-                    <i class="icon-right"></i>
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a>
-                  %elif op == 'D':
-                    ${_('Deleted')}
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a>
-                  %elif op == 'R':
-                    ${_('Renamed')}
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.a_repo.repo_name, f_path=filenode_path, revision=c.a_rev)}">${h.short_id(c.a_ref_name) if c.a_ref_type=='rev' else c.a_ref_name}</a>
-                    <i class="icon-right"></i>
-                    <a class="spantag" href="${h.url('files_home', repo_name=c.cs_repo.repo_name, f_path=filenode_path, revision=c.cs_rev)}">${h.short_id(c.cs_ref_name) if c.cs_ref_type=='rev' else c.cs_ref_name}</a>
-                  %else:
-                    ${op}???
-                  %endif
-              </div>
-              <div class="diff-actions">
-                <a href="${h.url('files_diff_2way_home',repo_name=c.cs_repo.repo_name,f_path=h.safe_unicode(filenode_path),diff1=c.a_rev,diff2=c.cs_rev,diff='diff',fulldiff=1)}" class="tooltip" title="${_('Show full side-by-side diff for this file')}">
-                  <i class="icon-docs"></i>
-                </a>
-                ${c.ignorews_url(request.GET)}
-                ${c.context_url(request.GET)}
-              </div>
-          </div>
-      </div>
-        <div class="code-body full_f_path" data-f_path="${h.safe_unicode(filenode_path)}">
-            ${diff|n}
-            %if filenode_path.rsplit('.')[-1] in ['png', 'gif', 'jpg', 'bmp']:
-              <div class="btn btn-image-diff-show">Show images</div>
-              %if op == 'M':
-                <div id="${h.FID('',filenode_path)}_image-diff" class="btn btn-image-diff-swap" style="display:none">Press to swap images</div>
-              %endif
-              <div style="font-size: 0">
-                %if op == 'M':
-                  <img id="${h.FID('',filenode_path)}_image-diff-img-a" class="img-diff img-diff-swapable" style="display:none"
-                      realsrc="${h.url('files_raw_home',repo_name=c.a_repo.repo_name,revision=c.a_rev,f_path=filenode_path) if op in 'DM' else ''}" />
-                %endif
-                %if op in 'AM':
-                  <img id="${h.FID('',filenode_path)}_image-diff-img-b" class="img-diff img-diff-swapable" style="display:none"
-                      realsrc="${h.url('files_raw_home',repo_name=c.cs_repo.repo_name,revision=c.cs_rev,f_path=filenode_path) if op in 'AM' else ''}" />
-                %endif
-              </div>
-            %endif
-        </div>
-    </div>
-  %endfor
 </%def>
 
 <%def name="diff_block_js()">
@@ -149,6 +131,31 @@
     };
     $('.btn-image-diff-swap').mouseup(reset);
     $('.btn-image-diff-swap').mouseleave(reset);
+
+    $('.diff-collapse-button').click(function(e) {
+        var $button = $(e.currentTarget);
+        var $target = $('#' + $button.attr('target'));
+        if($target.hasClass('hidden')){
+            $target.removeClass('hidden');
+            $button.html("&uarr; {0} &uarr;".format(_TM['Collapse Diff']));
+        }
+        else if(!$target.hasClass('hidden')){
+            $target.addClass('hidden');
+            $button.html("&darr; {0} &darr;".format(_TM['Expand Diff']));
+        }
+    });
+    $('.show-inline-comments').change(function(e){
+        var target = e.currentTarget;
+        if(target == null){
+            target = this;
+        }
+        var boxid = $(target).attr('id_for');
+        if(target.checked){
+            $('#{0} .inline-comments'.format(boxid)).show();
+        }else{
+            $('#{0} .inline-comments'.format(boxid)).hide();
+        }
+    });
 });
 </script>
 </%def>
--- a/kallithea/templates/compare/compare_diff.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/compare/compare_diff.html	Wed Jan 20 01:41:02 2016 +0100
@@ -26,9 +26,15 @@
     </div>
     <div class="table">
         <div id="body" class="diffblock">
-            <div class="code-header">
+            <div class="compare-revision-selector">
+                ## divs are "inline-block" and cannot have whitespace between them.
                 <div>
-                    ${h.hidden('compare_org')} <i class="icon-right"></i> ${h.hidden('compare_other')}
+                    ${h.hidden('compare_org')}
+                </div><div>
+                    <i class="icon-right"></i>
+                </div><div>
+                    ${h.hidden('compare_other')}
+                </div><div>
                     %if not c.compare_home:
                         <a class="btn btn-small" href="${c.swap_url}"><i class="icon-arrows-cw"></i> ${_('Swap')}</a>
                     %endif
@@ -82,9 +88,7 @@
         ## diff block
         <%namespace name="diff_block" file="/changeset/diff_block.html"/>
         ${diff_block.diff_block_js()}
-        %for fid, change, f, stat in c.files:
-          ${diff_block.diff_block_simple([c.changes[fid]])}
-        %endfor
+        ${diff_block.diff_block_simple(c.files, c.changes)}
         % if c.limited_diff:
           <h4>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}">${_('Show full diff')}</a></h4>
         % endif
--- a/kallithea/templates/email_templates/password_reset.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/email_templates/password_reset.html	Wed Jan 20 01:41:02 2016 +0100
@@ -4,9 +4,13 @@
 <h4>${_('Hello %s') % user}</h4>
 
 <p>${_('We have received a request to reset the password for your account.')}</p>
+%if reset_token is None:
+<p>${_('This account is however managed outside this system and the password cannot be changed here.')}</p>
+%else:
 <p>${_('To set a new password, click the following link')}:</p>
 <p><a href="${reset_url}">${reset_url}</a></p>
 
 <p>${_("Should you not be able to use the link above, please type the following code into the password reset form")}: <code>${reset_token}</code></p>
+%endif
 
 <p>${_("If it weren't you who requested the password reset, just disregard this message.")}</p>
--- a/kallithea/templates/email_templates/password_reset.txt	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/email_templates/password_reset.txt	Wed Jan 20 01:41:02 2016 +0100
@@ -3,11 +3,15 @@
 
 ${_('Hello %s') % user|n,unicode}
 
-${_('We have received a request to reset the password for your account..')|n,unicode}
+${_('We have received a request to reset the password for your account.')|n,unicode}
+%if reset_token is None:
+${_('This account is however managed outside this system and the password cannot be changed here.')|n,unicode}
+%else:
 ${_('To set a new password, click the following link')|n,unicode}:
 
 ${reset_url|n,unicode}
 
 ${_("Should you not be able to use the link above, please type the following code into the password reset form")|n,unicode}: ${reset_token|n,unicode}
+%endif
 
 ${_("If it weren't you who requested the password reset, just disregard this message.")|n,unicode}
--- a/kallithea/templates/files/files_add.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/files/files_add.html	Wed Jan 20 01:41:02 2016 +0100
@@ -44,14 +44,14 @@
                   ${_('or')} <div class="btn btn-small" id="upload_file_enable">${_('Upload File')}</div>
               </span>
               <span id="upload_file_container" class="reviewer_ac" style="display:none">
-                  <input type="file"  size="20" name="upload_file" id="upload_file">
+                  <input type="file" size="20" name="upload_file" id="upload_file">
                   ${_('or')} <div class="btn btn-small" id="file_enable">${_('Create New File')}</div>
               </span>
           </h3>
             <div id="body" class="codeblock">
-            <div class="code-header" id="set_mode_header">
-                <label class="commit" for="set_mode">${_('New file mode')}</label>
-                <select id="set_mode" name="set_mode"/>
+            <div class="code-header" id="mimetype_header">
+                <label class="commit" for="mimetype">${_('New file type')}</label>
+                <select id="mimetype" name="mimetype"/>
             </div>
                 <div id="editor_container">
                     <pre id="editor_pre"></pre>
@@ -66,50 +66,53 @@
             </div>
             ${h.end_form()}
             <script type="text/javascript">
-            var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path)}";
-            var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
+                $(document).ready(function(){
+                    var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path)}";
+                    var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
 
-            //inject new modes, based on codeMirrors modeInfo object
-            $('#set_mode').each(function(){
-                var modes_select = this;
-                var index = 1;
-                for(var i=0;i<CodeMirror.modeInfo.length;i++){
-                    var m = CodeMirror.modeInfo[i];
-                    var opt = new Option(m.name, m.mime);
-                    $(opt).attr('mode', m.mode);
-                    if (m.mime == 'text/plain') {
-                        // default plain text
-                        $(opt).prop('selected', true);
-                        modes_select.options[0] = opt;
-                    } else {
-                        modes_select.options[index++] = opt;
-                    }
-                }
-            });
-            $('#set_mode').change(function(e){
-                var selected = e.currentTarget;
-                var node = selected.options[selected.selectedIndex];
-                var detected_mode = CodeMirror.findModeByMIME(node.value);
-                setCodeMirrorMode(myCodeMirror, detected_mode);
+                    //inject new modes, based on codeMirrors modeInfo object
+                    var $mimetype_select = $('#mimetype');
+                    $mimetype_select.each(function(){
+                        var modes_select = this;
+                        var index = 1;
+                        for(var i=0;i<CodeMirror.modeInfo.length;i++){
+                            var m = CodeMirror.modeInfo[i];
+                            var opt = new Option(m.name, m.mime);
+                            $(opt).attr('mode', m.mode);
+                            if (m.mime == 'text/plain') {
+                                // default plain text
+                                $(opt).prop('selected', true);
+                                modes_select.options[0] = opt;
+                            } else {
+                                modes_select.options[index++] = opt;
+                            }
+                        }
+                    });
+                    var $filename_input = $('#filename');
+                    $mimetype_select.change(function(e){
+                        var selected = e.currentTarget;
+                        var node = selected.options[selected.selectedIndex];
+                        var detected_mode = CodeMirror.findModeByMIME(node.value);
+                        setCodeMirrorMode(myCodeMirror, detected_mode);
 
-                var filenameInput = $('#filename');
-                var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
-                var file_data = CodeMirror.getFilenameAndExt(filenameInput.val());
-                var filename = file_data['filename'] || 'filename1';
-                filenameInput.val(filename + '.' + proposed_ext);
-            });
+                        var proposed_ext = CodeMirror.findExtensionByMode(detected_mode);
+                        var file_data = CodeMirror.getFilenameAndExt($filename_input.val());
+                        var filename = file_data['filename'] || 'filename1';
+                        $filename_input.val(filename + '.' + proposed_ext);
+                    });
 
-            // on type the new filename set mode
-            $('#filename').keyup(function(e){
-                var file_data = CodeMirror.getFilenameAndExt(this.value);
-                if(file_data['ext'] != null){
-                    var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
-                    if (detected_mode){
-                        setCodeMirrorMode(myCodeMirror, detected_mode);
-                        $('#set_mode').val(detected_mode.mime);
-                    }
-                }
-            });
+                    // on type the new filename set mode
+                    $filename_input.keyup(function(e){
+                        var file_data = CodeMirror.getFilenameAndExt(this.value);
+                        if(file_data['ext'] != null){
+                            var detected_mode = CodeMirror.findModeByExtension(file_data['ext']) || CodeMirror.findModeByMIME('text/plain');
+                            if (detected_mode){
+                                setCodeMirrorMode(myCodeMirror, detected_mode);
+                                $mimetype_select.val(detected_mode.mime);
+                            }
+                        }
+                    });
+                });
             </script>
         </div>
     </div>
--- a/kallithea/templates/files/files_edit.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/files/files_edit.html	Wed Jan 20 01:41:02 2016 +0100
@@ -55,8 +55,8 @@
                       % endif
                     </div>
                 </div>
-                <label class="commit" for="set_mode">${_('Editing file')}: ${c.file.unicode_path}</label>
-                <select id="set_mode" name="set_mode"/>
+                <label class="commit" for="mimetype">${_('Editing file')}: ${c.file.unicode_path}</label>
+                <select id="mimetype" name="mimetype"/>
             </div>
                 <pre id="editor_pre"></pre>
                 <textarea id="editor" name="content" style="display:none">${h.escape(c.file.content)|n}</textarea>
@@ -73,40 +73,41 @@
 </div>
 
 <script type="text/javascript">
-$(document).ready(function(){
-    var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.file.path)}";
-    var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
+    $(document).ready(function(){
+        var reset_url = "${h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.file.path)}";
+        var myCodeMirror = initCodeMirror('editor', "${request.script_name}", reset_url);
 
-   //inject new modes, based on codeMirrors modeInfo object
-    $('#set_mode').each(function(){
-        var modes_select = this;
-        var index = 1;
-        for(var i=0;i<CodeMirror.modeInfo.length;i++){
-            var m = CodeMirror.modeInfo[i];
-            var opt = new Option(m.name, m.mime);
-            $(opt).attr('mode', m.mode);
-            if (m.mime == 'text/plain') {
-                // default plain text
-                $(opt).prop('selected', true);
-                modes_select.options[0] = opt;
-            } else {
-                modes_select.options[index++] = opt;
+       //inject new modes, based on codeMirrors modeInfo object
+        var $mimetype_select = $('#mimetype');
+        $mimetype_select.each(function(){
+            var modes_select = this;
+            var index = 1;
+            for(var i=0;i<CodeMirror.modeInfo.length;i++){
+                var m = CodeMirror.modeInfo[i];
+                var opt = new Option(m.name, m.mime);
+                $(opt).attr('mode', m.mode);
+                if (m.mime == 'text/plain') {
+                    // default plain text
+                    $(opt).prop('selected', true);
+                    modes_select.options[0] = opt;
+                } else {
+                    modes_select.options[index++] = opt;
+                }
             }
+        });
+        // try to detect the mode based on the file we edit
+        var detected_mode = CodeMirror.findModeByExtension("${c.file.extension}");
+        if(detected_mode){
+            setCodeMirrorMode(myCodeMirror, detected_mode);
+            $($mimetype_select.find('option[value="'+detected_mode.mime+'"]')[0]).prop('selected', true);
         }
+
+        $mimetype_select.on('change', function(e){
+            var selected = e.currentTarget;
+            var node = selected.options[selected.selectedIndex];
+            var detected_mode = CodeMirror.findModeByMIME(node.value);
+            setCodeMirrorMode(myCodeMirror, detected_mode);
+        });
     });
-    // try to detect the mode based on the file we edit
-    var detected_mode = CodeMirror.findModeByExtension("${c.file.extension}");
-    if(detected_mode){
-        setCodeMirrorMode(myCodeMirror, detected_mode);
-        $($('#set_mode option[value="'+detected_mode.mime+'"]')[0]).prop('selected', true);
-    }
-
-    $('#set_mode').on('change', function(e){
-        var selected = e.currentTarget;
-        var node = selected.options[selected.selectedIndex];
-        var detected_mode = CodeMirror.findModeByMIME(node.value);
-        setCodeMirrorMode(myCodeMirror, detected_mode);
-    });
-});
 </script>
 </%def>
--- a/kallithea/templates/files/files_source.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/files/files_source.html	Wed Jan 20 01:41:02 2016 +0100
@@ -63,15 +63,21 @@
           ${_('Binary file (%s)') % c.file.mimetype}
         </div>
       %else:
-        %if c.file.size < c.cut_off_limit:
+        %if c.file.size < c.cut_off_limit or c.fulldiff:
             %if c.annotate:
               ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
             %else:
               ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
             %endif
         %else:
-            ${_('File is too big to display')} ${h.link_to(_('Show as raw'),
-            h.url('files_raw_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path))}
+            <h4>
+            ${_('File is too big to display.')}
+            %if c.annotate:
+              ${h.link_to(_('Show full annotation anyway.'), h.url.current(fulldiff=1, **request.GET.mixed()))}
+            %else:
+              ${h.link_to(_('Show as raw.'), h.url('files_raw_home',repo_name=c.repo_name,revision=c.file_changeset.raw_id,f_path=c.f_path))}
+            %endif
+            </h4>
         %endif
       %endif
     </div>
--- a/kallithea/templates/pullrequests/pullrequest_show.html	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/templates/pullrequests/pullrequest_show.html	Wed Jan 20 01:41:02 2016 +0100
@@ -356,9 +356,7 @@
     <div class="commentable-diff">
     <%namespace name="diff_block" file="/changeset/diff_block.html"/>
     ${diff_block.diff_block_js()}
-    %for fid, change, f, stat in c.files:
-      ${diff_block.diff_block_simple([c.changes[fid]])}
-    %endfor
+    ${diff_block.diff_block_simple(c.files, c.changes)}
     % if c.limited_diff:
       <h4>${_('Changeset was too big and was cut off...')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}">${_('Show full diff anyway')}</a></h4>
     % endif
--- a/kallithea/tests/__init__.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/__init__.py	Wed Jan 20 01:41:02 2016 +0100
@@ -100,14 +100,14 @@
 TEST_USER_REGULAR2_PASS = 'test12'
 TEST_USER_REGULAR2_EMAIL = 'test_regular2@example.com'
 
-HG_REPO = 'vcs_test_hg'
-GIT_REPO = 'vcs_test_git'
+HG_REPO = u'vcs_test_hg'
+GIT_REPO = u'vcs_test_git'
 
-NEW_HG_REPO = 'vcs_test_hg_new'
-NEW_GIT_REPO = 'vcs_test_git_new'
+NEW_HG_REPO = u'vcs_test_hg_new'
+NEW_GIT_REPO = u'vcs_test_git_new'
 
-HG_FORK = 'vcs_test_hg_fork'
-GIT_FORK = 'vcs_test_git_fork'
+HG_FORK = u'vcs_test_hg_fork'
+GIT_FORK = u'vcs_test_git_fork'
 
 ## VCS
 SCM_TESTS = ['hg', 'git']
@@ -220,7 +220,6 @@
         user = user and User.get(user)
         user = user and user.username
         self.assertEqual(user, expected_username)
-        self.assertEqual(cookie.get('is_authenticated'), True)
 
     def authentication_token(self):
         return self.app.get(url('authentication_token')).body
--- a/kallithea/tests/api/api_base.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/api/api_base.py	Wed Jan 20 01:41:02 2016 +0100
@@ -38,8 +38,8 @@
 
 
 API_URL = '/_admin/api'
-TEST_USER_GROUP = 'test_user_group'
-TEST_REPO_GROUP = 'test_repo_group'
+TEST_USER_GROUP = u'test_user_group'
+TEST_REPO_GROUP = u'test_repo_group'
 
 fixture = Fixture()
 
@@ -99,8 +99,8 @@
             username='test-api',
             password='test',
             email='test@example.com',
-            firstname='first',
-            lastname='last'
+            firstname=u'first',
+            lastname=u'last'
         )
         Session().commit()
         cls.TEST_USER_LOGIN = cls.test_user.username
@@ -278,7 +278,7 @@
         self._compare_error(id_, expected, given=response.body)
 
     def test_api_pull(self):
-        repo_name = 'test_pull'
+        repo_name = u'test_pull'
         r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         r.clone_uri = os.path.join(TESTS_TMP_PATH, self.REPO)
         Session.add(r)
@@ -368,7 +368,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_lock_repo_lock_aquire_by_non_admin(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                             cur_user=self.TEST_USER_LOGIN)
         try:
@@ -390,7 +390,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                             cur_user=self.TEST_USER_LOGIN)
         try:
@@ -465,7 +465,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_lock_repo_lock_optional_not_locked(self):
-        repo_name = 'api_not_locked'
+        repo_name = u'api_not_locked'
         repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                             cur_user=self.TEST_USER_LOGIN)
         self.assertEqual(repo.locked, [None, None])
@@ -516,7 +516,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_get_locks_with_one_locked_repo(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                                    cur_user=self.TEST_USER_LOGIN)
         Repository.lock(repo, User.get_by_username(self.TEST_USER_LOGIN).user_id)
@@ -529,7 +529,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_get_locks_with_one_locked_repo_for_specific_user(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                                    cur_user=self.TEST_USER_LOGIN)
         Repository.lock(repo, User.get_by_username(self.TEST_USER_LOGIN).user_id)
@@ -766,7 +766,7 @@
         self._compare_error(id_, expected, given=response.body)
 
     def test_api_get_repo(self):
-        new_group = 'some_new_group'
+        new_group = u'some_new_group'
         make_user_group(new_group)
         RepoModel().grant_user_group_permission(repo=self.REPO,
                                                 group_name=new_group,
@@ -975,7 +975,7 @@
             RepoModel().revoke_user_permission(self.REPO, self.TEST_USER_LOGIN)
 
     def test_api_create_repo(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         id_, params = _build_data(self.apikey, 'create_repo',
                                   repo_name=repo_name,
                                   owner=TEST_USER_ADMIN_LOGIN,
@@ -995,7 +995,7 @@
         fixture.destroy_repo(repo_name)
 
     def test_api_create_repo_and_repo_group(self):
-        repo_name = 'my_gr/api-repo'
+        repo_name = u'my_gr/api-repo'
         id_, params = _build_data(self.apikey, 'create_repo',
                                   repo_name=repo_name,
                                   owner=TEST_USER_ADMIN_LOGIN,
@@ -1012,11 +1012,11 @@
         expected = ret
         self._compare_ok(id_, expected, given=response.body)
         fixture.destroy_repo(repo_name)
-        fixture.destroy_repo_group('my_gr')
+        fixture.destroy_repo_group(u'my_gr')
 
     def test_api_create_repo_in_repo_group_without_permission(self):
-        repo_group_name = '%s/api-repo-repo' % TEST_REPO_GROUP
-        repo_name = '%s/api-repo' % repo_group_name
+        repo_group_name = u'%s/api-repo-repo' % TEST_REPO_GROUP
+        repo_name = u'%s/api-repo' % repo_group_name
 
         rg = fixture.create_repo_group(repo_group_name)
         Session().commit()
@@ -1048,7 +1048,7 @@
         fixture.destroy_repo_group(repo_group_name)
 
     def test_api_create_repo_unknown_owner(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         owner = 'i-dont-exist'
         id_, params = _build_data(self.apikey, 'create_repo',
                                   repo_name=repo_name,
@@ -1060,7 +1060,7 @@
         self._compare_error(id_, expected, given=response.body)
 
     def test_api_create_repo_dont_specify_owner(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         owner = 'i-dont-exist'
         id_, params = _build_data(self.apikey, 'create_repo',
                                   repo_name=repo_name,
@@ -1080,7 +1080,7 @@
         fixture.destroy_repo(repo_name)
 
     def test_api_create_repo_by_non_admin(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         owner = 'i-dont-exist'
         id_, params = _build_data(self.apikey_regular, 'create_repo',
                                   repo_name=repo_name,
@@ -1100,7 +1100,7 @@
         fixture.destroy_repo(repo_name)
 
     def test_api_create_repo_by_non_admin_specify_owner(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         owner = 'i-dont-exist'
         id_, params = _build_data(self.apikey_regular, 'create_repo',
                                   repo_name=repo_name,
@@ -1124,7 +1124,7 @@
 
     @mock.patch.object(RepoModel, 'create', crash)
     def test_api_create_repo_exception_occurred(self):
-        repo_name = 'api-repo'
+        repo_name = u'api-repo'
         id_, params = _build_data(self.apikey, 'create_repo',
                                   repo_name=repo_name,
                                   owner=TEST_USER_ADMIN_LOGIN,
@@ -1135,7 +1135,7 @@
 
     @parameterized.expand([
         ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
-        ('description', {'description': 'new description'}),
+        ('description', {'description': u'new description'}),
         ('active', {'active': True}),
         ('active', {'active': False}),
         ('clone_uri', {'clone_uri': 'http://example.com/repo'}),
@@ -1144,11 +1144,11 @@
         ('enable_statistics', {'enable_statistics': True}),
         ('enable_locking', {'enable_locking': True}),
         ('enable_downloads', {'enable_downloads': True}),
-        ('name', {'name': 'new_repo_name'}),
-        ('repo_group', {'group': 'test_group_for_update'}),
+        ('name', {'name': u'new_repo_name'}),
+        ('repo_group', {'group': u'test_group_for_update'}),
     ])
     def test_api_update_repo(self, changing_attr, updates):
-        repo_name = 'api_update_me'
+        repo_name = u'api_update_me'
         repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         if changing_attr == 'repo_group':
             fixture.create_repo_group(updates['group'])
@@ -1159,7 +1159,7 @@
         if changing_attr == 'name':
             repo_name = updates['name']
         if changing_attr == 'repo_group':
-            repo_name = '/'.join([updates['group'], repo_name])
+            repo_name = u'/'.join([updates['group'], repo_name])
         try:
             expected = {
                 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
@@ -1172,7 +1172,7 @@
                 fixture.destroy_repo_group(updates['group'])
 
     def test_api_update_repo_repo_group_does_not_exist(self):
-        repo_name = 'admin_owned'
+        repo_name = u'admin_owned'
         fixture.create_repo(repo_name)
         updates = {'group': 'test_group_for_update'}
         id_, params = _build_data(self.apikey, 'update_repo',
@@ -1185,7 +1185,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_update_repo_regular_user_not_allowed(self):
-        repo_name = 'admin_owned'
+        repo_name = u'admin_owned'
         fixture.create_repo(repo_name)
         updates = {'active': False}
         id_, params = _build_data(self.apikey_regular, 'update_repo',
@@ -1199,7 +1199,7 @@
 
     @mock.patch.object(RepoModel, 'update', crash)
     def test_api_update_repo_exception_occurred(self):
-        repo_name = 'api_update_me'
+        repo_name = u'api_update_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         id_, params = _build_data(self.apikey, 'update_repo',
                                   repoid=repo_name, owner=TEST_USER_ADMIN_LOGIN,)
@@ -1211,8 +1211,8 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_update_repo_regular_user_change_repo_name(self):
-        repo_name = 'admin_owned'
-        new_repo_name = 'new_repo_name'
+        repo_name = u'admin_owned'
+        new_repo_name = u'new_repo_name'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         RepoModel().grant_user_permission(repo=repo_name,
                                           user=self.TEST_USER_LOGIN,
@@ -1231,8 +1231,8 @@
             fixture.destroy_repo(new_repo_name)
 
     def test_api_update_repo_regular_user_change_repo_name_allowed(self):
-        repo_name = 'admin_owned'
-        new_repo_name = 'new_repo_name'
+        repo_name = u'admin_owned'
+        new_repo_name = u'new_repo_name'
         repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         RepoModel().grant_user_permission(repo=repo_name,
                                           user=self.TEST_USER_LOGIN,
@@ -1254,7 +1254,7 @@
             fixture.destroy_repo(new_repo_name)
 
     def test_api_update_repo_regular_user_change_owner(self):
-        repo_name = 'admin_owned'
+        repo_name = u'admin_owned'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         RepoModel().grant_user_permission(repo=repo_name,
                                           user=self.TEST_USER_LOGIN,
@@ -1270,7 +1270,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_delete_repo(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
 
         id_, params = _build_data(self.apikey, 'delete_repo',
@@ -1288,7 +1288,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_delete_repo_by_non_admin(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
                             cur_user=self.TEST_USER_LOGIN)
         id_, params = _build_data(self.apikey_regular, 'delete_repo',
@@ -1306,7 +1306,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_delete_repo_by_non_admin_no_permission(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         try:
             id_, params = _build_data(self.apikey_regular, 'delete_repo',
@@ -1318,7 +1318,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_delete_repo_exception_occurred(self):
-        repo_name = 'api_delete_me'
+        repo_name = u'api_delete_me'
         fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
         try:
             with mock.patch.object(RepoModel, 'delete', crash):
@@ -1332,7 +1332,7 @@
             fixture.destroy_repo(repo_name)
 
     def test_api_fork_repo(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         id_, params = _build_data(self.apikey, 'fork_repo',
                                   repoid=self.REPO,
                                   fork_name=fork_name,
@@ -1351,7 +1351,7 @@
         fixture.destroy_repo(fork_name)
 
     def test_api_fork_repo_non_admin(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         id_, params = _build_data(self.apikey_regular, 'fork_repo',
                                   repoid=self.REPO,
                                   fork_name=fork_name,
@@ -1369,7 +1369,7 @@
         fixture.destroy_repo(fork_name)
 
     def test_api_fork_repo_non_admin_specify_owner(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         id_, params = _build_data(self.apikey_regular, 'fork_repo',
                                   repoid=self.REPO,
                                   fork_name=fork_name,
@@ -1384,7 +1384,7 @@
         RepoModel().grant_user_permission(repo=self.REPO,
                                           user=self.TEST_USER_LOGIN,
                                           perm='repository.none')
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         id_, params = _build_data(self.apikey_regular, 'fork_repo',
                                   repoid=self.REPO,
                                   fork_name=fork_name,
@@ -1398,7 +1398,7 @@
                            ('write', 'repository.write'),
                            ('admin', 'repository.admin')])
     def test_api_fork_repo_non_admin_no_create_repo_permission(self, name, perm):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         # regardless of base repository permission, forking is disallowed
         # when repository creation is disabled
         RepoModel().grant_user_permission(repo=self.REPO,
@@ -1416,7 +1416,7 @@
         fixture.destroy_repo(fork_name)
 
     def test_api_fork_repo_unknown_owner(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         owner = 'i-dont-exist'
         id_, params = _build_data(self.apikey, 'fork_repo',
                                   repoid=self.REPO,
@@ -1428,11 +1428,11 @@
         self._compare_error(id_, expected, given=response.body)
 
     def test_api_fork_repo_fork_exists(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         fixture.create_fork(self.REPO, fork_name)
 
         try:
-            fork_name = 'api-repo-fork'
+            fork_name = u'api-repo-fork'
 
             id_, params = _build_data(self.apikey, 'fork_repo',
                                       repoid=self.REPO,
@@ -1461,7 +1461,7 @@
 
     @mock.patch.object(RepoModel, 'create_fork', crash)
     def test_api_fork_repo_exception_occurred(self):
-        fork_name = 'api-repo-fork'
+        fork_name = u'api-repo-fork'
         id_, params = _build_data(self.apikey, 'fork_repo',
                                   repoid=self.REPO,
                                   fork_name=fork_name,
@@ -1490,7 +1490,7 @@
         self._compare_ok(id_, expected, given=response.body)
 
     def test_api_get_user_groups(self):
-        gr_name = 'test_user_group2'
+        gr_name = u'test_user_group2'
         make_user_group(gr_name)
 
         id_, params = _build_data(self.apikey, 'get_user_groups', )
@@ -1498,7 +1498,7 @@
 
         try:
             expected = []
-            for gr_name in [TEST_USER_GROUP, 'test_user_group2']:
+            for gr_name in [TEST_USER_GROUP, u'test_user_group2']:
                 user_group = UserGroupModel().get_group(gr_name)
                 ret = user_group.get_api_data()
                 expected.append(ret)
@@ -1507,7 +1507,7 @@
             fixture.destroy_user_group(gr_name)
 
     def test_api_create_user_group(self):
-        group_name = 'some_new_group'
+        group_name = u'some_new_group'
         id_, params = _build_data(self.apikey, 'create_user_group',
                                   group_name=group_name)
         response = api_call(self, params)
@@ -1533,7 +1533,7 @@
 
     @mock.patch.object(UserGroupModel, 'create', crash)
     def test_api_get_user_group_exception_occurred(self):
-        group_name = 'exception_happens'
+        group_name = u'exception_happens'
         id_, params = _build_data(self.apikey, 'create_user_group',
                                   group_name=group_name)
         response = api_call(self, params)
@@ -1541,13 +1541,13 @@
         expected = 'failed to create group `%s`' % group_name
         self._compare_error(id_, expected, given=response.body)
 
-    @parameterized.expand([('group_name', {'group_name': 'new_group_name'}),
-                           ('group_name', {'group_name': 'test_group_for_update'}),
+    @parameterized.expand([('group_name', {'group_name': u'new_group_name'}),
+                           ('group_name', {'group_name': u'test_group_for_update'}),
                            ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
                            ('active', {'active': False}),
                            ('active', {'active': True})])
     def test_api_update_user_group(self, changing_attr, updates):
-        gr_name = 'test_group_for_update'
+        gr_name = u'test_group_for_update'
         user_group = fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'update_user_group',
                                   usergroupid=gr_name, **updates)
@@ -1567,7 +1567,7 @@
 
     @mock.patch.object(UserGroupModel, 'update', crash)
     def test_api_update_user_group_exception_occurred(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'update_user_group',
                                   usergroupid=gr_name)
@@ -1579,7 +1579,7 @@
             fixture.destroy_user_group(gr_name)
 
     def test_api_add_user_to_user_group(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'add_user_to_user_group',
                                   usergroupid=gr_name,
@@ -1606,7 +1606,7 @@
 
     @mock.patch.object(UserGroupModel, 'add_user_to_group', crash)
     def test_api_add_user_to_user_group_exception_occurred(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         fixture.create_user_group(gr_name)
         id_, params = _build_data(self.apikey, 'add_user_to_user_group',
                                   usergroupid=gr_name,
@@ -1620,7 +1620,7 @@
             fixture.destroy_user_group(gr_name)
 
     def test_api_remove_user_from_user_group(self):
-        gr_name = 'test_group_3'
+        gr_name = u'test_group_3'
         gr = fixture.create_user_group(gr_name)
         UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
         Session().commit()
@@ -1641,7 +1641,7 @@
 
     @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash)
     def test_api_remove_user_from_user_group_exception_occurred(self):
-        gr_name = 'test_group_3'
+        gr_name = u'test_group_3'
         gr = fixture.create_user_group(gr_name)
         UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
         Session().commit()
@@ -1656,7 +1656,7 @@
             fixture.destroy_user_group(gr_name)
 
     def test_api_delete_user_group(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         ugroup = fixture.create_user_group(gr_name)
         gr_id = ugroup.users_group_id
         id_, params = _build_data(self.apikey, 'delete_user_group',
@@ -1675,7 +1675,7 @@
                 fixture.destroy_user_group(gr_name)
 
     def test_api_delete_user_group_that_is_assigned(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         ugroup = fixture.create_user_group(gr_name)
         gr_id = ugroup.users_group_id
 
@@ -1695,7 +1695,7 @@
                 fixture.destroy_user_group(gr_name)
 
     def test_api_delete_user_group_exception_occurred(self):
-        gr_name = 'test_group'
+        gr_name = u'test_group'
         ugroup = fixture.create_user_group(gr_name)
         gr_id = ugroup.users_group_id
         id_, params = _build_data(self.apikey, 'delete_user_group',
--- a/kallithea/tests/fixture.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/fixture.py	Wed Jan 20 01:41:02 2016 +0100
@@ -76,7 +76,7 @@
             repo_type='hg',
             clone_uri='',
             repo_group=u'-1',
-            repo_description='DESC',
+            repo_description=u'DESC',
             repo_private=False,
             repo_landing_rev='rev:tip',
             repo_copy_permissions=False,
@@ -95,7 +95,7 @@
     def _get_group_create_params(self, **custom):
         defs = dict(
             group_name=None,
-            group_description='DESC',
+            group_description=u'DESC',
             group_parent_id=None,
             perms_updates=[],
             perms_new=[],
@@ -111,8 +111,8 @@
             username=name,
             password='qweqwe',
             email='%s+test@example.com' % name,
-            firstname='TestUser',
-            lastname='Test',
+            firstname=u'TestUser',
+            lastname=u'Test',
             active=True,
             admin=False,
             extern_type='internal',
@@ -125,7 +125,7 @@
     def _get_user_group_create_params(self, name, **custom):
         defs = dict(
             users_group_name=name,
-            user_group_description='DESC',
+            user_group_description=u'DESC',
             users_group_active=True,
             user_group_data={},
         )
--- a/kallithea/tests/functional/test_admin_auth_settings.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_admin_auth_settings.py	Wed Jan 20 01:41:02 2016 +0100
@@ -135,6 +135,9 @@
     def test_container_auth_login_header(self):
         self._container_auth_setup(
             auth_container_header='THE_USER_NAME',
+            auth_container_email_header='',
+            auth_container_firstname_header='',
+            auth_container_lastname_header='',
             auth_container_fallback_header='',
             auth_container_clean_username='False',
         )
@@ -143,9 +146,34 @@
             resulting_username='john@example.org',
         )
 
+    def test_container_auth_login_header_attr(self):
+        self._container_auth_setup(
+            auth_container_header='THE_USER_NAME',
+            auth_container_email_header='THE_USER_EMAIL',
+            auth_container_firstname_header='THE_USER_FIRSTNAME',
+            auth_container_lastname_header='THE_USER_LASTNAME',
+            auth_container_fallback_header='',
+            auth_container_clean_username='False',
+        )
+        response = self.app.get(
+            url=url(controller='admin/my_account', action='my_account'),
+            extra_environ={'THE_USER_NAME': 'johnd',
+                           'THE_USER_EMAIL': 'john@example.org',
+                           'THE_USER_FIRSTNAME': 'John',
+                           'THE_USER_LASTNAME': 'Doe',
+                           }
+        )
+        self.assertEqual(response.form['email'].value, 'john@example.org')
+        self.assertEqual(response.form['firstname'].value, 'John')
+        self.assertEqual(response.form['lastname'].value, 'Doe')
+
+
     def test_container_auth_login_fallback_header(self):
         self._container_auth_setup(
             auth_container_header='THE_USER_NAME',
+            auth_container_email_header='',
+            auth_container_firstname_header='',
+            auth_container_lastname_header='',
             auth_container_fallback_header='HTTP_X_YZZY',
             auth_container_clean_username='False',
         )
@@ -157,6 +185,9 @@
     def test_container_auth_clean_username_at(self):
         self._container_auth_setup(
             auth_container_header='REMOTE_USER',
+            auth_container_email_header='',
+            auth_container_firstname_header='',
+            auth_container_lastname_header='',
             auth_container_fallback_header='',
             auth_container_clean_username='True',
         )
@@ -168,6 +199,9 @@
     def test_container_auth_clean_username_backslash(self):
         self._container_auth_setup(
             auth_container_header='REMOTE_USER',
+            auth_container_email_header='',
+            auth_container_firstname_header='',
+            auth_container_lastname_header='',
             auth_container_fallback_header='',
             auth_container_clean_username='True',
         )
@@ -179,6 +213,9 @@
     def test_container_auth_no_logout(self):
         self._container_auth_setup(
             auth_container_header='REMOTE_USER',
+            auth_container_email_header='',
+            auth_container_firstname_header='',
+            auth_container_lastname_header='',
             auth_container_fallback_header='',
             auth_container_clean_username='True',
         )
--- a/kallithea/tests/functional/test_admin_notifications.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_admin_notifications.py	Wed Jan 20 01:41:02 2016 +0100
@@ -16,7 +16,7 @@
 
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                           email='u1@example.com',
-                                          firstname='u1', lastname='u1')
+                                          firstname=u'u1', lastname=u'u1')
         u1 = u1.user_id
 
         response = self.app.get(url('notifications'))
@@ -35,10 +35,10 @@
 
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                                email='u1@example.com',
-                                               firstname='u1', lastname='u1')
+                                               firstname=u'u1', lastname=u'u1')
         u2 = UserModel().create_or_update(username='u2', password='qweqwe',
                                                email='u2@example.com',
-                                               firstname='u2', lastname='u2')
+                                               firstname=u'u2', lastname=u'u2')
 
         # make notifications
         notification = NotificationModel().create(created_by=cur_user,
@@ -69,10 +69,10 @@
         cur_user = self._get_logged_user()
         u1 = UserModel().create_or_update(username='u1', password='qweqwe',
                                           email='u1@example.com',
-                                          firstname='u1', lastname='u1')
+                                          firstname=u'u1', lastname=u'u1')
         u2 = UserModel().create_or_update(username='u2', password='qweqwe',
                                           email='u2@example.com',
-                                          firstname='u2', lastname='u2')
+                                          firstname=u'u2', lastname=u'u2')
 
         subject = u'test'
         notif_body = u'hi there'
--- a/kallithea/tests/functional/test_admin_repos.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_admin_repos.py	Wed Jan 20 01:41:02 2016 +0100
@@ -5,7 +5,8 @@
 import urllib
 
 from kallithea.lib import vcs
-from kallithea.model.db import Repository, RepoGroup, UserRepoToPerm, User,\
+from kallithea.lib.utils2 import safe_str, safe_unicode
+from kallithea.model.db import Repository, RepoGroup, UserRepoToPerm, User, \
     Permission
 from kallithea.model.user import UserModel
 from kallithea.tests import *
@@ -18,10 +19,10 @@
 
 
 def _get_permission_for_user(user, repo):
-    perm = UserRepoToPerm.query()\
+    perm = UserRepoToPerm.query() \
                 .filter(UserRepoToPerm.repository ==
-                        Repository.get_by_repo_name(repo))\
-                .filter(UserRepoToPerm.user == User.get_by_username(user))\
+                        Repository.get_by_repo_name(repo)) \
+                .filter(UserRepoToPerm.user == User.get_by_username(user)) \
                 .all()
     return perm
 
@@ -51,7 +52,7 @@
     def test_create(self):
         self.log_user()
         repo_name = self.NEW_REPO
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -66,7 +67,7 @@
                                % (repo_name, repo_name))
 
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -79,63 +80,26 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name)))
         except vcs.exceptions.VCSError:
             self.fail('no repo %s in filesystem' % repo_name)
 
         RepoModel().delete(repo_name)
         Session().commit()
 
-    def test_create_non_ascii(self):
-        self.log_user()
-        non_ascii = "ąęł"
-        repo_name = "%s%s" % (self.NEW_REPO, non_ascii)
-        repo_name_unicode = repo_name.decode('utf8')
-        description = 'description for newly created repo' + non_ascii
-        description_unicode = description.decode('utf8')
-        response = self.app.post(url('repos'),
-                        fixture._get_repo_create_params(repo_private=False,
-                                                repo_name=repo_name,
-                                                repo_type=self.REPO_TYPE,
-                                                repo_description=description,
-                                                _authentication_token=self.authentication_token()))
-        ## run the check page that triggers the flash message
-        response = self.app.get(url('repo_check_home', repo_name=repo_name))
-        self.assertEqual(response.json, {u'result': True})
-        self.checkSessionFlash(response,
-                               u'Created repository <a href="/%s">%s</a>'
-                               % (urllib.quote(repo_name), repo_name_unicode))
-        # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
-            .filter(Repository.repo_name == repo_name_unicode).one()
-
-        self.assertEqual(new_repo.repo_name, repo_name_unicode)
-        self.assertEqual(new_repo.description, description_unicode)
-
-        # test if the repository is visible in the list ?
-        response = self.app.get(url('summary_home', repo_name=repo_name))
-        response.mustcontain(repo_name)
-        response.mustcontain(self.REPO_TYPE)
-
-        # test if the repository was created on filesystem
-        try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
-        except vcs.exceptions.VCSError:
-            self.fail('no repo %s in filesystem' % repo_name)
-
     def test_create_in_group(self):
         self.log_user()
 
         ## create GROUP
-        group_name = 'sometest_%s' % self.REPO_TYPE
+        group_name = u'sometest_%s' % self.REPO_TYPE
         gr = RepoGroupModel().create(group_name=group_name,
-                                     group_description='test',
+                                     group_description=u'test',
                                      owner=TEST_USER_ADMIN_LOGIN)
         Session().commit()
 
-        repo_name = 'ingroup'
+        repo_name = u'ingroup'
         repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -150,7 +114,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
@@ -162,13 +126,13 @@
         response.mustcontain(repo_name_full)
         response.mustcontain(self.REPO_TYPE)
 
-        inherited_perms = UserRepoToPerm.query()\
+        inherited_perms = UserRepoToPerm.query() \
             .filter(UserRepoToPerm.repository_id == new_repo_id).all()
         self.assertEqual(len(inherited_perms), 1)
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name_full))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name_full)))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             Session().commit()
@@ -198,21 +162,21 @@
         Session().commit()
 
         ## create GROUP
-        group_name = 'reg_sometest_%s' % self.REPO_TYPE
+        group_name = u'reg_sometest_%s' % self.REPO_TYPE
         gr = RepoGroupModel().create(group_name=group_name,
-                                     group_description='test',
+                                     group_description=u'test',
                                      owner=TEST_USER_ADMIN_LOGIN)
         Session().commit()
 
-        group_name_allowed = 'reg_sometest_allowed_%s' % self.REPO_TYPE
+        group_name_allowed = u'reg_sometest_allowed_%s' % self.REPO_TYPE
         gr_allowed = RepoGroupModel().create(group_name=group_name_allowed,
-                                     group_description='test',
+                                     group_description=u'test',
                                      owner=TEST_USER_REGULAR_LOGIN)
         Session().commit()
 
-        repo_name = 'ingroup'
+        repo_name = u'ingroup'
         repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -224,9 +188,9 @@
         response.mustcontain('Invalid value')
 
         # user is allowed to create in this group
-        repo_name = 'ingroup'
+        repo_name = u'ingroup'
         repo_name_full = RepoGroup.url_sep().join([group_name_allowed, repo_name])
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -242,7 +206,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
@@ -254,13 +218,13 @@
         response.mustcontain(repo_name_full)
         response.mustcontain(self.REPO_TYPE)
 
-        inherited_perms = UserRepoToPerm.query()\
+        inherited_perms = UserRepoToPerm.query() \
             .filter(UserRepoToPerm.repository_id == new_repo_id).all()
         self.assertEqual(len(inherited_perms), 1)
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name_full))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name_full)))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             Session().commit()
@@ -275,9 +239,9 @@
         self.log_user()
 
         ## create GROUP
-        group_name = 'sometest_%s' % self.REPO_TYPE
+        group_name = u'sometest_%s' % self.REPO_TYPE
         gr = RepoGroupModel().create(group_name=group_name,
-                                     group_description='test',
+                                     group_description=u'test',
                                      owner=TEST_USER_ADMIN_LOGIN)
         perm = Permission.get_by_key('repository.write')
         RepoGroupModel().grant_user_permission(gr, TEST_USER_REGULAR_LOGIN, perm)
@@ -285,9 +249,9 @@
         ## add repo permissions
         Session().commit()
 
-        repo_name = 'ingroup_inherited_%s' % self.REPO_TYPE
+        repo_name = u'ingroup_inherited_%s' % self.REPO_TYPE
         repo_name_full = RepoGroup.url_sep().join([group_name, repo_name])
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -303,7 +267,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name_full, repo_name_full))
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name_full).one()
         new_repo_id = new_repo.repo_id
 
@@ -317,14 +281,14 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name_full))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name_full)))
         except vcs.exceptions.VCSError:
             RepoGroupModel().delete(group_name)
             Session().commit()
             self.fail('no repo %s in filesystem' % repo_name)
 
         #check if inherited permissiona are applied
-        inherited_perms = UserRepoToPerm.query()\
+        inherited_perms = UserRepoToPerm.query() \
             .filter(UserRepoToPerm.repository_id == new_repo_id).all()
         self.assertEqual(len(inherited_perms), 2)
 
@@ -340,7 +304,7 @@
     def test_create_remote_repo_wrong_clone_uri(self):
         self.log_user()
         repo_name = self.NEW_REPO
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -354,7 +318,7 @@
     def test_create_remote_repo_wrong_clone_uri_hg_svn(self):
         self.log_user()
         repo_name = self.NEW_REPO
-        description = 'description for newly created repo'
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -367,8 +331,8 @@
 
     def test_delete(self):
         self.log_user()
-        repo_name = 'vcs_test_new_to_delete_%s' % self.REPO_TYPE
-        description = 'description for newly created repo'
+        repo_name = u'vcs_test_new_to_delete_%s' % self.REPO_TYPE
+        description = u'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_type=self.REPO_TYPE,
@@ -381,7 +345,7 @@
                                'Created repository <a href="/%s">%s</a>'
                                % (repo_name, repo_name))
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name).one()
 
         self.assertEqual(new_repo.repo_name, repo_name)
@@ -394,7 +358,7 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name)))
         except vcs.exceptions.VCSError:
             self.fail('no repo %s in filesystem' % repo_name)
 
@@ -406,7 +370,7 @@
         response.follow()
 
         #check if repo was deleted from db
-        deleted_repo = Session().query(Repository)\
+        deleted_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name).scalar()
 
         self.assertEqual(deleted_repo, None)
@@ -417,10 +381,10 @@
     def test_delete_non_ascii(self):
         self.log_user()
         non_ascii = "ąęł"
-        repo_name = "%s%s" % (self.NEW_REPO, non_ascii)
-        repo_name_unicode = repo_name.decode('utf8')
+        repo_name = "%s%s" % (safe_str(self.NEW_REPO), non_ascii)
+        repo_name_unicode = safe_unicode(repo_name)
         description = 'description for newly created repo' + non_ascii
-        description_unicode = description.decode('utf8')
+        description_unicode = safe_unicode(description)
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
                                                 repo_name=repo_name,
@@ -434,7 +398,7 @@
                                u'Created repository <a href="/%s">%s</a>'
                                % (urllib.quote(repo_name), repo_name_unicode))
         # test if the repo was created in the database
-        new_repo = Session().query(Repository)\
+        new_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name_unicode).one()
 
         self.assertEqual(new_repo.repo_name, repo_name_unicode)
@@ -447,7 +411,7 @@
 
         # test if the repository was created on filesystem
         try:
-            vcs.get_repo(os.path.join(TESTS_TMP_PATH, repo_name))
+            vcs.get_repo(safe_str(os.path.join(TESTS_TMP_PATH, repo_name)))
         except vcs.exceptions.VCSError:
             self.fail('no repo %s in filesystem' % repo_name)
 
@@ -457,7 +421,7 @@
         response.follow()
 
         #check if repo was deleted from db
-        deleted_repo = Session().query(Repository)\
+        deleted_repo = Session().query(Repository) \
             .filter(Repository.repo_name == repo_name_unicode).scalar()
 
         self.assertEqual(deleted_repo, None)
@@ -532,7 +496,7 @@
 
     def test_set_fork_of_other_repo(self):
         self.log_user()
-        other_repo = 'other_%s' % self.REPO_TYPE
+        other_repo = u'other_%s' % self.REPO_TYPE
         fixture.create_repo(other_repo, repo_type=self.REPO_TYPE)
         repo = Repository.get_by_repo_name(self.REPO)
         repo2 = Repository.get_by_repo_name(other_repo)
@@ -604,7 +568,7 @@
 
         user = User.get(usr['user_id'])
 
-        repo_name = self.NEW_REPO+'no_perms'
+        repo_name = self.NEW_REPO + u'no_perms'
         description = 'description for newly created repo'
         response = self.app.post(url('repos'),
                         fixture._get_repo_create_params(repo_private=False,
--- a/kallithea/tests/functional/test_admin_user_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_admin_user_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -3,7 +3,7 @@
 from kallithea.model.db import UserGroup, UserGroupToPerm, Permission
 from kallithea.model.meta import Session
 
-TEST_USER_GROUP = 'admins_test'
+TEST_USER_GROUP = u'admins_test'
 
 
 class TestAdminUsersGroupsController(TestController):
@@ -18,7 +18,7 @@
         users_group_name = TEST_USER_GROUP
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
-                                  'user_group_description': 'DESC',
+                                  'user_group_description': u'DESC',
                                   'active': True,
                                   '_authentication_token': self.authentication_token()})
         response.follow()
@@ -43,7 +43,7 @@
         users_group_name = TEST_USER_GROUP + 'another'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name':users_group_name,
-                                  'user_group_description': 'DESC',
+                                  'user_group_description': u'DESC',
                                   'active': True,
                                   '_authentication_token': self.authentication_token()})
         response.follow()
@@ -51,13 +51,13 @@
         self.checkSessionFlash(response,
                                'Created user group ')
 
-        gr = Session().query(UserGroup)\
+        gr = Session().query(UserGroup) \
             .filter(UserGroup.users_group_name == users_group_name).one()
 
         response = self.app.post(url('users_group', id=gr.users_group_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
 
-        gr = Session().query(UserGroup)\
+        gr = Session().query(UserGroup) \
             .filter(UserGroup.users_group_name == users_group_name).scalar()
 
         self.assertEqual(gr, None)
@@ -67,7 +67,7 @@
         users_group_name = TEST_USER_GROUP + 'another2'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
-                                  'user_group_description': 'DESC',
+                                  'user_group_description': u'DESC',
                                   'active': True,
                                   '_authentication_token': self.authentication_token()})
         response.follow()
@@ -87,7 +87,7 @@
         p3 = Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
@@ -109,7 +109,7 @@
 
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
@@ -124,12 +124,12 @@
         response = self.app.post(url('users_group', id=ug.users_group_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
         response = response.follow()
-        gr = Session().query(UserGroup)\
+        gr = Session().query(UserGroup) \
             .filter(UserGroup.users_group_name == users_group_name).scalar()
 
         self.assertEqual(gr, None)
         p = Permission.get_by_key('hg.create.repository')
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
@@ -140,7 +140,7 @@
         users_group_name = TEST_USER_GROUP + 'another2'
         response = self.app.post(url('users_groups'),
                                  {'users_group_name': users_group_name,
-                                  'user_group_description': 'DESC',
+                                  'user_group_description': u'DESC',
                                   'active': True,
                                   '_authentication_token': self.authentication_token()})
         response.follow()
@@ -160,7 +160,7 @@
         p3 = Permission.get_by_key('hg.fork.repository')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
@@ -180,7 +180,7 @@
         p3 = Permission.get_by_key('hg.fork.none')
         # check if user has this perms, they should be here since
         # defaults are on
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group == ug).all()
 
         self.assertEqual(
@@ -195,13 +195,13 @@
         response = self.app.post(url('users_group', id=ug.users_group_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
         response = response.follow()
-        gr = Session().query(UserGroup)\
+        gr = Session().query(UserGroup) \
                            .filter(UserGroup.users_group_name ==
                                    users_group_name).scalar()
 
         self.assertEqual(gr, None)
         p = Permission.get_by_key('hg.fork.repository')
-        perms = UserGroupToPerm.query()\
+        perms = UserGroupToPerm.query() \
             .filter(UserGroupToPerm.users_group_id == ugid).all()
         perms = [[x.users_group_id,
                   x.permission_id, ] for x in perms]
--- a/kallithea/tests/functional/test_admin_users.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_admin_users.py	Wed Jan 20 01:41:02 2016 +0100
@@ -45,8 +45,8 @@
         username = 'newtestuser'
         password = 'test12'
         password_confirmation = password
-        name = 'name'
-        lastname = 'lastname'
+        name = u'name'
+        lastname = u'lastname'
         email = 'mail@example.com'
 
         response = self.app.post(url('users'),
@@ -64,7 +64,7 @@
         self.checkSessionFlash(response, '''Created user <a href="/_admin/users/''')
         self.checkSessionFlash(response, '''/edit">%s</a>''' % (username))
 
-        new_user = Session().query(User).\
+        new_user = Session().query(User). \
             filter(User.username == username).one()
 
         self.assertEqual(new_user.username, username)
@@ -81,8 +81,8 @@
         self.log_user()
         username = 'new_user'
         password = ''
-        name = 'name'
-        lastname = 'lastname'
+        name = u'name'
+        lastname = u'lastname'
         email = 'errmail.example.com'
 
         response = self.app.post(url('users'), {'username': username,
@@ -165,7 +165,7 @@
 
         fixture.create_user(name=username)
 
-        new_user = Session().query(User)\
+        new_user = Session().query(User) \
             .filter(User.username == username).one()
         response = self.app.post(url('user', id=new_user.user_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
@@ -175,12 +175,12 @@
     def test_delete_repo_err(self):
         self.log_user()
         username = 'repoerr'
-        reponame = 'repoerr_fail'
+        reponame = u'repoerr_fail'
 
         fixture.create_user(name=username)
         fixture.create_repo(name=reponame, cur_user=username)
 
-        new_user = Session().query(User)\
+        new_user = Session().query(User) \
             .filter(User.username == username).one()
         response = self.app.post(url('user', id=new_user.user_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
@@ -200,12 +200,12 @@
     def test_delete_repo_group_err(self):
         self.log_user()
         username = 'repogrouperr'
-        groupname = 'repogroup_fail'
+        groupname = u'repogroup_fail'
 
         fixture.create_user(name=username)
         fixture.create_repo_group(name=groupname, cur_user=username)
 
-        new_user = Session().query(User)\
+        new_user = Session().query(User) \
             .filter(User.username == username).one()
         response = self.app.post(url('user', id=new_user.user_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
@@ -229,12 +229,12 @@
     def test_delete_user_group_err(self):
         self.log_user()
         username = 'usergrouperr'
-        groupname = 'usergroup_fail'
+        groupname = u'usergroup_fail'
 
         fixture.create_user(name=username)
         ug = fixture.create_user_group(name=groupname, cur_user=username)
 
-        new_user = Session().query(User)\
+        new_user = Session().query(User) \
             .filter(User.username == username).one()
         response = self.app.post(url('user', id=new_user.user_id),
             params={'_method': 'delete', '_authentication_token': self.authentication_token()})
@@ -267,8 +267,8 @@
         perm_create = Permission.get_by_key('hg.create.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
-                                            email='dummy', firstname='a',
-                                            lastname='b')
+                                            email='dummy', firstname=u'a',
+                                            lastname=u'b')
         Session().commit()
         uid = user.user_id
 
@@ -298,8 +298,8 @@
         perm_create = Permission.get_by_key('hg.create.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
-                                            email='dummy', firstname='a',
-                                            lastname='b')
+                                            email='dummy', firstname=u'a',
+                                            lastname=u'b')
         Session().commit()
         uid = user.user_id
 
@@ -327,8 +327,8 @@
         perm_fork = Permission.get_by_key('hg.fork.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
-                                            email='dummy', firstname='a',
-                                            lastname='b')
+                                            email='dummy', firstname=u'a',
+                                            lastname=u'b')
         Session().commit()
         uid = user.user_id
 
@@ -358,8 +358,8 @@
         perm_fork = Permission.get_by_key('hg.fork.repository')
 
         user = UserModel().create_or_update(username='dummy', password='qwe',
-                                            email='dummy', firstname='a',
-                                            lastname='b')
+                                            email='dummy', firstname=u'a',
+                                            lastname=u'b')
         Session().commit()
         uid = user.user_id
 
--- a/kallithea/tests/functional/test_compare.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_compare.py	Wed Jan 20 01:41:02 2016 +0100
@@ -26,7 +26,7 @@
 
     def test_compare_forks_on_branch_extra_commits_hg(self):
         self.log_user()
-        repo1 = fixture.create_repo('one', repo_type='hg',
+        repo1 = fixture.create_repo(u'one', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
         self.r1_id = repo1.repo_id
@@ -36,7 +36,7 @@
                 parent=None, newfile=True)
 
         #fork this repo
-        repo2 = fixture.create_fork('one', 'one-fork')
+        repo2 = fixture.create_fork(u'one', u'one-fork')
         self.r2_id = repo2.repo_id
 
         #add two extra commit into fork
@@ -77,7 +77,7 @@
 
     def test_compare_forks_on_branch_extra_commits_git(self):
         self.log_user()
-        repo1 = fixture.create_repo('one-git', repo_type='git',
+        repo1 = fixture.create_repo(u'one-git', repo_type='git',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
         self.r1_id = repo1.repo_id
@@ -87,7 +87,7 @@
                 parent=None, newfile=True)
 
         #fork this repo
-        repo2 = fixture.create_fork('one-git', 'one-git-fork')
+        repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
         self.r2_id = repo2.repo_id
 
         #add two extra commit into fork
@@ -129,7 +129,7 @@
     def test_compare_forks_on_branch_extra_commits_origin_has_incomming_hg(self):
         self.log_user()
 
-        repo1 = fixture.create_repo('one', repo_type='hg',
+        repo1 = fixture.create_repo(u'one', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
 
@@ -141,7 +141,7 @@
                 parent=None, newfile=True)
 
         #fork this repo
-        repo2 = fixture.create_fork('one', 'one-fork')
+        repo2 = fixture.create_fork(u'one', u'one-fork')
         self.r2_id = repo2.repo_id
 
         #now commit something to origin repo
@@ -188,7 +188,7 @@
     def test_compare_forks_on_branch_extra_commits_origin_has_incomming_git(self):
         self.log_user()
 
-        repo1 = fixture.create_repo('one-git', repo_type='git',
+        repo1 = fixture.create_repo(u'one-git', repo_type='git',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
 
@@ -200,7 +200,7 @@
                 parent=None, newfile=True)
 
         #fork this repo
-        repo2 = fixture.create_fork('one-git', 'one-git-fork')
+        repo2 = fixture.create_fork(u'one-git', u'one-git-fork')
         self.r2_id = repo2.repo_id
 
         #now commit something to origin repo
@@ -259,7 +259,7 @@
         #make repo1, and cs1+cs2
         self.log_user()
 
-        repo1 = fixture.create_repo('repo1', repo_type='hg',
+        repo1 = fixture.create_repo(u'repo1', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
         self.r1_id = repo1.repo_id
@@ -272,7 +272,7 @@
                 content='line1\nline2\n', message='commit2', vcs_type='hg',
                 parent=cs0)
         #fork this repo
-        repo2 = fixture.create_fork('repo1', 'repo1-fork')
+        repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
         self.r2_id = repo2.repo_id
         #now make cs3-6
         cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
@@ -326,7 +326,7 @@
 #
         #make repo1, and cs1+cs2
         self.log_user()
-        repo1 = fixture.create_repo('repo1', repo_type='hg',
+        repo1 = fixture.create_repo(u'repo1', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
         self.r1_id = repo1.repo_id
@@ -339,7 +339,7 @@
                 content='line1\nline2\n', message='commit2', vcs_type='hg',
                 parent=cs0)
         #fork this repo
-        repo2 = fixture.create_fork('repo1', 'repo1-fork')
+        repo2 = fixture.create_fork(u'repo1', u'repo1-fork')
         self.r2_id = repo2.repo_id
         #now make cs3-6
         cs2 = fixture.commit_change(repo1.repo_name, filename='file1',
@@ -445,7 +445,7 @@
     def test_org_repo_new_commits_after_forking_simple_diff_hg(self):
         self.log_user()
 
-        repo1 = fixture.create_repo('one', repo_type='hg',
+        repo1 = fixture.create_repo(u'one', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
 
@@ -457,7 +457,7 @@
         Session().commit()
         self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
         #fork the repo1
-        repo2 = fixture.create_repo('one-fork', repo_type='hg',
+        repo2 = fixture.create_repo(u'one-fork', repo_type='hg',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN,
                                     clone_uri=repo1.repo_full_path,
@@ -524,7 +524,7 @@
     def test_org_repo_new_commits_after_forking_simple_diff_git(self):
         self.log_user()
 
-        repo1 = fixture.create_repo('one-git', repo_type='git',
+        repo1 = fixture.create_repo(u'one-git', repo_type='git',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN)
 
@@ -537,7 +537,7 @@
         Session().commit()
         self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
         #fork the repo1
-        repo2 = fixture.create_repo('one-git-fork', repo_type='git',
+        repo2 = fixture.create_repo(u'one-git-fork', repo_type='git',
                                     repo_description='diff-test',
                                     cur_user=TEST_USER_ADMIN_LOGIN,
                                     clone_uri=repo1.repo_full_path,
--- a/kallithea/tests/functional/test_files.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_files.py	Wed Jan 20 01:41:02 2016 +0100
@@ -374,7 +374,7 @@
     ])
     def test_add_file_into_hg(self, cnt, location, filename):
         self.log_user()
-        repo = fixture.create_repo('commit-test-%s' % cnt, repo_type='hg')
+        repo = fixture.create_repo(u'commit-test-%s' % cnt, repo_type='hg')
         response = self.app.post(url('files_add_home',
                                       repo_name=repo.repo_name,
                                       revision='tip', f_path='/'),
@@ -450,7 +450,7 @@
     ])
     def test_add_file_into_git(self, cnt, location, filename):
         self.log_user()
-        repo = fixture.create_repo('commit-test-%s' % cnt, repo_type='git')
+        repo = fixture.create_repo(u'commit-test-%s' % cnt, repo_type='git')
         response = self.app.post(url('files_add_home',
                                       repo_name=repo.repo_name,
                                       revision='tip', f_path='/'),
@@ -476,7 +476,7 @@
 
     def test_edit_file_view_not_on_branch_hg(self):
         self.log_user()
-        repo = fixture.create_repo('test-edit-repo', repo_type='hg')
+        repo = fixture.create_repo(u'test-edit-repo', repo_type='hg')
 
         ## add file
         location = 'vcs'
@@ -506,7 +506,7 @@
 
     def test_edit_file_view_commit_changes_hg(self):
         self.log_user()
-        repo = fixture.create_repo('test-edit-repo', repo_type='hg')
+        repo = fixture.create_repo(u'test-edit-repo', repo_type='hg')
 
         ## add file
         location = 'vcs'
@@ -550,7 +550,7 @@
 
     def test_edit_file_view_not_on_branch_git(self):
         self.log_user()
-        repo = fixture.create_repo('test-edit-repo', repo_type='git')
+        repo = fixture.create_repo(u'test-edit-repo', repo_type='git')
 
         ## add file
         location = 'vcs'
@@ -580,7 +580,7 @@
 
     def test_edit_file_view_commit_changes_git(self):
         self.log_user()
-        repo = fixture.create_repo('test-edit-repo', repo_type='git')
+        repo = fixture.create_repo(u'test-edit-repo', repo_type='git')
 
         ## add file
         location = 'vcs'
@@ -624,7 +624,7 @@
 
     def test_delete_file_view_not_on_branch_hg(self):
         self.log_user()
-        repo = fixture.create_repo('test-delete-repo', repo_type='hg')
+        repo = fixture.create_repo(u'test-delete-repo', repo_type='hg')
 
         ## add file
         location = 'vcs'
@@ -654,7 +654,7 @@
 
     def test_delete_file_view_commit_changes_hg(self):
         self.log_user()
-        repo = fixture.create_repo('test-delete-repo', repo_type='hg')
+        repo = fixture.create_repo(u'test-delete-repo', repo_type='hg')
 
         ## add file
         location = 'vcs'
@@ -697,7 +697,7 @@
 
     def test_delete_file_view_not_on_branch_git(self):
         self.log_user()
-        repo = fixture.create_repo('test-delete-repo', repo_type='git')
+        repo = fixture.create_repo(u'test-delete-repo', repo_type='git')
 
         ## add file
         location = 'vcs'
@@ -727,7 +727,7 @@
 
     def test_delete_file_view_commit_changes_git(self):
         self.log_user()
-        repo = fixture.create_repo('test-delete-repo', repo_type='git')
+        repo = fixture.create_repo(u'test-delete-repo', repo_type='git')
 
         ## add file
         location = 'vcs'
--- a/kallithea/tests/functional/test_forks.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_forks.py	Wed Jan 20 01:41:02 2016 +0100
@@ -101,7 +101,7 @@
 
     def test_fork_create_into_group(self):
         self.log_user()
-        group = fixture.create_repo_group('vc')
+        group = fixture.create_repo_group(u'vc')
         group_id = group.group_id
         fork_name = self.REPO_FORK
         fork_name_full = 'vc/%s' % fork_name
@@ -130,7 +130,7 @@
                 % (repo_name, fork_name_full, fork_name_full))
 
         #test if the fork was created in the database
-        fork_repo = Session().query(Repository)\
+        fork_repo = Session().query(Repository) \
             .filter(Repository.repo_name == fork_name_full).one()
 
         self.assertEqual(fork_repo.repo_name, fork_name_full)
@@ -173,7 +173,7 @@
                 % (repo_name, fork_name, fork_name))
 
         #test if the fork was created in the database
-        fork_repo = Session().query(Repository)\
+        fork_repo = Session().query(Repository) \
             .filter(Repository.repo_name == fork_name).one()
 
         self.assertEqual(fork_repo.repo_name, fork_name)
@@ -189,8 +189,8 @@
         usr = self.log_user(self.username, self.password)['user_id']
         repo_name = self.REPO
 
-        forks = Repository.query()\
-            .filter(Repository.repo_type == self.REPO_TYPE)\
+        forks = Repository.query() \
+            .filter(Repository.repo_type == self.REPO_TYPE) \
             .filter(Repository.fork_id != None).all()
         self.assertEqual(1, len(forks))
 
@@ -209,8 +209,8 @@
         usr = self.log_user(self.username, self.password)['user_id']
         repo_name = self.REPO
 
-        forks = Repository.query()\
-            .filter(Repository.repo_type == self.REPO_TYPE)\
+        forks = Repository.query() \
+            .filter(Repository.repo_type == self.REPO_TYPE) \
             .filter(Repository.fork_id != None).all()
         self.assertEqual(1, len(forks))
 
--- a/kallithea/tests/functional/test_home.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_home.py	Wed Jan 20 01:41:02 2016 +0100
@@ -44,13 +44,13 @@
 
     def test_index_page_on_groups(self):
         self.log_user()
-        gr = fixture.create_repo_group('gr1')
-        fixture.create_repo(name='gr1/repo_in_group', repo_group=gr)
-        response = self.app.get(url('repos_group_home', group_name='gr1'))
+        gr = fixture.create_repo_group(u'gr1')
+        fixture.create_repo(name=u'gr1/repo_in_group', repo_group=gr)
+        response = self.app.get(url('repos_group_home', group_name=u'gr1'))
 
         try:
-            response.mustcontain("gr1/repo_in_group")
+            response.mustcontain(u"gr1/repo_in_group")
         finally:
-            RepoModel().delete('gr1/repo_in_group')
-            RepoGroupModel().delete(repo_group='gr1', force_delete=True)
+            RepoModel().delete(u'gr1/repo_in_group')
+            RepoGroupModel().delete(repo_group=u'gr1', force_delete=True)
             Session().commit()
--- a/kallithea/tests/functional/test_journal.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_journal.py	Wed Jan 20 01:41:02 2016 +0100
@@ -15,8 +15,8 @@
 #        usr = Session().query(User).filter(User.username == TEST_USER_ADMIN_LOGIN).one()
 #        repo = Session().query(Repository).filter(Repository.repo_name == HG_REPO).one()
 #
-#        followings = Session().query(UserFollowing)\
-#            .filter(UserFollowing.user == usr)\
+#        followings = Session().query(UserFollowing) \
+#            .filter(UserFollowing.user == usr) \
 #            .filter(UserFollowing.follows_repository == repo).all()
 #
 #        assert len(followings) == 1, 'Not following any repository'
--- a/kallithea/tests/functional/test_login.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_login.py	Wed Jan 20 01:41:02 2016 +0100
@@ -350,8 +350,8 @@
         username = 'test_password_reset_1'
         password = 'qweqwe'
         email = 'username@example.com'
-        name = 'passwd'
-        lastname = 'reset'
+        name = u'passwd'
+        lastname = u'reset'
         timestamp = int(time.time())
 
         new = User()
--- a/kallithea/tests/functional/test_my_account.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_my_account.py	Wed Jan 20 01:41:02 2016 +0100
@@ -72,8 +72,8 @@
         response = self.app.get(url('my_account_emails'))
 
         from kallithea.model.db import UserEmailMap
-        email_id = UserEmailMap.query()\
-            .filter(UserEmailMap.user == User.get_by_username(TEST_USER_ADMIN_LOGIN))\
+        email_id = UserEmailMap.query() \
+            .filter(UserEmailMap.user == User.get_by_username(TEST_USER_ADMIN_LOGIN)) \
             .filter(UserEmailMap.email == 'barz@example.com').one().email_id
 
         response.mustcontain('barz@example.com')
@@ -156,8 +156,8 @@
                                     username=TEST_USER_ADMIN_LOGIN,
                                     new_password=TEST_USER_ADMIN_PASS,
                                     password_confirmation='test122',
-                                    firstname='NewName',
-                                    lastname='NewLastname',
+                                    firstname=u'NewName',
+                                    lastname=u'NewLastname',
                                     email=new_email,
                                     _authentication_token=self.authentication_token())
                                 )
@@ -173,14 +173,14 @@
                                             username=TEST_USER_ADMIN_LOGIN,
                                             new_password=TEST_USER_ADMIN_PASS,
                                             password_confirmation='test122',
-                                            firstname='NewName',
-                                            lastname='NewLastname',
+                                            firstname=u'NewName',
+                                            lastname=u'NewLastname',
                                             email=new_email,
                                             _authentication_token=self.authentication_token()))
 
         response.mustcontain('An email address must contain a single @')
         from kallithea.model import validators
-        msg = validators.ValidUsername(edit=False, old_data={})\
+        msg = validators.ValidUsername(edit=False, old_data={}) \
                 ._messages['username_exists']
         msg = h.html_escape(msg % {'username': TEST_USER_ADMIN_LOGIN})
         response.mustcontain(msg)
--- a/kallithea/tests/functional/test_pullrequests.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_pullrequests.py	Wed Jan 20 01:41:02 2016 +0100
@@ -146,13 +146,13 @@
 class TestPullrequestsGetRepoRefs(TestController):
 
     def setUp(self):
-        self.main = fixture.create_repo('main', repo_type='hg')
+        self.main = fixture.create_repo(u'main', repo_type='hg')
         Session.add(self.main)
         Session.commit()
         self.c = PullrequestsController()
 
     def tearDown(self):
-        fixture.destroy_repo('main')
+        fixture.destroy_repo(u'main')
         Session.commit()
         Session.remove()
 
--- a/kallithea/tests/functional/test_summary.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/functional/test_summary.py	Wed Jan 20 01:41:02 2016 +0100
@@ -82,7 +82,7 @@
 
     def test_index_by_repo_having_id_path_in_name_hg(self):
         self.log_user()
-        fixture.create_repo(name='repo_1')
+        fixture.create_repo(name=u'repo_1')
         response = self.app.get(url(controller='summary',
                                     action='index',
                                     repo_name='repo_1'))
@@ -90,7 +90,7 @@
         try:
             response.mustcontain("repo_1")
         finally:
-            RepoModel().delete(Repository.get_by_repo_name('repo_1'))
+            RepoModel().delete(Repository.get_by_repo_name(u'repo_1'))
             Session().commit()
 
     def test_index_by_id_git(self):
--- a/kallithea/tests/models/common.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/common.py	Wed Jan 20 01:41:02 2016 +0100
@@ -15,7 +15,7 @@
 
 def _destroy_project_tree(test_u1_id):
     Session.remove()
-    repo_group = RepoGroup.get_by_group_name(group_name='g0')
+    repo_group = RepoGroup.get_by_group_name(group_name=u'g0')
     for el in reversed(repo_group.recursive_groups_and_repos()):
         if isinstance(el, Repository):
             RepoModel().delete(el)
@@ -56,18 +56,18 @@
         username=u'test_u1', password=u'qweqwe',
         email=u'test_u1@example.com', firstname=u'test_u1', lastname=u'test_u1'
     )
-    g0 = fixture.create_repo_group('g0')
-    g0_1 = fixture.create_repo_group('g0_1', group_parent_id=g0)
-    g0_1_1 = fixture.create_repo_group('g0_1_1', group_parent_id=g0_1)
-    g0_1_1_r1 = fixture.create_repo('g0/g0_1/g0_1_1/g0_1_1_r1', repo_group=g0_1_1)
-    g0_1_1_r2 = fixture.create_repo('g0/g0_1/g0_1_1/g0_1_1_r2', repo_group=g0_1_1)
-    g0_1_r1 = fixture.create_repo('g0/g0_1/g0_1_r1', repo_group=g0_1)
-    g0_2 = fixture.create_repo_group('g0_2', group_parent_id=g0)
-    g0_2_r1 = fixture.create_repo('g0/g0_2/g0_2_r1', repo_group=g0_2)
-    g0_2_r2 = fixture.create_repo('g0/g0_2/g0_2_r2', repo_group=g0_2)
-    g0_3 = fixture.create_repo_group('g0_3', group_parent_id=g0)
-    g0_3_r1 = fixture.create_repo('g0/g0_3/g0_3_r1', repo_group=g0_3)
-    g0_3_r2_private = fixture.create_repo('g0/g0_3/g0_3_r1_private',
+    g0 = fixture.create_repo_group(u'g0')
+    g0_1 = fixture.create_repo_group(u'g0_1', group_parent_id=g0)
+    g0_1_1 = fixture.create_repo_group(u'g0_1_1', group_parent_id=g0_1)
+    g0_1_1_r1 = fixture.create_repo(u'g0/g0_1/g0_1_1/g0_1_1_r1', repo_group=g0_1_1)
+    g0_1_1_r2 = fixture.create_repo(u'g0/g0_1/g0_1_1/g0_1_1_r2', repo_group=g0_1_1)
+    g0_1_r1 = fixture.create_repo(u'g0/g0_1/g0_1_r1', repo_group=g0_1)
+    g0_2 = fixture.create_repo_group(u'g0_2', group_parent_id=g0)
+    g0_2_r1 = fixture.create_repo(u'g0/g0_2/g0_2_r1', repo_group=g0_2)
+    g0_2_r2 = fixture.create_repo(u'g0/g0_2/g0_2_r2', repo_group=g0_2)
+    g0_3 = fixture.create_repo_group(u'g0_3', group_parent_id=g0)
+    g0_3_r1 = fixture.create_repo(u'g0/g0_3/g0_3_r1', repo_group=g0_3)
+    g0_3_r2_private = fixture.create_repo(u'g0/g0_3/g0_3_r1_private',
                                           repo_group=g0_3, repo_private=True)
     return test_u1
 
--- a/kallithea/tests/models/test_diff_parsers.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_diff_parsers.py	Wed Jan 20 01:41:02 2016 +0100
@@ -276,7 +276,10 @@
     @parameterized.expand([(x,) for x in DIFF_FIXTURES])
     def test_diff(self, diff_fixture):
         diff = fixture.load_resource(diff_fixture, strip=False)
-        diff_proc = DiffProcessor(diff)
+        vcs = 'hg'
+        if diff_fixture.startswith('git_'):
+            vcs = 'git'
+        diff_proc = DiffProcessor(diff, vcs=vcs)
         diff_proc_d = diff_proc.prepare()
         data = [(x['filename'], x['operation'], x['stats']) for x in diff_proc_d]
         expected_data = DIFF_FIXTURES[diff_fixture]
--- a/kallithea/tests/models/test_notifications.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_notifications.py	Wed Jan 20 01:41:02 2016 +0100
@@ -55,7 +55,7 @@
         self.assertEqual(notification.notification_id,
                          notifications[0].notification_id)
 
-        unotification = UserNotification.query()\
+        unotification = UserNotification.query() \
             .filter(UserNotification.notification == notification).all()
 
         self.assertEqual(len(unotification), len(usrs))
@@ -100,10 +100,10 @@
                                     recipients=[self.u3, self.u1, self.u2])
         Session().commit()
 
-        unotification = UserNotification.query()\
+        unotification = UserNotification.query() \
                             .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u3)\
+                                    notification) \
+                            .filter(UserNotification.user_id == self.u3) \
                             .scalar()
 
         self.assertEqual(unotification.user_id, self.u3)
@@ -112,10 +112,10 @@
                                    notification.notification_id)
         Session().commit()
 
-        u3notification = UserNotification.query()\
+        u3notification = UserNotification.query() \
                             .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u3)\
+                                    notification) \
+                            .filter(UserNotification.user_id == self.u3) \
                             .scalar()
 
         self.assertEqual(u3notification, None)
@@ -124,16 +124,16 @@
         self.assertEqual(Notification.query().all(), [notification])
 
         #u1 and u2 still have assignments
-        u1notification = UserNotification.query()\
+        u1notification = UserNotification.query() \
                             .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u1)\
+                                    notification) \
+                            .filter(UserNotification.user_id == self.u1) \
                             .scalar()
         self.assertNotEqual(u1notification, None)
-        u2notification = UserNotification.query()\
+        u2notification = UserNotification.query() \
                             .filter(UserNotification.notification ==
-                                    notification)\
-                            .filter(UserNotification.user_id == self.u2)\
+                                    notification) \
+                            .filter(UserNotification.user_id == self.u2) \
                             .scalar()
         self.assertNotEqual(u2notification, None)
 
@@ -144,7 +144,7 @@
         Session().commit()
 
         self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u1), 1)
+                         .get_unread_cnt_for_user(self.u1), 0)
         self.assertEqual(NotificationModel()
                          .get_unread_cnt_for_user(self.u2), 0)
         self.assertEqual(NotificationModel()
@@ -156,7 +156,7 @@
         Session().commit()
 
         self.assertEqual(NotificationModel()
-                         .get_unread_cnt_for_user(self.u1), 2)
+                         .get_unread_cnt_for_user(self.u1), 0)
         self.assertEqual(NotificationModel()
                          .get_unread_cnt_for_user(self.u2), 1)
         self.assertEqual(NotificationModel()
--- a/kallithea/tests/models/test_permissions.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_permissions.py	Wed Jan 20 01:41:02 2016 +0100
@@ -2,7 +2,7 @@
 from kallithea.tests.fixture import Fixture
 from kallithea.model.repo_group import RepoGroupModel
 from kallithea.model.repo import RepoModel
-from kallithea.model.db import RepoGroup, User, UserGroupRepoGroupToPerm,\
+from kallithea.model.db import RepoGroup, User, UserGroupRepoGroupToPerm, \
     Permission, UserToPerm
 from kallithea.model.user import UserModel
 
@@ -70,9 +70,9 @@
         u1_auth = AuthUser(user_id=self.u1.user_id)
         perms = {
             'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {HG_REPO: u'repository.read'}
+            'global': set(['hg.create.repository', 'repository.read',
+                           'hg.register.manual_activate']),
+            'repositories': {HG_REPO: 'repository.read'}
         }
         self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                          perms['repositories'][HG_REPO])
@@ -89,8 +89,8 @@
         a1_auth = AuthUser(user_id=self.a1.user_id)
         perms = {
             'repositories_groups': {},
-            'global': set([u'hg.admin', 'hg.create.write_on_repogroup.true']),
-            'repositories': {HG_REPO: u'repository.admin'}
+            'global': set(['hg.admin', 'hg.create.write_on_repogroup.true']),
+            'repositories': {HG_REPO: 'repository.admin'}
         }
         self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
                          perms['repositories'][HG_REPO])
@@ -105,13 +105,13 @@
                          perms['repositories'][HG_REPO])
 
     def test_default_group_perms(self):
-        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
-        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'test1', skip_if_exists=True)
+        self.g2 = fixture.create_repo_group(u'test2', skip_if_exists=True)
         u1_auth = AuthUser(user_id=self.u1.user_id)
         perms = {
             'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
             'global': set(Permission.DEFAULT_USER_PERMISSIONS),
-            'repositories': {HG_REPO: u'repository.read'}
+            'repositories': {HG_REPO: 'repository.read'}
         }
         self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                          perms['repositories'][HG_REPO])
@@ -121,8 +121,8 @@
                          perms['global'])
 
     def test_default_admin_group_perms(self):
-        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
-        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'test1', skip_if_exists=True)
+        self.g2 = fixture.create_repo_group(u'test2', skip_if_exists=True)
         a1_auth = AuthUser(user_id=self.a1.user_id)
         perms = {
             'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
@@ -137,7 +137,7 @@
 
     def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
         # make group
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
         # set permission to lower
@@ -158,9 +158,9 @@
         u1_auth = AuthUser(user_id=self.u1.user_id)
         perms = {
             'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {HG_REPO: u'repository.read'}
+            'global': set(['hg.create.repository', 'repository.read',
+                           'hg.register.manual_activate']),
+            'repositories': {HG_REPO: 'repository.read'}
         }
         self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                          new_perm)
@@ -169,7 +169,7 @@
 
     def test_propagated_permission_from_users_group(self):
         # make group
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u3)
 
         # grant perm for group this should override default permission from user
@@ -181,9 +181,9 @@
         u3_auth = AuthUser(user_id=self.u3.user_id)
         perms = {
             'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {HG_REPO: u'repository.read'}
+            'global': set(['hg.create.repository', 'repository.read',
+                           'hg.register.manual_activate']),
+            'repositories': {HG_REPO: 'repository.read'}
         }
         self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
                          new_perm_gr)
@@ -192,7 +192,7 @@
 
     def test_propagated_permission_from_users_group_lower_weight(self):
         # make group
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         # add user to group
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
 
@@ -215,9 +215,9 @@
         u1_auth = AuthUser(user_id=self.u1.user_id)
         perms = {
             'repositories_groups': {},
-            'global': set([u'hg.create.repository', u'repository.read',
-                           u'hg.register.manual_activate']),
-            'repositories': {HG_REPO: u'repository.write'}
+            'global': set(['hg.create.repository', 'repository.read',
+                           'hg.register.manual_activate']),
+            'repositories': {HG_REPO: 'repository.write'}
         }
         self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
                          new_perm_h)
@@ -225,8 +225,8 @@
                          perms['repositories_groups'])
 
     def test_repo_in_group_permissions(self):
-        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
-        self.g2 = fixture.create_repo_group('group2', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'group1', skip_if_exists=True)
+        self.g2 = fixture.create_repo_group(u'group2', skip_if_exists=True)
         # both perms should be read !
         u1_auth = AuthUser(user_id=self.u1.user_id)
         self.assertEqual(u1_auth.permissions['repositories_groups'],
@@ -289,7 +289,7 @@
 
     def test_repo_group_user_as_user_group_member(self):
         # create Group1
-        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'group1', skip_if_exists=True)
         a1_auth = AuthUser(user_id=self.anon.user_id)
 
         self.assertEqual(a1_auth.permissions['repositories_groups'],
@@ -300,7 +300,7 @@
                                                user=self.anon,
                                                perm='group.none')
         # make group
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         # add user to group
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
         Session().commit()
@@ -325,9 +325,9 @@
                                                       perm='group.read')
         Session().commit()
         # check if the
-        obj = Session().query(UserGroupRepoGroupToPerm)\
-            .filter(UserGroupRepoGroupToPerm.group == self.g1)\
-            .filter(UserGroupRepoGroupToPerm.users_group == self.ug1)\
+        obj = Session().query(UserGroupRepoGroupToPerm) \
+            .filter(UserGroupRepoGroupToPerm.group == self.g1) \
+            .filter(UserGroupRepoGroupToPerm.users_group == self.ug1) \
             .scalar()
         self.assertEqual(obj.permission.permission_name, 'group.read')
 
@@ -441,7 +441,7 @@
         # Add user to inactive user group, set specific permissions on user
         # group and disable inherit-from-default. User permissions should still
         # inherit from default.
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
@@ -477,7 +477,7 @@
         # Add user to inactive user group, set specific permissions on user
         # group and disable inherit-from-default. User permissions should still
         # inherit from default.
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
@@ -509,7 +509,7 @@
                               'hg.create.write_on_repogroup.true']))
 
     def test_inactive_user_group_does_not_affect_repo_permissions(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
@@ -517,7 +517,7 @@
 
         # note: make u2 repo owner rather than u1, because the owner always has
         # admin permissions
-        self.test_repo = fixture.create_repo(name='myownrepo',
+        self.test_repo = fixture.create_repo(name=u'myownrepo',
                                              repo_type='hg',
                                              cur_user=self.u2)
 
@@ -535,7 +535,7 @@
                          'repository.write')
 
     def test_inactive_user_group_does_not_affect_repo_permissions_inverse(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
@@ -543,7 +543,7 @@
 
         # note: make u2 repo owner rather than u1, because the owner always has
         # admin permissions
-        self.test_repo = fixture.create_repo(name='myownrepo',
+        self.test_repo = fixture.create_repo(name=u'myownrepo',
                                              repo_type='hg',
                                              cur_user=self.u2)
 
@@ -561,13 +561,13 @@
                          'repository.admin')
 
     def test_inactive_user_group_does_not_affect_repo_group_permissions(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
         user_group_model.update(self.ug1, {'users_group_active': False})
 
-        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'group1', skip_if_exists=True)
 
         # enable admin access for user group on repo group
         RepoGroupModel().grant_user_group_permission(self.g1,
@@ -583,13 +583,13 @@
                          {u'group1': u'group.write'})
 
     def test_inactive_user_group_does_not_affect_repo_group_permissions_inverse(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
         user_group_model.update(self.ug1, {'users_group_active': False})
 
-        self.g1 = fixture.create_repo_group('group1', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'group1', skip_if_exists=True)
 
         # enable only write access for user group on repo group
         RepoGroupModel().grant_user_group_permission(self.g1,
@@ -605,13 +605,13 @@
                          {u'group1': u'group.admin'})
 
     def test_inactive_user_group_does_not_affect_user_group_permissions(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
         user_group_model.update(self.ug1, {'users_group_active': False})
 
-        self.ug2 = fixture.create_user_group('G2')
+        self.ug2 = fixture.create_user_group(u'G2')
 
         # enable admin access for user group on user group
         UserGroupModel().grant_user_group_permission(self.ug2,
@@ -627,13 +627,13 @@
         self.assertEqual(u1_auth.permissions['user_groups'][u'G2'], u'usergroup.write')
 
     def test_inactive_user_group_does_not_affect_user_group_permissions_inverse(self):
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         self.ug1.inherit_default_permissions = False
         user_group_model = UserGroupModel()
         user_group_model.add_user_to_group(self.ug1, self.u1)
         user_group_model.update(self.ug1, {'users_group_active': False})
 
-        self.ug2 = fixture.create_user_group('G2')
+        self.ug2 = fixture.create_user_group(u'G2')
 
         # enable only write access for user group on user group
         UserGroupModel().grant_user_group_permission(self.ug2,
@@ -650,7 +650,7 @@
 
     def test_owner_permissions_doesnot_get_overwritten_by_group(self):
         #create repo as USER,
-        self.test_repo = fixture.create_repo(name='myownrepo',
+        self.test_repo = fixture.create_repo(name=u'myownrepo',
                                              repo_type='hg',
                                              cur_user=self.u1)
 
@@ -659,7 +659,7 @@
         self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
                          'repository.admin')
         #set his permission as user group, he should still be admin
-        self.ug1 = fixture.create_user_group('G1')
+        self.ug1 = fixture.create_user_group(u'G1')
         UserGroupModel().add_user_to_group(self.ug1, self.u1)
         RepoModel().grant_user_group_permission(self.test_repo,
                                                  group_name=self.ug1,
@@ -672,7 +672,7 @@
 
     def test_owner_permissions_doesnot_get_overwritten_by_others(self):
         #create repo as USER,
-        self.test_repo = fixture.create_repo(name='myownrepo',
+        self.test_repo = fixture.create_repo(name=u'myownrepo',
                                              repo_type='hg',
                                              cur_user=self.u1)
 
@@ -689,8 +689,8 @@
                          'repository.admin')
 
     def _test_def_perm_equal(self, user, change_factor=0):
-        perms = UserToPerm.query()\
-                .filter(UserToPerm.user == user)\
+        perms = UserToPerm.query() \
+                .filter(UserToPerm.user == user) \
                 .all()
         self.assertEqual(len(perms),
                          len(Permission.DEFAULT_USER_PERMISSIONS,)+change_factor,
@@ -704,8 +704,8 @@
         PermissionModel().create_default_permissions(user=self.u1)
         self._test_def_perm_equal(user=self.u1)
         #now we delete one, it should be re-created after another call
-        perms = UserToPerm.query()\
-                .filter(UserToPerm.user == self.u1)\
+        perms = UserToPerm.query() \
+                .filter(UserToPerm.user == self.u1) \
                 .all()
         Session().delete(perms[0])
         Session().commit()
@@ -734,9 +734,9 @@
         self.assertNotEqual(new, None)
 
         #now modify permissions
-        p = UserToPerm.query()\
-                .filter(UserToPerm.user == self.u1)\
-                .filter(UserToPerm.permission == old)\
+        p = UserToPerm.query() \
+                .filter(UserToPerm.user == self.u1) \
+                .filter(UserToPerm.permission == old) \
                 .one()
         p.permission = new
         Session().add(p)
--- a/kallithea/tests/models/test_repo_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_repo_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -13,7 +13,7 @@
 fixture = Fixture()
 
 
-def _update_group(id_, group_name, desc='desc', parent_id=None):
+def _update_group(id_, group_name, desc=u'desc', parent_id=None):
     form_data = fixture._get_group_create_params(group_name=group_name,
                                                  group_desc=desc,
                                                  group_parent_id=parent_id)
@@ -36,9 +36,9 @@
 class TestRepoGroups(BaseTestCase):
 
     def setUp(self):
-        self.g1 = fixture.create_repo_group('test1', skip_if_exists=True)
-        self.g2 = fixture.create_repo_group('test2', skip_if_exists=True)
-        self.g3 = fixture.create_repo_group('test3', skip_if_exists=True)
+        self.g1 = fixture.create_repo_group(u'test1', skip_if_exists=True)
+        self.g2 = fixture.create_repo_group(u'test2', skip_if_exists=True)
+        self.g3 = fixture.create_repo_group(u'test3', skip_if_exists=True)
 
     def tearDown(self):
         Session.remove()
@@ -58,78 +58,78 @@
         RepoGroupModel().delete(id_)
 
     def test_create_group(self):
-        g = fixture.create_repo_group('newGroup')
+        g = fixture.create_repo_group(u'newGroup')
         Session().commit()
         self.assertEqual(g.full_path, 'newGroup')
 
         self.assertTrue(self.__check_path('newGroup'))
 
     def test_create_same_name_group(self):
-        self.assertRaises(IntegrityError, lambda: fixture.create_repo_group('newGroup'))
+        self.assertRaises(IntegrityError, lambda: fixture.create_repo_group(u'newGroup'))
         Session().rollback()
 
     def test_same_subgroup(self):
-        sg1 = fixture.create_repo_group('sub1', group_parent_id=self.g1.group_id)
+        sg1 = fixture.create_repo_group(u'sub1', group_parent_id=self.g1.group_id)
         self.assertEqual(sg1.parent_group, self.g1)
         self.assertEqual(sg1.full_path, 'test1/sub1')
         self.assertTrue(self.__check_path('test1', 'sub1'))
 
-        ssg1 = fixture.create_repo_group('subsub1', group_parent_id=sg1.group_id)
+        ssg1 = fixture.create_repo_group(u'subsub1', group_parent_id=sg1.group_id)
         self.assertEqual(ssg1.parent_group, sg1)
         self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
         self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
 
     def test_remove_group(self):
-        sg1 = fixture.create_repo_group('deleteme')
+        sg1 = fixture.create_repo_group(u'deleteme')
         self.__delete_group(sg1.group_id)
 
         self.assertEqual(RepoGroup.get(sg1.group_id), None)
         self.assertFalse(self.__check_path('deteteme'))
 
-        sg1 = fixture.create_repo_group('deleteme', group_parent_id=self.g1.group_id)
+        sg1 = fixture.create_repo_group(u'deleteme', group_parent_id=self.g1.group_id)
         self.__delete_group(sg1.group_id)
 
         self.assertEqual(RepoGroup.get(sg1.group_id), None)
         self.assertFalse(self.__check_path('test1', 'deteteme'))
 
     def test_rename_single_group(self):
-        sg1 = fixture.create_repo_group('initial')
+        sg1 = fixture.create_repo_group(u'initial')
 
-        new_sg1 = _update_group(sg1.group_id, 'after')
+        new_sg1 = _update_group(sg1.group_id, u'after')
         self.assertTrue(self.__check_path('after'))
-        self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
+        self.assertEqual(RepoGroup.get_by_group_name(u'initial'), None)
 
     def test_update_group_parent(self):
 
-        sg1 = fixture.create_repo_group('initial', group_parent_id=self.g1.group_id)
+        sg1 = fixture.create_repo_group(u'initial', group_parent_id=self.g1.group_id)
 
-        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
+        new_sg1 = _update_group(sg1.group_id, u'after', parent_id=self.g1.group_id)
         self.assertTrue(self.__check_path('test1', 'after'))
-        self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
+        self.assertEqual(RepoGroup.get_by_group_name(u'test1/initial'), None)
 
-        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
+        new_sg1 = _update_group(sg1.group_id, u'after', parent_id=self.g3.group_id)
         self.assertTrue(self.__check_path('test3', 'after'))
-        self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
+        self.assertEqual(RepoGroup.get_by_group_name(u'test3/initial'), None)
 
-        new_sg1 = _update_group(sg1.group_id, 'hello')
+        new_sg1 = _update_group(sg1.group_id, u'hello')
         self.assertTrue(self.__check_path('hello'))
 
-        self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
+        self.assertEqual(RepoGroup.get_by_group_name(u'hello'), new_sg1)
 
     def test_subgrouping_with_repo(self):
 
-        g1 = fixture.create_repo_group('g1')
-        g2 = fixture.create_repo_group('g2')
+        g1 = fixture.create_repo_group(u'g1')
+        g2 = fixture.create_repo_group(u'g2')
         # create new repo
-        r = fixture.create_repo('john')
+        r = fixture.create_repo(u'john')
 
         self.assertEqual(r.repo_name, 'john')
         # put repo into group
-        r = _update_repo('john', repo_group=g1.group_id)
+        r = _update_repo(u'john', repo_group=g1.group_id)
         Session().commit()
         self.assertEqual(r.repo_name, 'g1/john')
 
-        _update_group(g1.group_id, 'g1', parent_id=g2.group_id)
+        _update_group(g1.group_id, u'g1', parent_id=g2.group_id)
         self.assertTrue(self.__check_path('g2', 'g1'))
 
         # test repo
@@ -137,13 +137,13 @@
                                                                 r.just_name]))
 
     def test_move_to_root(self):
-        g1 = fixture.create_repo_group('t11')
-        g2 = fixture.create_repo_group('t22', group_parent_id=g1.group_id)
+        g1 = fixture.create_repo_group(u't11')
+        g2 = fixture.create_repo_group(u't22', group_parent_id=g1.group_id)
 
         self.assertEqual(g2.full_path, 't11/t22')
         self.assertTrue(self.__check_path('t11', 't22'))
 
-        g2 = _update_group(g2.group_id, 'g22', parent_id=None)
+        g2 = _update_group(g2.group_id, u'g22', parent_id=None)
         Session().commit()
 
         self.assertEqual(g2.group_name, 'g22')
@@ -153,14 +153,14 @@
         self.assertTrue(self.__check_path('g22'))
 
     def test_rename_top_level_group_in_nested_setup(self):
-        g1 = fixture.create_repo_group('L1')
-        g2 = fixture.create_repo_group('L2', group_parent_id=g1.group_id)
-        g3 = fixture.create_repo_group('L3', group_parent_id=g2.group_id)
+        g1 = fixture.create_repo_group(u'L1')
+        g2 = fixture.create_repo_group(u'L2', group_parent_id=g1.group_id)
+        g3 = fixture.create_repo_group(u'L3', group_parent_id=g2.group_id)
 
-        r = fixture.create_repo('L1/L2/L3/L3_REPO', repo_group=g3.group_id)
+        r = fixture.create_repo(u'L1/L2/L3/L3_REPO', repo_group=g3.group_id)
 
         ##rename L1 all groups should be now changed
-        _update_group(g1.group_id, 'L1_NEW')
+        _update_group(g1.group_id, u'L1_NEW')
         Session().commit()
         self.assertEqual(g1.full_path, 'L1_NEW')
         self.assertEqual(g2.full_path, 'L1_NEW/L2')
@@ -168,14 +168,14 @@
         self.assertEqual(r.repo_name,  'L1_NEW/L2/L3/L3_REPO')
 
     def test_change_parent_of_top_level_group_in_nested_setup(self):
-        g1 = fixture.create_repo_group('R1')
-        g2 = fixture.create_repo_group('R2', group_parent_id=g1.group_id)
-        g3 = fixture.create_repo_group('R3', group_parent_id=g2.group_id)
-        g4 = fixture.create_repo_group('R1_NEW')
+        g1 = fixture.create_repo_group(u'R1')
+        g2 = fixture.create_repo_group(u'R2', group_parent_id=g1.group_id)
+        g3 = fixture.create_repo_group(u'R3', group_parent_id=g2.group_id)
+        g4 = fixture.create_repo_group(u'R1_NEW')
 
-        r = fixture.create_repo('R1/R2/R3/R3_REPO', repo_group=g3.group_id)
+        r = fixture.create_repo(u'R1/R2/R3/R3_REPO', repo_group=g3.group_id)
         ##rename L1 all groups should be now changed
-        _update_group(g1.group_id, 'R1', parent_id=g4.group_id)
+        _update_group(g1.group_id, u'R1', parent_id=g4.group_id)
         Session().commit()
         self.assertEqual(g1.full_path, 'R1_NEW/R1')
         self.assertEqual(g2.full_path, 'R1_NEW/R1/R2')
@@ -183,15 +183,15 @@
         self.assertEqual(r.repo_name,  'R1_NEW/R1/R2/R3/R3_REPO')
 
     def test_change_parent_of_top_level_group_in_nested_setup_with_rename(self):
-        g1 = fixture.create_repo_group('X1')
-        g2 = fixture.create_repo_group('X2', group_parent_id=g1.group_id)
-        g3 = fixture.create_repo_group('X3', group_parent_id=g2.group_id)
-        g4 = fixture.create_repo_group('X1_NEW')
+        g1 = fixture.create_repo_group(u'X1')
+        g2 = fixture.create_repo_group(u'X2', group_parent_id=g1.group_id)
+        g3 = fixture.create_repo_group(u'X3', group_parent_id=g2.group_id)
+        g4 = fixture.create_repo_group(u'X1_NEW')
 
-        r = fixture.create_repo('X1/X2/X3/X3_REPO', repo_group=g3.group_id)
+        r = fixture.create_repo(u'X1/X2/X3/X3_REPO', repo_group=g3.group_id)
 
         ##rename L1 all groups should be now changed
-        _update_group(g1.group_id, 'X1_PRIM', parent_id=g4.group_id)
+        _update_group(g1.group_id, u'X1_PRIM', parent_id=g4.group_id)
         Session().commit()
         self.assertEqual(g1.full_path, 'X1_NEW/X1_PRIM')
         self.assertEqual(g2.full_path, 'X1_NEW/X1_PRIM/X2')
--- a/kallithea/tests/models/test_repos.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_repos.py	Wed Jan 20 01:41:02 2016 +0100
@@ -18,60 +18,60 @@
         Session.remove()
 
     def test_remove_repo(self):
-        repo = fixture.create_repo(name='test-repo-1')
+        repo = fixture.create_repo(name=u'test-repo-1')
         Session().commit()
 
         RepoModel().delete(repo=repo)
         Session().commit()
 
-        self.assertEqual(None, Repository.get_by_repo_name(repo_name='test-repo-1'))
+        self.assertEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-1'))
 
     def test_remove_repo_repo_raises_exc_when_attached_forks(self):
-        repo = fixture.create_repo(name='test-repo-1')
+        repo = fixture.create_repo(name=u'test-repo-1')
         Session().commit()
 
-        fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
+        fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
         Session().commit()
 
         self.assertRaises(AttachedForksError, lambda: RepoModel().delete(repo=repo))
 
     def test_remove_repo_delete_forks(self):
-        repo = fixture.create_repo(name='test-repo-1')
+        repo = fixture.create_repo(name=u'test-repo-1')
         Session().commit()
 
-        fork = fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
+        fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
         Session().commit()
 
         #fork of fork
-        fixture.create_fork(fork.repo_name, 'test-repo-fork-fork-1')
+        fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
         Session().commit()
 
         RepoModel().delete(repo=repo, forks='delete')
         Session().commit()
 
-        self.assertEqual(None, Repository.get_by_repo_name(repo_name='test-repo-1'))
-        self.assertEqual(None, Repository.get_by_repo_name(repo_name='test-repo-fork-1'))
-        self.assertEqual(None, Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1'))
+        self.assertEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-1'))
+        self.assertEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-fork-1'))
+        self.assertEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-fork-fork-1'))
 
     def test_remove_repo_detach_forks(self):
-        repo = fixture.create_repo(name='test-repo-1')
+        repo = fixture.create_repo(name=u'test-repo-1')
         Session().commit()
 
-        fork = fixture.create_fork(repo.repo_name, 'test-repo-fork-1')
+        fork = fixture.create_fork(repo.repo_name, u'test-repo-fork-1')
         Session().commit()
 
         #fork of fork
-        fixture.create_fork(fork.repo_name, 'test-repo-fork-fork-1')
+        fixture.create_fork(fork.repo_name, u'test-repo-fork-fork-1')
         Session().commit()
 
         RepoModel().delete(repo=repo, forks='detach')
         Session().commit()
 
         try:
-            self.assertEqual(None, Repository.get_by_repo_name(repo_name='test-repo-1'))
-            self.assertNotEqual(None, Repository.get_by_repo_name(repo_name='test-repo-fork-1'))
-            self.assertNotEqual(None, Repository.get_by_repo_name(repo_name='test-repo-fork-fork-1'))
+            self.assertEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-1'))
+            self.assertNotEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-fork-1'))
+            self.assertNotEqual(None, Repository.get_by_repo_name(repo_name=u'test-repo-fork-fork-1'))
         finally:
-            RepoModel().delete(repo='test-repo-fork-fork-1')
-            RepoModel().delete(repo='test-repo-fork-1')
+            RepoModel().delete(repo=u'test-repo-fork-fork-1')
+            RepoModel().delete(repo=u'test-repo-fork-1')
             Session().commit()
--- a/kallithea/tests/models/test_user_group_permissions_on_repo_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_user_group_permissions_on_repo_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -17,7 +17,7 @@
 _get_group_perms = None
 
 
-def permissions_setup_func(group_name='g0', perm='group.read', recursive='all'):
+def permissions_setup_func(group_name=u'g0', perm='group.read', recursive='all'):
     """
     Resets all permissions to perm attribute
     """
@@ -44,7 +44,7 @@
     Session().commit()
     test_u2_id = test_u2.user_id
 
-    gr1 = fixture.create_user_group('perms_group_1')
+    gr1 = fixture.create_user_group(u'perms_group_1')
     Session().commit()
     test_u2_gr_id = gr1.users_group_id
     UserGroupModel().add_user_to_group(gr1, user=test_u2_id)
@@ -58,13 +58,13 @@
 
 def teardown_module():
     _destroy_project_tree(test_u2_id)
-    fixture.destroy_user_group('perms_group_1')
+    fixture.destroy_user_group(u'perms_group_1')
 
 
 def test_user_permissions_on_group_without_recursive_mode():
     # set permission to g0 non-recursive mode
     recursive = 'none'
-    group = 'g0'
+    group = u'g0'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     items = [x for x in _get_repo_perms(group, recursive)]
@@ -83,7 +83,7 @@
 def test_user_permissions_on_group_without_recursive_mode_subgroup():
     # set permission to g0 non-recursive mode
     recursive = 'none'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     items = [x for x in _get_repo_perms(group, recursive)]
@@ -104,7 +104,7 @@
     # set permission to g0 recursive mode, all children including
     # other repos and groups should have this permission now set !
     recursive = 'all'
-    group = 'g0'
+    group = u'g0'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -121,7 +121,7 @@
 def test_user_permissions_on_group_with_recursive_mode_inner_group():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_3'
+    group = u'g0/g0_3'
     permissions_setup_func(group, 'group.none', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -138,7 +138,7 @@
 def test_user_permissions_on_group_with_recursive_mode_deepest():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_1/g0_1_1'
+    group = u'g0/g0_1/g0_1_1'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -155,7 +155,7 @@
 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_2'
+    group = u'g0/g0_2'
     permissions_setup_func(group, 'group.admin', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -172,7 +172,7 @@
 def test_user_permissions_on_group_with_recursive_mode_on_repos():
     # set permission to g0/g0_1 with recursive mode on just repositories
     recursive = 'repos'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     perm = 'group.write'
     permissions_setup_func(group, perm, recursive=recursive)
 
@@ -196,7 +196,7 @@
 def test_user_permissions_on_group_with_recursive_mode_on_repo_groups():
     # set permission to g0/g0_1 with recursive mode on just repository groups
     recursive = 'groups'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     perm = 'group.none'
     permissions_setup_func(group, perm, recursive=recursive)
 
--- a/kallithea/tests/models/test_user_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_user_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -20,12 +20,12 @@
 
     @parameterized.expand([
         ([], [], [], [], []),
-        ([], ['regular'], [], [], ['regular']),  # no changes of regular
-        (['some_other'], [], [], ['some_other'], []),   # not added to regular group
-        ([], ['regular'], ['container'], ['container'], ['regular', 'container']),
-        ([], ['regular'], [], ['container', 'container2'], ['regular', 'container', 'container2']),
-        ([], ['regular'], ['other'], [], ['regular']),  # remove not used
-        (['some_other'], ['regular'], ['other', 'container'], ['container', 'container2'], ['regular', 'container', 'container2']),
+        ([], [u'regular'], [], [], [u'regular']),  # no changes of regular
+        ([u'some_other'], [], [], [u'some_other'], []),   # not added to regular group
+        ([], [u'regular'], [u'container'], [u'container'], [u'regular', u'container']),
+        ([], [u'regular'], [], [u'container', u'container2'], [u'regular', u'container', u'container2']),
+        ([], [u'regular'], [u'other'], [], [u'regular']),  # remove not used
+        ([u'some_other'], [u'regular'], [u'other', u'container'], [u'container', u'container2'], [u'regular', u'container', u'container2']),
     ])
     def test_enforce_groups(self, pre_existing, regular_should_be,
                             external_should_be, groups, expected):
--- a/kallithea/tests/models/test_user_permissions_on_repo_groups.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_user_permissions_on_repo_groups.py	Wed Jan 20 01:41:02 2016 +0100
@@ -13,7 +13,7 @@
 _get_group_perms = None
 
 
-def permissions_setup_func(group_name='g0', perm='group.read', recursive='all',
+def permissions_setup_func(group_name=u'g0', perm='group.read', recursive='all',
                            user_id=None):
     """
     Resets all permissions to perm attribute
@@ -58,7 +58,7 @@
 def test_user_permissions_on_group_without_recursive_mode():
     # set permission to g0 non-recursive mode
     recursive = 'none'
-    group = 'g0'
+    group = u'g0'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     items = [x for x in _get_repo_perms(group, recursive)]
@@ -77,7 +77,7 @@
 def test_user_permissions_on_group_without_recursive_mode_subgroup():
     # set permission to g0 non-recursive mode
     recursive = 'none'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     items = [x for x in _get_repo_perms(group, recursive)]
@@ -98,7 +98,7 @@
     # set permission to g0 recursive mode, all children including
     # other repos and groups should have this permission now set !
     recursive = 'all'
-    group = 'g0'
+    group = u'g0'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -117,7 +117,7 @@
     # set permission to g0 recursive mode, all children including
     # other repos and groups should have this permission now set !
     recursive = 'all'
-    group = 'g0'
+    group = u'g0'
     default_user_id = User.get_default_user().user_id
     permissions_setup_func(group, 'group.write', recursive=recursive,
                            user_id=default_user_id)
@@ -142,7 +142,7 @@
 def test_user_permissions_on_group_with_recursive_mode_inner_group():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_3'
+    group = u'g0/g0_3'
     permissions_setup_func(group, 'group.none', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -159,7 +159,7 @@
 def test_user_permissions_on_group_with_recursive_mode_deepest():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_1/g0_1_1'
+    group = u'g0/g0_1/g0_1_1'
     permissions_setup_func(group, 'group.write', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -176,7 +176,7 @@
 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
     ## set permission to g0_3 group to none
     recursive = 'all'
-    group = 'g0/g0_2'
+    group = u'g0/g0_2'
     permissions_setup_func(group, 'group.admin', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
@@ -194,7 +194,7 @@
     # set permission to g0/g0_1 recursive repos only mode, all children including
     # other repos should have this permission now set, inner groups are excluded!
     recursive = 'repos'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     perm = 'group.none'
     default_user_id = User.get_default_user().user_id
 
@@ -227,7 +227,7 @@
 def test_user_permissions_on_group_with_recursive_repo_mode_inner_group():
     ## set permission to g0_3 group to none, with recursive repos only
     recursive = 'repos'
-    group = 'g0/g0_3'
+    group = u'g0/g0_3'
     perm = 'group.none'
     permissions_setup_func(group, perm, recursive=recursive)
 
@@ -253,7 +253,7 @@
     # other groups should have this permission now set. repositories should
     # remain intact as we use groups only mode !
     recursive = 'groups'
-    group = 'g0/g0_1'
+    group = u'g0/g0_1'
     default_user_id = User.get_default_user().user_id
     permissions_setup_func(group, 'group.write', recursive=recursive,
                            user_id=default_user_id)
@@ -278,7 +278,7 @@
 def test_user_permissions_on_group_with_recursive_group_mode_inner_group():
     ## set permission to g0_3 group to none, with recursive mode for groups only
     recursive = 'groups'
-    group = 'g0/g0_3'
+    group = u'g0/g0_3'
     permissions_setup_func(group, 'group.none', recursive=recursive)
 
     repo_items = [x for x in _get_repo_perms(group, recursive)]
--- a/kallithea/tests/models/test_users.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/models/test_users.py	Wed Jan 20 01:41:02 2016 +0100
@@ -1,6 +1,6 @@
 from kallithea.tests import *
 
-from kallithea.model.db import User, UserGroup, UserGroupMember, UserEmailMap,\
+from kallithea.model.db import User, UserGroup, UserGroupMember, UserEmailMap, \
     Permission
 from kallithea.model.user import UserModel
 
@@ -28,7 +28,7 @@
         self.assertEqual(User.get_by_username(u'test_user'), usr)
 
         # make user group
-        user_group = fixture.create_user_group('some_example_group')
+        user_group = fixture.create_user_group(u'some_example_group')
         Session().commit()
 
         UserGroupModel().add_user_to_group(user_group, usr)
--- a/kallithea/tests/other/manual_test_vcs_operations.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/other/manual_test_vcs_operations.py	Wed Jan 20 01:41:02 2016 +0100
@@ -273,8 +273,8 @@
         stdout, stderr = _add_files_and_push('hg', DEST, files_no=1)
 
         key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
-                                               ==HG_REPO).one()
-        self.assertEqual(key.cache_active, False)
+                                               ==HG_REPO).all()
+        self.assertEqual(key, [])
 
     def test_push_invalidates_cache_git(self):
         key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
@@ -295,9 +295,8 @@
         _check_proper_git_push(stdout, stderr)
 
         key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
-                                               ==GIT_REPO).one()
-        print CacheInvalidation.get_all()
-        self.assertEqual(key.cache_active, False)
+                                               ==GIT_REPO).all()
+        self.assertEqual(key, [])
 
     def test_push_wrong_credentials_hg(self):
         DEST = _get_tmp_dir()
--- a/kallithea/tests/other/test_mail.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/other/test_mail.py	Wed Jan 20 01:41:02 2016 +0100
@@ -145,7 +145,7 @@
         subject = 'subject'
         body = 'body'
         html_body = 'html_body'
-        author = User(name='foo', lastname='(fubar) "baz"')
+        author = User(name='foo', lastname=u'(fubar) "baz"')
         headers = {'extra': 'yes'}
 
         config_mock = {
--- a/kallithea/tests/other/test_validators.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/other/test_validators.py	Wed Jan 20 01:41:02 2016 +0100
@@ -51,21 +51,21 @@
 
     def test_ValidUserGroup(self):
         validator = v.ValidUserGroup()
-        self.assertRaises(formencode.Invalid, validator.to_python, 'default')
-        self.assertRaises(formencode.Invalid, validator.to_python, '.,')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'default')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'.,')
 
-        gr = fixture.create_user_group('test')
-        gr2 = fixture.create_user_group('tes2')
+        gr = fixture.create_user_group(u'test')
+        gr2 = fixture.create_user_group(u'tes2')
         Session().commit()
-        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'test')
         assert gr.users_group_id is not None
         validator = v.ValidUserGroup(edit=True,
                                     old_data={'users_group_id':
                                               gr2.users_group_id})
 
-        self.assertRaises(formencode.Invalid, validator.to_python, 'test')
-        self.assertRaises(formencode.Invalid, validator.to_python, 'TesT')
-        self.assertRaises(formencode.Invalid, validator.to_python, 'TEST')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'test')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'TesT')
+        self.assertRaises(formencode.Invalid, validator.to_python, u'TEST')
         UserGroupModel().delete(gr)
         UserGroupModel().delete(gr2)
         Session().commit()
@@ -75,7 +75,7 @@
         model = RepoGroupModel()
         self.assertRaises(formencode.Invalid, validator.to_python,
                           {'group_name': HG_REPO, })
-        gr = model.create(group_name='test_gr', group_description='desc',
+        gr = model.create(group_name=u'test_gr', group_description=u'desc',
                           parent=None,
                           just_db=True,
                           owner=TEST_USER_ADMIN_LOGIN)
@@ -147,8 +147,8 @@
         self.assertRaises(formencode.Invalid,
                           validator.to_python, {'repo_name': HG_REPO})
 
-        gr = RepoGroupModel().create(group_name='group_test',
-                                      group_description='desc',
+        gr = RepoGroupModel().create(group_name=u'group_test',
+                                      group_description=u'desc',
                                       parent=None,
                                       owner=TEST_USER_ADMIN_LOGIN)
         self.assertRaises(formencode.Invalid,
--- a/kallithea/tests/test.ini	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/test.ini	Wed Jan 20 01:41:02 2016 +0100
@@ -163,6 +163,7 @@
 
 ## COMMON ##
 host = 127.0.0.1
+#port = 5000
 port = 4999
 
 ## middleware for hosting the WSGI application under a URL prefix
@@ -224,6 +225,7 @@
 
 ## options for showing and identifying changesets
 show_sha_length = 12
+#show_revision_number = false
 show_revision_number = true
 
 ## gist URL alias, used to create nicer urls for gist. This should be an
@@ -280,12 +282,6 @@
 #issue_server_link_wiki = https://wiki.example.com/{id}
 #issue_prefix_wiki = WIKI-
 
-## instance-id prefix
-## a prefix key for this instance used for cache invalidation when running
-## multiple instances of kallithea, make sure it's globally unique for
-## all running kallithea instances. Leave empty if you don't use it
-instance_id =
-
 ## alternative return HTTP header for failed authentication. Default HTTP
 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
 ## handling that. Set this variable to 403 to return HTTPForbidden
@@ -301,6 +297,18 @@
 ## allows to setup custom hooks in settings page
 allow_custom_hooks_settings = True
 
+## extra extensions for indexing, space separated and without the leading '.'.
+# index.extensions =
+#    gemfile
+#    lock
+
+## extra filenames for indexing, space separated
+# index.filenames =
+#    .dockerignore
+#    .editorconfig
+#    INSTALL
+#    CHANGELOG
+
 ####################################
 ###        CELERY CONFIG        ####
 ####################################
@@ -347,6 +355,7 @@
 beaker.cache.long_term.key_length = 256
 
 beaker.cache.sql_cache_short.type = memory
+#beaker.cache.sql_cache_short.expire = 10
 beaker.cache.sql_cache_short.expire = 1
 beaker.cache.sql_cache_short.key_length = 256
 
@@ -486,13 +495,12 @@
 #sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
 
 # MySQL
-#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
+#sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea?charset=utf8
 
 # see sqlalchemy docs for others
 
 sqlalchemy.db1.echo = false
 sqlalchemy.db1.pool_recycle = 3600
-sqlalchemy.db1.convert_unicode = true
 
 ################################
 ### LOGGING CONFIGURATION   ####
@@ -543,8 +551,8 @@
 
 [logger_sqlalchemy]
 #level = INFO
+level = ERROR
 #handlers = console_sql
-level = ERROR
 handlers = console
 qualname = sqlalchemy.engine
 propagate = 0
--- a/kallithea/tests/vcs/test_git.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/vcs/test_git.py	Wed Jan 20 01:41:02 2016 +0100
@@ -303,8 +303,8 @@
         self.assertTrue(api is chset.get_node('docs/api'))
         index = api.get_node('index.rst')
         self.assertTrue(index is chset.get_node('docs/api/index.rst'))
-        self.assertTrue(index is chset.get_node('docs')\
-            .get_node('api')\
+        self.assertTrue(index is chset.get_node('docs') \
+            .get_node('api') \
             .get_node('index.rst'))
 
     def test_branch_and_tags(self):
@@ -535,8 +535,8 @@
         """
         Tests state of FileNodes.
         """
-        node = self.repo\
-            .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0')\
+        node = self.repo \
+            .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0') \
             .get_node('vcs/utils/diffs.py')
         self.assertTrue(node.state, NodeState.ADDED)
         self.assertTrue(node.added)
@@ -544,8 +544,8 @@
         self.assertFalse(node.not_changed)
         self.assertFalse(node.removed)
 
-        node = self.repo\
-            .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e')\
+        node = self.repo \
+            .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e') \
             .get_node('.hgignore')
         self.assertTrue(node.state, NodeState.CHANGED)
         self.assertFalse(node.added)
@@ -553,8 +553,8 @@
         self.assertFalse(node.not_changed)
         self.assertFalse(node.removed)
 
-        node = self.repo\
-            .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064')\
+        node = self.repo \
+            .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064') \
             .get_node('setup.py')
         self.assertTrue(node.state, NodeState.NOT_CHANGED)
         self.assertFalse(node.added)
@@ -599,24 +599,24 @@
 
     def test_author_email(self):
         self.assertEqual('marcin@python-blog.com',
-          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3')\
+          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
           .author_email)
         self.assertEqual('lukasz.balcerzak@python-center.pl',
-          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b')\
+          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
           .author_email)
         self.assertEqual('none@none',
-          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992')\
+          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
           .author_email)
 
     def test_author_username(self):
         self.assertEqual('Marcin Kuzminski',
-          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3')\
+          self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
           .author_name)
         self.assertEqual('Lukasz Balcerzak',
-          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b')\
+          self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
           .author_name)
         self.assertEqual('marcink',
-          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992')\
+          self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
           .author_name)
 
 
--- a/kallithea/tests/vcs/test_hg.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/vcs/test_hg.py	Wed Jan 20 01:41:02 2016 +0100
@@ -1,5 +1,6 @@
 
 import os
+from kallithea.lib.utils2 import safe_str
 from kallithea.lib.vcs.backends.hg import MercurialRepository, MercurialChangeset
 from kallithea.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
 from kallithea.lib.vcs.nodes import NodeKind, NodeState
@@ -24,7 +25,7 @@
                       % TEST_HG_REPO_CLONE)
 
     def setUp(self):
-        self.repo = MercurialRepository(TEST_HG_REPO)
+        self.repo = MercurialRepository(safe_str(TEST_HG_REPO))
 
     def test_wrong_repo_path(self):
         wrong_repo_path = '/tmp/errorrepo'
@@ -35,7 +36,7 @@
 
     def test_repo_clone(self):
         self.__check_for_existing_repo()
-        repo = MercurialRepository(TEST_HG_REPO)
+        repo = MercurialRepository(safe_str(TEST_HG_REPO))
         repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
             src_url=TEST_HG_REPO, update_after_clone=True)
         self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
@@ -45,7 +46,7 @@
             self.assertEqual(raw_id, repo_clone.get_changeset(raw_id).raw_id)
 
     def test_repo_clone_with_update(self):
-        repo = MercurialRepository(TEST_HG_REPO)
+        repo = MercurialRepository(safe_str(TEST_HG_REPO))
         repo_clone = MercurialRepository(TEST_HG_REPO_CLONE + '_w_update',
             src_url=TEST_HG_REPO, update_after_clone=True)
         self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
@@ -56,7 +57,7 @@
                                                     'MANIFEST.in')), True,)
 
     def test_repo_clone_without_update(self):
-        repo = MercurialRepository(TEST_HG_REPO)
+        repo = MercurialRepository(safe_str(TEST_HG_REPO))
         repo_clone = MercurialRepository(TEST_HG_REPO_CLONE + '_wo_update',
             src_url=TEST_HG_REPO, update_after_clone=False)
         self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
@@ -242,7 +243,7 @@
 class MercurialChangesetTest(unittest.TestCase):
 
     def setUp(self):
-        self.repo = MercurialRepository(TEST_HG_REPO)
+        self.repo = MercurialRepository(safe_str(TEST_HG_REPO))
 
     def _test_equality(self, changeset):
         revision = changeset.revision
@@ -302,8 +303,8 @@
         self.assertTrue(api is chset.get_node('docs/api'))
         index = api.get_node('index.rst')
         self.assertTrue(index is chset.get_node('docs/api/index.rst'))
-        self.assertTrue(index is chset.get_node('docs')\
-            .get_node('api')\
+        self.assertTrue(index is chset.get_node('docs') \
+            .get_node('api') \
             .get_node('index.rst'))
 
     def test_branch_and_tags(self):
--- a/kallithea/tests/vcs/test_vcs.py	Fri Jan 15 14:55:27 2016 +0000
+++ b/kallithea/tests/vcs/test_vcs.py	Wed Jan 20 01:41:02 2016 +0100
@@ -2,6 +2,7 @@
 import os
 import shutil
 
+from kallithea.lib.utils2 import safe_str
 from kallithea.lib.vcs import VCSError, get_repo, get_backend
 from kallithea.lib.vcs.backends.hg import MercurialRepository
 from kallithea.lib.vcs.utils.compat import unittest
@@ -22,14 +23,14 @@
         alias = 'hg'
         path = TEST_HG_REPO
         backend = get_backend(alias)
-        repo = backend(path)
+        repo = backend(safe_str(path))
         self.assertEqual('hg',repo.alias)
 
     def test_alias_detect_git(self):
         alias = 'git'
         path = TEST_GIT_REPO
         backend = get_backend(alias)
-        repo = backend(path)
+        repo = backend(safe_str(path))
         self.assertEqual('git',repo.alias)
 
     def test_wrong_alias(self):
@@ -40,28 +41,28 @@
         alias = 'hg'
         path = TEST_HG_REPO
         backend = get_backend(alias)
-        repo = backend(path)
+        repo = backend(safe_str(path))
 
-        self.assertEqual(repo.__class__, get_repo(path, alias).__class__)
-        self.assertEqual(repo.path, get_repo(path, alias).path)
+        self.assertEqual(repo.__class__, get_repo(safe_str(path), alias).__class__)
+        self.assertEqual(repo.path, get_repo(safe_str(path), alias).path)
 
     def test_get_repo_autoalias_hg(self):
         alias = 'hg'
         path = TEST_HG_REPO
         backend = get_backend(alias)
-        repo = backend(path)
+        repo = backend(safe_str(path))
 
-        self.assertEqual(repo.__class__, get_repo(path).__class__)
-        self.assertEqual(repo.path, get_repo(path).path)
+        self.assertEqual(repo.__class__, get_repo(safe_str(path)).__class__)
+        self.assertEqual(repo.path, get_repo(safe_str(path)).path)
 
     def test_get_repo_autoalias_git(self):
         alias = 'git'
         path = TEST_GIT_REPO
         backend = get_backend(alias)
-        repo = backend(path)
+        repo = backend(safe_str(path))
 
-        self.assertEqual(repo.__class__, get_repo(path).__class__)
-        self.assertEqual(repo.path, get_repo(path).path)
+        self.assertEqual(repo.__class__, get_repo(safe_str(path)).__class__)
+        self.assertEqual(repo.path, get_repo(safe_str(path)).path)
 
 
     def test_get_repo_err(self):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/docs-headings.py	Wed Jan 20 01:41:02 2016 +0100
@@ -0,0 +1,79 @@
+#!/usr/bin/env python2
+
+"""
+Consistent formatting of rst section titles
+"""
+
+import re
+import subprocess
+
+spaces = [
+    (0, 1), # we assume this is a over-and-underlined header
+    (2, 1),
+    (1, 1),
+    (1, 0),
+    (1, 0),
+    ]
+
+# http://sphinx-doc.org/rest.html :
+#   for the Python documentation, this convention is used which you may follow:
+#   # with overline, for parts
+#   * with overline, for chapters
+#   =, for sections
+#   -, for subsections
+#   ^, for subsubsections
+#   ", for paragraphs
+pystyles = ['#', '*', '=', '-', '^', '"']
+
+# match on a header line underlined with one of the valid characters
+headermatch = re.compile(r'''\n*(.+)\n([][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-])\2{2,}\n+''', flags=re.MULTILINE)
+
+
+def main():
+    for fn in subprocess.check_output(['hg', 'loc', 'set:**.rst+kallithea/i18n/how_to']).splitlines():
+        print 'processing %s:' % fn
+        s = file(fn).read()
+
+        # find levels and their styles
+        lastpos = 0
+        styles = []
+        for markup in headermatch.findall(s):
+            style = markup[1]
+            if style in styles:
+                stylepos = styles.index(style)
+                if stylepos > lastpos + 1:
+                    print 'bad style %r with level %s - was at %s' % (style, stylepos, lastpos)
+            else:
+                stylepos = len(styles)
+                if stylepos > lastpos + 1:
+                    print 'bad new style %r - expected %r' % (style, styles[lastpos + 1])
+                else:
+                    styles.append(style)
+            lastpos = stylepos
+
+        # remove superfluous spacing (may however be restored by header spacing)
+        s = re.sub(r'''(\n\n)\n*''', r'\1', s, flags=re.MULTILINE)
+
+        if styles:
+            newstyles = pystyles[pystyles.index(styles[0]):]
+
+            def subf(m):
+                title, style = m.groups()
+                level = styles.index(style)
+                before, after = spaces[level]
+                newstyle = newstyles[level]
+                return '\n' * (before + 1) + title + '\n' + newstyle * len(title) + '\n' * (after + 1)
+            s = headermatch.sub(subf, s)
+
+        # remove superfluous spacing when headers are adjacent
+        s = re.sub(r'''(\n.+\n([][!"#$%&'()*+,./:;<=>?@\\^_`{|}~-])\2{2,}\n\n\n)\n*''', r'\1', s, flags=re.MULTILINE)
+        # fix trailing space and spacing before link sections
+        s = s.strip() + '\n'
+        s = re.sub(r'''\n+((?:\.\. _[^\n]*\n)+)$''', r'\n\n\n\1', s)
+
+        file(fn, 'w').write(s)
+        print subprocess.check_output(['hg', 'diff', fn])
+        print
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/generate-ini.py	Wed Jan 20 01:41:02 2016 +0100
@@ -0,0 +1,173 @@
+#!/usr/bin/env python2
+"""
+Based on kallithea/bin/template.ini.mako, generate
+  kallithea/config/deployment.ini_tmpl
+  development.ini
+  kallithea/tests/test.ini
+"""
+
+import re
+
+makofile = 'kallithea/bin/template.ini.mako'
+
+# the mako conditionals used in all other ini files and templates
+selected_mako_conditionals = set([
+    "database_engine == 'sqlite'",
+    "http_server == 'waitress'",
+    "error_aggregation_service == 'errormator'",
+    "error_aggregation_service == 'sentry'",
+])
+
+# the mako variables used in all other ini files and templates
+mako_variable_values = {
+    'host': '127.0.0.1',
+    'port': '5000',
+    'here': '%(here)s',
+    'uuid()': '${app_instance_uuid}',
+}
+
+# files to be generated from the mako template
+ini_files = [
+    ('kallithea/config/deployment.ini_tmpl',
+        '''
+        Kallithea - Example config
+
+        The %(here)s variable will be replaced with the parent directory of this file
+        ''',
+        {}, # exactly the same settings as template.ini.mako
+    ),
+    ('kallithea/tests/test.ini',
+        '''
+        Kallithea - config for tests:
+        initial_repo_scan = true
+        vcs_full_cache = false
+        sqlalchemy and kallithea_test.sqlite
+        custom logging
+
+        The %(here)s variable will be replaced with the parent directory of this file
+        ''',
+        {
+            '[server:main]': {
+                'port': '4999',
+            },
+            '[app:main]': {
+                'initial_repo_scan': 'true',
+                'app_instance_uuid': 'test',
+                'vcs_full_cache': 'false',
+                'show_revision_number': 'true',
+                'beaker.cache.sql_cache_short.expire': '1',
+                'beaker.session.secret': '{74e0cd75-b339-478b-b129-07dd221def1f}',
+                'sqlalchemy.db1.url': 'sqlite:///%(here)s/kallithea_test.sqlite',
+            },
+            '[logger_root]': {
+                'level': 'DEBUG',
+            },
+            '[logger_sqlalchemy]': {
+                'level': 'ERROR',
+                'handlers': 'console',
+            },
+            '[handler_console]': {
+                'level': 'NOTSET',
+            },
+        },
+    ),
+    ('development.ini',
+        '''
+        Kallithea - Development config:
+        listening on *:5000
+        sqlite and kallithea.db
+        initial_repo_scan = true
+        set debug = true
+        verbose and colorful logging
+
+        The %(here)s variable will be replaced with the parent directory of this file
+        ''',
+        {
+            '[server:main]': {
+                'host': '0.0.0.0',
+            },
+            '[app:main]': {
+                'initial_repo_scan': 'true',
+                'set debug': 'true',
+                'app_instance_uuid': 'development-not-secret',
+                'beaker.session.secret': 'development-not-secret',
+            },
+            '[handler_console]': {
+                'level': 'DEBUG',
+                'formatter': 'color_formatter',
+            },
+            '[handler_console_sql]': {
+                'level': 'DEBUG',
+                'formatter': 'color_formatter_sql',
+            },
+        },
+    ),
+]
+
+
+def main():
+    # make sure all mako lines starting with '#' (the '##' comments) are marked up as <text>
+    print 'reading:', makofile
+    mako_org = file(makofile).read()
+    mako_no_text_markup = re.sub(r'</?%text>', '', mako_org)
+    mako_marked_up = re.sub(r'\n(##.*)', r'\n<%text>\1</%text>', mako_no_text_markup, flags=re.MULTILINE)
+    if mako_marked_up != mako_org:
+        print 'writing:', makofile
+        file(makofile, 'w').write(mako_marked_up)
+
+    # select the right mako conditionals for the other less sophisticated formats
+    def sub_conditionals(m):
+        """given a %if...%endif match, replace with just the selected
+        conditional sections enabled and the rest as comments
+        """
+        conditional_lines = m.group(1)
+        def sub_conditional(m):
+            """given a conditional and the corresponding lines, return them raw
+            or commented out, based on whether conditional is selected
+            """
+            criteria, lines = m.groups()
+            if criteria not in selected_mako_conditionals:
+                lines = '\n'.join((l if not l or l.startswith('#') else '#' + l) for l in lines.split('\n'))
+            return lines
+        conditional_lines = re.sub(r'^%(?:el)?if (.*):\n((?:^[^%\n].*\n|\n)*)',
+            sub_conditional, conditional_lines, flags=re.MULTILINE)
+        return conditional_lines
+    mako_no_conditionals = re.sub(r'^(%if .*\n(?:[^%\n].*\n|%elif .*\n|\n)*)%endif\n',
+        sub_conditionals, mako_no_text_markup, flags=re.MULTILINE)
+
+    # expand mako variables
+    def pyrepl(m):
+        return mako_variable_values.get(m.group(1), m.group(0))
+    mako_no_variables = re.sub(r'\${([^}]*)}', pyrepl, mako_no_conditionals)
+
+    # remove utf-8 coding header
+    base_ini = re.sub(r'^## -\*- coding: utf-8 -\*-\n', '', mako_no_variables)
+
+    # create ini files
+    for fn, desc, settings in ini_files:
+        print 'updating:', fn
+        ini_lines = re.sub(
+            '# Kallithea - config file generated with kallithea-config *#\n',
+            ''.join('# %-77s#\n' % l.strip() for l in desc.strip().split('\n')),
+            base_ini)
+        def process_section(m):
+            """process a ini section, replacing values as necessary"""
+            sectionname, lines = m.groups()
+            if sectionname in settings:
+                section_settings = settings[sectionname]
+                def process_line(m):
+                    """process a section line and update value if necessary"""
+                    setting, value = m.groups()
+                    line = m.group(0)
+                    if setting in section_settings:
+                        line = '%s = %s' % (setting, section_settings[setting])
+                        if '$' not in value:
+                            line = '#%s = %s\n%s' % (setting, value, line)
+                    return line.rstrip()
+                lines = re.sub(r'^([^#\n].*) = ?(.*)', process_line, lines, flags=re.MULTILINE)
+            return sectionname + '\n' + lines
+        ini_lines = re.sub(r'^(\[.*\])\n((?:(?:[^[\n].*)?\n)*)', process_section, ini_lines, flags=re.MULTILINE)
+        file(fn, 'w').write(ini_lines)
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/logformat.py	Wed Jan 20 01:41:02 2016 +0100
@@ -0,0 +1,39 @@
+#!/usr/bin/env python2
+
+import re
+import sys
+
+if len(sys.argv) < 2:
+    print 'Cleanup of superfluous % formatting of log statements.'
+    print 'Usage:'
+    print '''  hg revert `hg loc '*.py'|grep -v logformat.py` && scripts/logformat.py `hg loc '*.py'` && hg diff'''
+    raise SystemExit(1)
+
+
+logre = r'''
+(log\.(?:error|info|warning|debug)
+[(][ \n]*
+)
+%s
+(
+[ \n]*[)]
+)
+'''
+res = [
+    # handle % () - keeping spaces around the old %
+    (re.compile(logre % r'''("[^"]*"|'[^']*')   ([\n ]*) %  ([\n ]*) \( ( (?:[^()]|\n)* (?: \( (?:[^()]|\n)* \) (?:[^()]|\n)* )* ) \) ''', flags=re.MULTILINE|re.VERBOSE), r'\1\2,\3\4\5\6'),
+    # handle % without () - keeping spaces around the old %
+    (re.compile(logre % r'''("[^"]*"|'[^']*')   ([\n ]*) %  ([\n ]*)    ( (?:[^()]|\n)* (?: \( (?:[^()]|\n)* \) (?:[^()]|\n)* )* )    ''', flags=re.MULTILINE|re.VERBOSE), r'\1\2,\3\4\5\6'),
+    # remove extra space if it is on next line
+    (re.compile(logre % r'''("[^"]*"|'[^']*') , (\n [ ]) ([ ][\n ]*)    ( (?:[^()]|\n)* (?: \( (?:[^()]|\n)* \) (?:[^()]|\n)* )* )    ''', flags=re.MULTILINE|re.VERBOSE), r'\1\2,\3\4\5\6'),
+    # remove extra space if it is on same line
+    (re.compile(logre % r'''("[^"]*"|'[^']*') , [ ]+  () (   [\n ]+)    ( (?:[^()]|\n)* (?: \( (?:[^()]|\n)* \) (?:[^()]|\n)* )* )    ''', flags=re.MULTILINE|re.VERBOSE), r'\1\2,\3\4\5\6'),
+    # remove trailing , and space
+    (re.compile(logre % r'''("[^"]*"|'[^']*') ,       () (   [\n ]*)    ( (?:[^()]|\n)* (?: \( (?:[^()]|\n)* \) (?:[^()]|\n)* )* [^(), \n] ) [ ,]*''', flags=re.MULTILINE|re.VERBOSE), r'\1\2,\3\4\5\6'),
+    ]
+
+for f in sys.argv[1:]:
+    s = file(f).read()
+    for r, t in res:
+        s = r.sub(t, s)
+    file(f, 'w').write(s)
--- a/scripts/whitespacecleanup.sh	Fri Jan 15 14:55:27 2016 +0000
+++ b/scripts/whitespacecleanup.sh	Wed Jan 20 01:41:02 2016 +0100
@@ -6,6 +6,7 @@
 
 sed -i -e "s,`printf '\t'`,    ,g" $files
 sed -i -e "s,  *$,,g" $files
+sed -i -e 's,\([^ ]\)\\$,\1 \\,g' -e 's,\(["'"'"']["'"'"']["'"'"']\) \\$,\1\\,g' $files
 # ensure one trailing newline - remove empty last line and make last line include trailing newline:
 sed -i -e '$,${/^$/d}' -e '$a\' $files