changeset 6523:3760df6251e0

model: remove BaseModel class The only remaining purpose of this class was to provide the "sa" field, allowing a custom SQLAlchemy session to be used for model operations. However, this never actually worked, nor was it used anywhere. There's always a global SQLAlchemy session associated with the current thread; using another session for a single function call does not make any sense (as sessions cannot be mixed), unless the code works carefully to ensure the two sessions (and all objects loaded from them) are kept completely separate. Suffice to say that Kallithea does no such thing, thus there's no need to pretend to support multiple concurrent sessions.
author Søren Løvborg <sorenl@unity3d.com>
date Tue, 28 Feb 2017 21:09:48 +0100
parents 6edba875451d
children d32a2218b525
files kallithea/controllers/journal.py kallithea/controllers/summary.py kallithea/lib/base.py kallithea/lib/celerylib/tasks.py kallithea/lib/db_manage.py kallithea/lib/indexers/daemon.py kallithea/lib/utils.py kallithea/model/api_key.py kallithea/model/base.py kallithea/model/changeset_status.py kallithea/model/comment.py kallithea/model/gist.py kallithea/model/notification.py kallithea/model/permission.py kallithea/model/pull_request.py kallithea/model/repo.py kallithea/model/repo_group.py kallithea/model/repo_permission.py kallithea/model/scm.py kallithea/model/user.py kallithea/model/user_group.py kallithea/tests/scripts/manual_test_concurrency.py
diffstat 22 files changed, 143 insertions(+), 173 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/journal.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/controllers/journal.py	Tue Feb 28 21:09:48 2017 +0100
@@ -95,7 +95,7 @@
         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) \
+            journal = UserLog.query() \
                 .options(joinedload(UserLog.user)) \
                 .options(joinedload(UserLog.repository))
             #filter
@@ -197,7 +197,7 @@
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
         c.user = User.get(request.authuser.user_id)
-        c.following = self.sa.query(UserFollowing) \
+        c.following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
@@ -229,7 +229,7 @@
         """
         Produce an atom-1.0 feed via feedgenerator module
         """
-        following = self.sa.query(UserFollowing) \
+        following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
@@ -241,7 +241,7 @@
         """
         Produce an rss feed via feedgenerator module
         """
-        following = self.sa.query(UserFollowing) \
+        following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
@@ -279,7 +279,7 @@
         # Return a rendered template
         p = safe_int(request.GET.get('page'), 1)
 
-        c.following = self.sa.query(UserFollowing) \
+        c.following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
@@ -300,7 +300,7 @@
         """
         Produce an atom-1.0 feed via feedgenerator module
         """
-        c.following = self.sa.query(UserFollowing) \
+        c.following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
@@ -312,7 +312,7 @@
         """
         Produce an rss2 feed via feedgenerator module
         """
-        c.following = self.sa.query(UserFollowing) \
+        c.following = UserFollowing.query() \
             .filter(UserFollowing.user_id == request.authuser.user_id) \
             .options(joinedload(UserFollowing.follows_repository)) \
             .all()
--- a/kallithea/controllers/summary.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/controllers/summary.py	Tue Feb 28 21:09:48 2017 +0100
@@ -132,7 +132,7 @@
         else:
             c.show_stats = False
 
-        stats = self.sa.query(Statistics) \
+        stats = Statistics.query() \
             .filter(Statistics.repository == c.db_repo) \
             .scalar()
 
@@ -188,7 +188,7 @@
         c.ts_min = ts_min_m
         c.ts_max = ts_max_y
 
-        stats = self.sa.query(Statistics) \
+        stats = Statistics.query() \
             .filter(Statistics.repository == c.db_repo) \
             .scalar()
         c.stats_percentage = 0
--- a/kallithea/lib/base.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/lib/base.py	Tue Feb 28 21:09:48 2017 +0100
@@ -432,8 +432,7 @@
 
         c.my_pr_count = PullRequest.query(reviewer_id=request.authuser.user_id, include_closed=False).count()
 
-        self.sa = meta.Session
-        self.scm_model = ScmModel(self.sa)
+        self.scm_model = ScmModel()
 
     @staticmethod
     def _determine_auth_user(api_key, bearer_token, session_authuser):
--- a/kallithea/lib/celerylib/tasks.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/lib/celerylib/tasks.py	Tue Feb 28 21:09:48 2017 +0100
@@ -63,11 +63,11 @@
 @celerylib.dbsession
 def whoosh_index(repo_location, full_index):
     from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
-    DBS = celerylib.get_session()
+    celerylib.get_session() # initialize database connection
 
     index_location = config['index_dir']
     WhooshIndexingDaemon(index_location=index_location,
-                         repo_location=repo_location, sa=DBS) \
+                         repo_location=repo_location) \
                          .run(full_index=full_index)
 
 
@@ -354,7 +354,7 @@
     enable_downloads = defs.get('repo_enable_downloads')
 
     try:
-        repo = RepoModel(DBS)._create_repo(
+        repo = RepoModel()._create_repo(
             repo_name=repo_name_full,
             repo_type=repo_type,
             description=description,
@@ -377,7 +377,7 @@
 
         DBS.commit()
         # now create this repo on Filesystem
-        RepoModel(DBS)._create_filesystem_repo(
+        RepoModel()._create_filesystem_repo(
             repo_name=repo_name,
             repo_type=repo_type,
             repo_group=RepoGroup.guess_instance(repo_group),
@@ -400,7 +400,7 @@
         if repo:
             Repository.delete(repo.repo_id)
             DBS.commit()
-            RepoModel(DBS)._delete_filesystem_repo(repo)
+            RepoModel()._delete_filesystem_repo(repo)
         raise
 
     return True
@@ -436,7 +436,7 @@
     try:
         fork_of = Repository.guess_instance(form_data.get('fork_parent_id'))
 
-        RepoModel(DBS)._create_repo(
+        RepoModel()._create_repo(
             repo_name=repo_name_full,
             repo_type=repo_type,
             description=form_data['description'],
@@ -456,7 +456,7 @@
         source_repo_path = os.path.join(base_path, fork_of.repo_name)
 
         # now create this repo on Filesystem
-        RepoModel(DBS)._create_filesystem_repo(
+        RepoModel()._create_filesystem_repo(
             repo_name=repo_name,
             repo_type=repo_type,
             repo_group=RepoGroup.guess_instance(repo_group),
@@ -479,7 +479,7 @@
         if repo:
             Repository.delete(repo.repo_id)
             DBS.commit()
-            RepoModel(DBS)._delete_filesystem_repo(repo)
+            RepoModel()._delete_filesystem_repo(repo)
         raise
 
     return True
--- a/kallithea/lib/db_manage.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/lib/db_manage.py	Tue Feb 28 21:09:48 2017 +0100
@@ -126,7 +126,7 @@
         Fixes a old kallithea version path into new one without a '*'
         """
 
-        paths = self.sa.query(Ui) \
+        paths = Ui.query() \
                 .filter(Ui.ui_key == '/') \
                 .scalar()
 
@@ -139,7 +139,7 @@
         Fixes a old default user with some 'nicer' default values,
         used mostly for anonymous access
         """
-        def_user = self.sa.query(User).filter_by(is_default_user=True).one()
+        def_user = User.query().filter_by(is_default_user=True).one()
 
         def_user.name = 'Anonymous'
         def_user.lastname = 'User'
@@ -214,7 +214,7 @@
 
         #HOOKS
         hooks1_key = Ui.HOOK_UPDATE
-        hooks1_ = self.sa.query(Ui) \
+        hooks1_ = Ui.query() \
             .filter(Ui.ui_key == hooks1_key).scalar()
 
         hooks1 = Ui() if hooks1_ is None else hooks1_
@@ -225,7 +225,7 @@
         self.sa.add(hooks1)
 
         hooks2_key = Ui.HOOK_REPO_SIZE
-        hooks2_ = self.sa.query(Ui) \
+        hooks2_ = Ui.query() \
             .filter(Ui.ui_key == hooks2_key).scalar()
         hooks2 = Ui() if hooks2_ is None else hooks2_
         hooks2.ui_section = 'hooks'
@@ -482,7 +482,7 @@
         # module.(access|create|change|delete)_[name]
         # module.(none|read|write|admin)
         log.info('creating permissions')
-        PermissionModel(self.sa).create_permissions()
+        PermissionModel().create_permissions()
 
     def populate_default_permissions(self):
         """
@@ -490,4 +490,4 @@
         permissions that are missing, and not alter already defined ones
         """
         log.info('creating default user permissions')
-        PermissionModel(self.sa).create_default_permissions(user=User.DEFAULT_USER)
+        PermissionModel().create_default_permissions(user=User.DEFAULT_USER)
--- a/kallithea/lib/indexers/daemon.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/lib/indexers/daemon.py	Tue Feb 28 21:09:48 2017 +0100
@@ -63,7 +63,7 @@
     """
 
     def __init__(self, indexname=IDX_NAME, index_location=None,
-                 repo_location=None, sa=None, repo_list=None,
+                 repo_location=None, repo_list=None,
                  repo_update_list=None):
         self.indexname = indexname
 
@@ -75,7 +75,7 @@
         if not repo_location:
             raise Exception('You have to provide repositories location')
 
-        self.repo_paths = ScmModel(sa).repo_scan(self.repo_location)
+        self.repo_paths = ScmModel().repo_scan(self.repo_location)
 
         #filter repo list
         if repo_list:
--- a/kallithea/lib/utils.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/lib/utils.py	Tue Feb 28 21:09:48 2017 +0100
@@ -430,7 +430,7 @@
 
     # last element is repo in nested groups structure
     groups = groups[:-1]
-    rgm = RepoGroupModel(sa)
+    rgm = RepoGroupModel()
     owner = User.get_first_admin()
     for lvl, group_name in enumerate(groups):
         group_name = u'/'.join(groups[:lvl] + [group_name])
@@ -531,7 +531,7 @@
                 log.debug("Removing non-existing repository found in db `%s`",
                           repo.repo_name)
                 try:
-                    RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
+                    RepoModel().delete(repo, forks='detach', fs_remove=False)
                     sa.commit()
                 except Exception:
                     #don't hold further removals on error
--- a/kallithea/model/api_key.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/api_key.py	Tue Feb 28 21:09:48 2017 +0100
@@ -29,14 +29,13 @@
 import logging
 
 from kallithea.lib.utils2 import generate_api_key
-from kallithea.model.base import BaseModel
 from kallithea.model.db import User, UserApiKeys
 from kallithea.model.meta import Session
 
 log = logging.getLogger(__name__)
 
 
-class ApiKeyModel(BaseModel):
+class ApiKeyModel(object):
 
     def create(self, user, description, lifetime=-1):
         """
--- a/kallithea/model/base.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/base.py	Tue Feb 28 21:09:48 2017 +0100
@@ -44,18 +44,3 @@
     engine_str = obfuscate_url_pw(str(engine.url))
     log.info("initializing db for %s", engine_str)
     meta.Base.metadata.bind = engine
-
-
-class BaseModel(object):
-    """
-    Base Model for all Kallithea models, it adds sql alchemy session
-    into instance of model
-
-    :param sa: If passed it reuses this session instead of creating a new one
-    """
-
-    def __init__(self, sa=None):
-        if sa is not None:
-            self.sa = sa
-        else:
-            self.sa = meta.Session()
--- a/kallithea/model/changeset_status.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/changeset_status.py	Tue Feb 28 21:09:48 2017 +0100
@@ -28,14 +28,13 @@
 import logging
 from sqlalchemy.orm import joinedload
 
-from kallithea.model.base import BaseModel
-from kallithea.model.db import ChangesetStatus, PullRequest, Repository, User
+from kallithea.model.db import ChangesetStatus, PullRequest, Repository, User, Session
 from kallithea.lib.exceptions import StatusChangeOnClosedPullRequestError
 
 log = logging.getLogger(__name__)
 
 
-class ChangesetStatusModel(BaseModel):
+class ChangesetStatusModel(object):
 
     def _get_status_query(self, repo, revision, pull_request,
                           with_revisions=False):
@@ -190,5 +189,5 @@
             new_status.revision = rev
             new_status.pull_request = pull_request
             new_statuses.append(new_status)
-            self.sa.add(new_status)
+            Session().add(new_status)
         return new_statuses
--- a/kallithea/model/comment.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/comment.py	Tue Feb 28 21:09:48 2017 +0100
@@ -32,7 +32,6 @@
 
 from kallithea.lib.utils2 import extract_mentioned_users, safe_unicode
 from kallithea.lib import helpers as h
-from kallithea.model.base import BaseModel
 from kallithea.model.db import ChangesetComment, User, \
     Notification, PullRequest, Repository
 from kallithea.model.notification import NotificationModel
@@ -54,7 +53,7 @@
         .all())
 
 
-class ChangesetCommentsModel(BaseModel):
+class ChangesetCommentsModel(object):
 
     def _get_notification_data(self, repo, comment, author, comment_text,
                                line_no=None, revision=None, pull_request=None,
--- a/kallithea/model/gist.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/gist.py	Tue Feb 28 21:09:48 2017 +0100
@@ -35,8 +35,7 @@
 from kallithea.lib.utils2 import safe_unicode, safe_int, \
     time_to_datetime, AttributeDict
 from kallithea.lib.compat import json
-from kallithea.model.base import BaseModel
-from kallithea.model.db import Gist, User
+from kallithea.model.db import Gist, Session, User
 from kallithea.model.repo import RepoModel
 from kallithea.model.scm import ScmModel
 
@@ -54,7 +53,7 @@
     return u''.join(rnd.choice(alphabet) for _ in xrange(length))
 
 
-class GistModel(BaseModel):
+class GistModel(object):
 
     def __delete_gist(self, gist):
         """
@@ -122,8 +121,8 @@
         gist.owner_id = owner.user_id
         gist.gist_expires = gist_expires
         gist.gist_type = safe_unicode(gist_type)
-        self.sa.add(gist)
-        self.sa.flush() # make database assign gist.gist_id
+        Session().add(gist)
+        Session().flush() # make database assign gist.gist_id
         if gist_type == Gist.GIST_PUBLIC:
             # use DB ID for easy to use GIST ID
             gist_id = safe_unicode(gist.gist_id)
@@ -173,7 +172,7 @@
     def delete(self, gist, fs_remove=True):
         gist = Gist.guess_instance(gist)
         try:
-            self.sa.delete(gist)
+            Session().delete(gist)
             if fs_remove:
                 self.__delete_gist(gist)
             else:
--- a/kallithea/model/notification.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/notification.py	Tue Feb 28 21:09:48 2017 +0100
@@ -36,14 +36,13 @@
 import kallithea
 from kallithea.lib import helpers as h
 from kallithea.lib.utils2 import safe_unicode
-from kallithea.model.base import BaseModel
 from kallithea.model.db import Notification, User, UserNotification
 from kallithea.model.meta import Session
 
 log = logging.getLogger(__name__)
 
 
-class NotificationModel(BaseModel):
+class NotificationModel(object):
 
     def create(self, created_by, subject, body, recipients=None,
                type_=Notification.TYPE_MESSAGE, with_email=True,
@@ -262,7 +261,7 @@
                 )
 
 
-class EmailNotificationModel(BaseModel):
+class EmailNotificationModel(object):
 
     TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
     TYPE_MESSAGE = Notification.TYPE_MESSAGE # only used for testing
--- a/kallithea/model/permission.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/permission.py	Tue Feb 28 21:09:48 2017 +0100
@@ -31,15 +31,14 @@
 
 from sqlalchemy.exc import DatabaseError
 
-from kallithea.model.base import BaseModel
-from kallithea.model.db import User, Permission, UserToPerm, UserRepoToPerm, \
-    UserRepoGroupToPerm, UserUserGroupToPerm
+from kallithea.model.db import Permission, Session, User, \
+    UserToPerm, UserRepoToPerm, UserRepoGroupToPerm, UserUserGroupToPerm
 from kallithea.lib.utils2 import str2bool
 
 log = logging.getLogger(__name__)
 
 
-class PermissionModel(BaseModel):
+class PermissionModel(object):
     """
     Permissions model for Kallithea
     """
@@ -52,7 +51,7 @@
             if not Permission.get_by_key(p[0]):
                 new_perm = Permission()
                 new_perm.permission_name = p[0]
-                self.sa.add(new_perm)
+                Session().add(new_perm)
 
     def create_default_permissions(self, user, force=False):
         """
@@ -81,8 +80,8 @@
 
         if force:
             for perm in perms:
-                self.sa.delete(perm)
-            self.sa.commit()
+                Session().delete(perm)
+            Session().commit()
             defined_perms_groups = []
         # For every default permission that needs to be created, we check if
         # its group is already defined. If it's not, we create default permission.
@@ -92,7 +91,7 @@
                 log.debug('GR:%s not found, creating permission %s',
                           gr, perm_name)
                 new_perm = _make_perm(perm_name)
-                self.sa.add(new_perm)
+                Session().add(new_perm)
 
     def update(self, form_result):
         perm_user = User.get_by_username(username=form_result['perm_user_name'])
@@ -112,11 +111,11 @@
             # 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) \
+            u2p = UserToPerm.query() \
                 .filter(UserToPerm.user == perm_user) \
                 .all()
             for p in u2p:
-                self.sa.delete(p)
+                Session().delete(p)
             #create fresh set of permissions
             for def_perm_key in ['default_repo_perm',
                                  'default_group_perm',
@@ -129,14 +128,14 @@
                                  'default_register',
                                  'default_extern_activate']:
                 p = _make_new(perm_user, form_result[def_perm_key])
-                self.sa.add(p)
+                Session().add(p)
 
             #stage 3 update all default permissions for repos if checked
             if form_result['overwrite_default_repo']:
                 _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) \
+                for r2p in UserRepoToPerm.query() \
                                .filter(UserRepoToPerm.user == perm_user) \
                                .all():
 
@@ -148,7 +147,7 @@
                 _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) \
+                for g2p in UserRepoGroupToPerm.query() \
                                .filter(UserRepoGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
@@ -157,13 +156,13 @@
                 _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) \
+                for g2p in UserUserGroupToPerm.query() \
                                .filter(UserUserGroupToPerm.user == perm_user) \
                                .all():
                     g2p.permission = _def
 
-            self.sa.commit()
+            Session().commit()
         except (DatabaseError,):
             log.error(traceback.format_exc())
-            self.sa.rollback()
+            Session().rollback()
             raise
--- a/kallithea/model/pull_request.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/pull_request.py	Tue Feb 28 21:09:48 2017 +0100
@@ -35,7 +35,6 @@
 from kallithea.model.meta import Session
 from kallithea.lib import helpers as h
 from kallithea.lib.exceptions import UserInvalidException
-from kallithea.model.base import BaseModel
 from kallithea.model.db import PullRequest, PullRequestReviewer, Notification, \
     ChangesetStatus, User
 from kallithea.model.notification import NotificationModel
@@ -45,7 +44,7 @@
 log = logging.getLogger(__name__)
 
 
-class PullRequestModel(BaseModel):
+class PullRequestModel(object):
 
     def _get_valid_reviewers(self, seq):
         """ Generate User objects from a sequence of user IDs, usernames or
--- a/kallithea/model/repo.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/repo.py	Tue Feb 28 21:09:48 2017 +0100
@@ -41,9 +41,8 @@
 from kallithea.lib.caching_query import FromCache
 from kallithea.lib.hooks import log_delete_repository
 
-from kallithea.model.base import BaseModel
 from kallithea.model.db import Repository, UserRepoToPerm, UserGroupRepoToPerm, \
-    UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission, \
+    UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission, Session, \
     Statistics, UserGroup, Ui, RepoGroup, RepositoryField
 
 from kallithea.lib import helpers as h
@@ -54,7 +53,7 @@
 log = logging.getLogger(__name__)
 
 
-class RepoModel(BaseModel):
+class RepoModel(object):
 
     URL_SEPARATOR = Repository.url_sep()
 
@@ -74,7 +73,7 @@
 
         repo_to_perm.repository = repository
         repo_to_perm.user_id = def_user.user_id
-        self.sa.add(repo_to_perm)
+        Session().add(repo_to_perm)
 
         return repo_to_perm
 
@@ -84,11 +83,11 @@
         Gets the repositories root path from database
         """
 
-        q = self.sa.query(Ui).filter(Ui.ui_key == '/').one()
+        q = Ui.query().filter(Ui.ui_key == '/').one()
         return q.ui_value
 
     def get(self, repo_id, cache=False):
-        repo = self.sa.query(Repository) \
+        repo = Repository.query() \
             .filter(Repository.repo_id == repo_id)
 
         if cache:
@@ -100,7 +99,7 @@
         return Repository.guess_instance(repository)
 
     def get_by_repo_name(self, repo_name, cache=False):
-        repo = self.sa.query(Repository) \
+        repo = Repository.query() \
             .filter(Repository.repo_name == repo_name)
 
         if cache:
@@ -124,7 +123,7 @@
         return Repository.query().filter(Repository.repo_name.in_(repos))
 
     def get_users_js(self):
-        users = self.sa.query(User) \
+        users = User.query() \
             .filter(User.active == True) \
             .order_by(User.name, User.lastname) \
             .all()
@@ -140,7 +139,7 @@
         )
 
     def get_user_groups_js(self):
-        user_groups = self.sa.query(UserGroup) \
+        user_groups = UserGroup.query() \
             .filter(UserGroup.users_group_active == True) \
             .order_by(UserGroup.users_group_name) \
             .options(subqueryload(UserGroup.members)) \
@@ -391,7 +390,7 @@
                 parent_repo = fork_of
                 new_repo.fork = parent_repo
 
-            self.sa.add(new_repo)
+            Session().add(new_repo)
 
             if fork_of and copy_fork_permissions:
                 repo = fork_of
@@ -429,11 +428,10 @@
                 self._create_default_perms(new_repo, private)
 
             # now automatically start following this repository as owner
-            ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
-                                                    owner.user_id)
+            ScmModel().toggle_following_repo(new_repo.repo_id, owner.user_id)
             # we need to flush here, in order to check if database won't
             # throw any exceptions, create filesystem dirs at the very end
-            self.sa.flush()
+            Session().flush()
             return new_repo
         except Exception:
             log.error(traceback.format_exc())
@@ -517,7 +515,7 @@
 
             old_repo_dict = repo.get_dict()
             try:
-                self.sa.delete(repo)
+                Session().delete(repo)
                 if fs_remove:
                     self._delete_filesystem_repo(repo)
                 else:
@@ -542,14 +540,14 @@
         permission = Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserRepoToPerm) \
+        obj = UserRepoToPerm.query() \
             .filter(UserRepoToPerm.user == user) \
             .filter(UserRepoToPerm.repository == repo) \
             .scalar()
         if obj is None:
             # create new !
             obj = UserRepoToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
         obj.repository = repo
         obj.user = user
         obj.permission = permission
@@ -567,12 +565,12 @@
         user = User.guess_instance(user)
         repo = Repository.guess_instance(repo)
 
-        obj = self.sa.query(UserRepoToPerm) \
+        obj = UserRepoToPerm.query() \
             .filter(UserRepoToPerm.repository == repo) \
             .filter(UserRepoToPerm.user == user) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm on %s on %s', repo, user)
 
     def grant_user_group_permission(self, repo, group_name, perm):
@@ -590,7 +588,7 @@
         permission = Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserGroupRepoToPerm) \
+        obj = UserGroupRepoToPerm.query() \
             .filter(UserGroupRepoToPerm.users_group == group_name) \
             .filter(UserGroupRepoToPerm.repository == repo) \
             .scalar()
@@ -598,7 +596,7 @@
         if obj is None:
             # create new
             obj = UserGroupRepoToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
 
         obj.repository = repo
         obj.users_group = group_name
@@ -617,12 +615,12 @@
         repo = Repository.guess_instance(repo)
         group_name = UserGroup.guess_instance(group_name)
 
-        obj = self.sa.query(UserGroupRepoToPerm) \
+        obj = UserGroupRepoToPerm.query() \
             .filter(UserGroupRepoToPerm.repository == repo) \
             .filter(UserGroupRepoToPerm.users_group == group_name) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm to %s on %s', repo, group_name)
 
     def delete_stats(self, repo_name):
@@ -633,10 +631,10 @@
         """
         repo = Repository.guess_instance(repo_name)
         try:
-            obj = self.sa.query(Statistics) \
+            obj = Statistics.query() \
                 .filter(Statistics.repository == repo).scalar()
             if obj is not None:
-                self.sa.delete(obj)
+                Session().delete(obj)
         except Exception:
             log.error(traceback.format_exc())
             raise
--- a/kallithea/model/repo_group.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/repo_group.py	Tue Feb 28 21:09:48 2017 +0100
@@ -34,14 +34,13 @@
 
 from kallithea.lib.utils2 import LazyProperty
 
-from kallithea.model.base import BaseModel
-from kallithea.model.db import RepoGroup, Ui, UserRepoGroupToPerm, \
+from kallithea.model.db import RepoGroup, Session, Ui, UserRepoGroupToPerm, \
     User, Permission, UserGroupRepoGroupToPerm, UserGroup, Repository
 
 log = logging.getLogger(__name__)
 
 
-class RepoGroupModel(BaseModel):
+class RepoGroupModel(object):
 
     @LazyProperty
     def repos_path(self):
@@ -66,7 +65,7 @@
 
         repo_group_to_perm.group = new_group
         repo_group_to_perm.user_id = def_user.user_id
-        self.sa.add(repo_group_to_perm)
+        Session().add(repo_group_to_perm)
         return repo_group_to_perm
 
     def _create_group(self, group_name):
@@ -144,7 +143,7 @@
             new_repo_group.parent_group = parent_group
             new_repo_group.group_name = new_repo_group.get_new_name(group_name)
 
-            self.sa.add(new_repo_group)
+            Session().add(new_repo_group)
 
             # create an ADMIN permission for owner except if we're super admin,
             # later owner should go into the owner field of groups
@@ -175,7 +174,7 @@
             if not just_db:
                 # we need to flush here, in order to check if database won't
                 # throw any exceptions, create filesystem dirs at the very end
-                self.sa.flush()
+                Session().flush()
                 self._create_group(new_repo_group.group_name)
 
             return new_repo_group
@@ -288,7 +287,7 @@
             repo_group.parent_group = RepoGroup.get(form_data['parent_group_id'])
             repo_group.group_name = repo_group.get_new_name(form_data['group_name'])
             new_path = repo_group.full_path
-            self.sa.add(repo_group)
+            Session().add(repo_group)
 
             # iterate over all members of this groups and do fixes
             # set locking if given
@@ -322,7 +321,7 @@
     def delete(self, repo_group, force_delete=False):
         repo_group = RepoGroup.guess_instance(repo_group)
         try:
-            self.sa.delete(repo_group)
+            Session().delete(repo_group)
             self._delete_group(repo_group, force_delete)
         except Exception:
             log.error('Error removing repo_group %s', repo_group)
@@ -444,14 +443,14 @@
         permission = Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserRepoGroupToPerm) \
+        obj = UserRepoGroupToPerm.query() \
             .filter(UserRepoGroupToPerm.user == user) \
             .filter(UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is None:
             # create new !
             obj = UserRepoGroupToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
         obj.group = repo_group
         obj.user = user
         obj.permission = permission
@@ -470,12 +469,12 @@
         repo_group = RepoGroup.guess_instance(repo_group)
         user = User.guess_instance(user)
 
-        obj = self.sa.query(UserRepoGroupToPerm) \
+        obj = UserRepoGroupToPerm.query() \
             .filter(UserRepoGroupToPerm.user == user) \
             .filter(UserRepoGroupToPerm.group == repo_group) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm on %s on %s', repo_group, user)
 
     def grant_user_group_permission(self, repo_group, group_name, perm):
@@ -494,7 +493,7 @@
         permission = Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserGroupRepoGroupToPerm) \
+        obj = UserGroupRepoGroupToPerm.query() \
             .filter(UserGroupRepoGroupToPerm.group == repo_group) \
             .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
@@ -502,7 +501,7 @@
         if obj is None:
             # create new
             obj = UserGroupRepoGroupToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
 
         obj.group = repo_group
         obj.users_group = group_name
@@ -522,10 +521,10 @@
         repo_group = RepoGroup.guess_instance(repo_group)
         group_name = UserGroup.guess_instance(group_name)
 
-        obj = self.sa.query(UserGroupRepoGroupToPerm) \
+        obj = UserGroupRepoGroupToPerm.query() \
             .filter(UserGroupRepoGroupToPerm.group == repo_group) \
             .filter(UserGroupRepoGroupToPerm.users_group == group_name) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm to %s on %s', repo_group, group_name)
--- a/kallithea/model/repo_permission.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/repo_permission.py	Tue Feb 28 21:09:48 2017 +0100
@@ -24,14 +24,13 @@
 """
 
 import logging
-from kallithea.model.base import BaseModel
 from kallithea.model.db import User, UserRepoToPerm, UserGroupRepoToPerm, \
-    Permission, Repository
+    Permission, Repository, Session
 
 log = logging.getLogger(__name__)
 
 
-class RepositoryPermissionModel(BaseModel):
+class RepositoryPermissionModel(object):
 
     def get_user_permission(self, repository, user):
         repository = Repository.guess_instance(repository)
@@ -53,12 +52,12 @@
             p.user = user
             p.repository = repository
             p.permission = permission
-            self.sa.add(p)
+            Session().add(p)
 
     def delete_user_permission(self, repository, user):
         current = self.get_user_permission(repository, user)
         if current:
-            self.sa.delete(current)
+            Session().delete(current)
 
     def get_users_group_permission(self, repository, users_group):
         return UserGroupRepoToPerm.query() \
@@ -78,12 +77,12 @@
             p.users_group = users_group
             p.repository = repository
             p.permission = permission
-            self.sa.add(p)
+            Session().add(p)
 
     def delete_users_group_permission(self, repository, users_group):
         current = self.get_users_group_permission(repository, users_group)
         if current:
-            self.sa.delete(current)
+            Session().delete(current)
 
     def update_or_delete_user_permission(self, repository, user, permission):
         if permission:
--- a/kallithea/model/scm.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/scm.py	Tue Feb 28 21:09:48 2017 +0100
@@ -53,8 +53,7 @@
     HasUserGroupPermissionLevel, HasPermissionAny, HasPermissionAny
 from kallithea.lib.utils import get_filesystem_repos, make_ui, \
     action_logger
-from kallithea.model.base import BaseModel
-from kallithea.model.db import Repository, Ui, CacheInvalidation, \
+from kallithea.model.db import Repository, Session, Ui, CacheInvalidation, \
     UserFollowing, UserLog, User, RepoGroup, PullRequest
 from kallithea.lib.hooks import log_push_action
 from kallithea.lib.exceptions import NonRelativePathError, IMCCommitError
@@ -139,7 +138,7 @@
                     extra_kwargs=extra_kwargs)
 
 
-class ScmModel(BaseModel):
+class ScmModel(object):
     """
     Generic Scm Model
     """
@@ -162,7 +161,7 @@
         Gets the repositories root path from database
         """
 
-        q = self.sa.query(Ui).filter(Ui.ui_key == '/').one()
+        q = Ui.query().filter(Ui.ui_key == '/').one()
 
         return q.ui_value
 
@@ -231,13 +230,13 @@
 
     def toggle_following_repo(self, follow_repo_id, user_id):
 
-        f = self.sa.query(UserFollowing) \
+        f = UserFollowing.query() \
             .filter(UserFollowing.follows_repository_id == follow_repo_id) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
             try:
-                self.sa.delete(f)
+                Session().delete(f)
                 action_logger(UserTemp(user_id),
                               'stopped_following_repo',
                               RepoTemp(follow_repo_id))
@@ -250,7 +249,7 @@
             f = UserFollowing()
             f.user_id = user_id
             f.follows_repository_id = follow_repo_id
-            self.sa.add(f)
+            Session().add(f)
 
             action_logger(UserTemp(user_id),
                           'started_following_repo',
@@ -260,13 +259,13 @@
             raise
 
     def toggle_following_user(self, follow_user_id, user_id):
-        f = self.sa.query(UserFollowing) \
+        f = UserFollowing.query() \
             .filter(UserFollowing.follows_user_id == follow_user_id) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
         if f is not None:
             try:
-                self.sa.delete(f)
+                Session().delete(f)
                 return
             except Exception:
                 log.error(traceback.format_exc())
@@ -276,16 +275,16 @@
             f = UserFollowing()
             f.user_id = user_id
             f.follows_user_id = follow_user_id
-            self.sa.add(f)
+            Session().add(f)
         except Exception:
             log.error(traceback.format_exc())
             raise
 
     def is_following_repo(self, repo_name, user_id, cache=False):
-        r = self.sa.query(Repository) \
+        r = Repository.query() \
             .filter(Repository.repo_name == repo_name).scalar()
 
-        f = self.sa.query(UserFollowing) \
+        f = UserFollowing.query() \
             .filter(UserFollowing.follows_repository == r) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
@@ -294,7 +293,7 @@
     def is_following_user(self, username, user_id, cache=False):
         u = User.get_by_username(username)
 
-        f = self.sa.query(UserFollowing) \
+        f = UserFollowing.query() \
             .filter(UserFollowing.follows_user == u) \
             .filter(UserFollowing.user_id == user_id).scalar()
 
@@ -303,17 +302,17 @@
     def get_followers(self, repo):
         repo = Repository.guess_instance(repo)
 
-        return self.sa.query(UserFollowing) \
+        return UserFollowing.query() \
                 .filter(UserFollowing.follows_repository == repo).count()
 
     def get_forks(self, repo):
         repo = Repository.guess_instance(repo)
-        return self.sa.query(Repository) \
+        return Repository.query() \
                 .filter(Repository.fork == repo).count()
 
     def get_pull_requests(self, repo):
         repo = Repository.guess_instance(repo)
-        return self.sa.query(PullRequest) \
+        return PullRequest.query() \
                 .filter(PullRequest.other_repo == repo) \
                 .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
 
@@ -682,7 +681,7 @@
         return tip
 
     def get_unread_journal(self):
-        return self.sa.query(UserLog).count()
+        return UserLog.query().count()
 
     def get_repo_landing_revs(self, repo=None):
         """
--- a/kallithea/model/user.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/user.py	Tue Feb 28 21:09:48 2017 +0100
@@ -39,7 +39,6 @@
 
 from kallithea.lib.utils2 import safe_str, generate_api_key, get_current_authuser
 from kallithea.lib.caching_query import FromCache
-from kallithea.model.base import BaseModel
 from kallithea.model.db import Permission, User, UserToPerm, Notification, \
     UserEmailMap, UserIpMap
 from kallithea.lib.exceptions import DefaultUserException, \
@@ -50,11 +49,11 @@
 log = logging.getLogger(__name__)
 
 
-class UserModel(BaseModel):
+class UserModel(object):
     password_reset_token_lifetime = 86400 # 24 hours
 
     def get(self, user_id, cache=False):
-        user = self.sa.query(User)
+        user = User.query()
         if cache:
             user = user.options(FromCache("sql_cache_short",
                                           "get_user_%s" % user_id))
@@ -271,7 +270,7 @@
                 _('User "%s" still owns %s user groups and cannot be '
                   'removed. Switch owners or remove those user groups: %s')
                 % (user.username, len(usergroups), ', '.join(usergroups)))
-        self.sa.delete(user)
+        Session().delete(user)
 
         from kallithea.lib.hooks import log_delete_user
         log_delete_user(user.get_dict(), cur_user)
@@ -443,7 +442,7 @@
         new = UserToPerm()
         new.user = user
         new.permission = perm
-        self.sa.add(new)
+        Session().add(new)
         return new
 
     def revoke_perm(self, user, perm):
@@ -476,7 +475,7 @@
         obj = UserEmailMap()
         obj.user = user
         obj.email = data['email']
-        self.sa.add(obj)
+        Session().add(obj)
         return obj
 
     def delete_extra_email(self, user, email_id):
@@ -489,7 +488,7 @@
         user = User.guess_instance(user)
         obj = UserEmailMap.query().get(email_id)
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
 
     def add_extra_ip(self, user, ip):
         """
@@ -506,7 +505,7 @@
         obj = UserIpMap()
         obj.user = user
         obj.ip_addr = data['ip']
-        self.sa.add(obj)
+        Session().add(obj)
         return obj
 
     def delete_extra_ip(self, user, ip_id):
@@ -519,4 +518,4 @@
         user = User.guess_instance(user)
         obj = UserIpMap.query().get(ip_id)
         if obj:
-            self.sa.delete(obj)
+            Session().delete(obj)
--- a/kallithea/model/user_group.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/model/user_group.py	Tue Feb 28 21:09:48 2017 +0100
@@ -27,8 +27,7 @@
 import logging
 import traceback
 
-from kallithea.model.base import BaseModel
-from kallithea.model.db import UserGroupMember, UserGroup, \
+from kallithea.model.db import Session, UserGroupMember, UserGroup, \
     UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm, \
     UserGroupUserGroupToPerm
 from kallithea.lib.exceptions import UserGroupsAssignedException, \
@@ -37,7 +36,7 @@
 log = logging.getLogger(__name__)
 
 
-class UserGroupModel(BaseModel):
+class UserGroupModel(object):
 
     def _create_default_perms(self, user_group):
         # create default permission
@@ -53,7 +52,7 @@
 
         user_group_to_perm.user_group = user_group
         user_group_to_perm.user_id = def_user.user_id
-        self.sa.add(user_group_to_perm)
+        Session().add(user_group_to_perm)
         return user_group_to_perm
 
     def _update_permissions(self, user_group, perms_new=None,
@@ -108,7 +107,7 @@
             new_user_group.users_group_active = active
             if group_data:
                 new_user_group.group_data = group_data
-            self.sa.add(new_user_group)
+            Session().add(new_user_group)
             self._create_default_perms(new_user_group)
 
             self.grant_user_permission(user_group=new_user_group,
@@ -132,13 +131,13 @@
                         for u_id in set(v):
                             member = UserGroupMember(user_group.users_group_id, u_id)
                             members_list.append(member)
-                            self.sa.add(member)
+                            Session().add(member)
                     user_group.members = members_list
                 setattr(user_group, k, v)
 
             # Flush to make db assign users_group_member_id to newly
             # created UserGroupMembers.
-            self.sa.flush()
+            Session().flush()
         except Exception:
             log.error(traceback.format_exc())
             raise
@@ -162,7 +161,7 @@
             if assigned_groups and not force:
                 raise UserGroupsAssignedException(
                     'User Group assigned to %s' % ", ".join(assigned_groups))
-            self.sa.delete(user_group)
+            Session().delete(user_group)
         except Exception:
             log.error(traceback.format_exc())
             raise
@@ -185,7 +184,7 @@
             user_group.members.append(user_group_member)
             user.group_member.append(user_group_member)
 
-            self.sa.add(user_group_member)
+            Session().add(user_group_member)
             return user_group_member
         except Exception:
             log.error(traceback.format_exc())
@@ -204,7 +203,7 @@
 
         if user_group_member:
             try:
-                self.sa.delete(user_group_member)
+                Session().delete(user_group_member)
                 return True
             except Exception:
                 log.error(traceback.format_exc())
@@ -236,7 +235,7 @@
         new = UserGroupToPerm()
         new.users_group = user_group
         new.permission = perm
-        self.sa.add(new)
+        Session().add(new)
         return new
 
     def revoke_perm(self, user_group, perm):
@@ -247,7 +246,7 @@
             .filter(UserGroupToPerm.users_group == user_group) \
             .filter(UserGroupToPerm.permission == perm).scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
 
     def grant_user_permission(self, user_group, user, perm):
         """
@@ -265,14 +264,14 @@
         permission = Permission.guess_instance(perm)
 
         # check if we have that permission already
-        obj = self.sa.query(UserUserGroupToPerm) \
+        obj = UserUserGroupToPerm.query() \
             .filter(UserUserGroupToPerm.user == user) \
             .filter(UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
             obj = UserUserGroupToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
         obj.user_group = user_group
         obj.user = user
         obj.permission = permission
@@ -291,12 +290,12 @@
         user_group = UserGroup.guess_instance(user_group)
         user = User.guess_instance(user)
 
-        obj = self.sa.query(UserUserGroupToPerm) \
+        obj = UserUserGroupToPerm.query() \
             .filter(UserUserGroupToPerm.user == user) \
             .filter(UserUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm on %s on %s', user_group, user)
 
     def grant_user_group_permission(self, target_user_group, user_group, perm):
@@ -316,14 +315,14 @@
                                            'assigned to itself' % target_user_group)
 
         # check if we have that permission already
-        obj = self.sa.query(UserGroupUserGroupToPerm) \
+        obj = UserGroupUserGroupToPerm.query() \
             .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
             .filter(UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is None:
             # create new !
             obj = UserGroupUserGroupToPerm()
-            self.sa.add(obj)
+            Session().add(obj)
         obj.user_group = user_group
         obj.target_user_group = target_user_group
         obj.permission = permission
@@ -340,12 +339,12 @@
         target_user_group = UserGroup.guess_instance(target_user_group)
         user_group = UserGroup.guess_instance(user_group)
 
-        obj = self.sa.query(UserGroupUserGroupToPerm) \
+        obj = UserGroupUserGroupToPerm.query() \
             .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group) \
             .filter(UserGroupUserGroupToPerm.user_group == user_group) \
             .scalar()
         if obj is not None:
-            self.sa.delete(obj)
+            Session().delete(obj)
             log.debug('Revoked perm on %s on %s', target_user_group, user_group)
 
     def enforce_groups(self, user, groups, extern_type=None):
--- a/kallithea/tests/scripts/manual_test_concurrency.py	Mon Feb 27 20:36:49 2017 +0100
+++ b/kallithea/tests/scripts/manual_test_concurrency.py	Tue Feb 28 21:09:48 2017 +0100
@@ -135,7 +135,7 @@
                      'repo_type': 'hg',
                      'private':False,
                      'clone_uri': '' }
-        rm = RepoModel(sa)
+        rm = RepoModel()
         rm.base_path = '/home/hg'
         rm.create(form_data, user)