You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2019/03/27 21:03:11 UTC

[allura] branch db/8273 created (now c61442a)

This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a change to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git.


      at c61442a  [#8273] Upgrade TG 2.3.1

This branch includes the following new commits:

     new 330ab36  [#8273] upgrade TG 2.2.2 webob 1.1.1
     new cbe6b8b  [#8273] Upgrade TG 2.3.0 Webob 1.3.1: pylons imports, some registry stuff, etc
     new a7cbe67  [#8273] TG 2.3.0: root override; appconfig
     new cecff40  [#8273] TG 2.3.0: small test fixes
     new 296bcdd  [#8273] TG 2.3.0: root controller is only init'd once, so move dynamic code to _lookup; basetestroot now gives precedence to full root-based urls
     new 4dbf351  [#8273] TG 2.3.0: root controller single-run fix for oauth
     new e223aa5  [#8273] TG 2.3.0: signature of TGController.__call__ changed
     new c61442a  [#8273] Upgrade TG 2.3.1

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[allura] 02/08: [#8273] Upgrade TG 2.3.0 Webob 1.3.1: pylons imports, some registry stuff, etc

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit cbe6b8b8799cf9d339eb5ea7d318b8533b7408de
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Wed Mar 20 15:31:52 2019 -0400

    [#8273] Upgrade TG 2.3.0 Webob 1.3.1: pylons imports, some registry stuff, etc
---
 Allura/allura/__init__.py                          |  2 +-
 Allura/allura/app.py                               |  2 +-
 Allura/allura/command/base.py                      | 21 ++++----
 Allura/allura/command/reclone_repo.py              |  2 +-
 Allura/allura/command/script.py                    |  6 +--
 Allura/allura/command/show_models.py               |  2 +-
 Allura/allura/command/taskd.py                     |  3 +-
 Allura/allura/config/app_cfg.py                    |  9 ++--
 Allura/allura/config/environment.py                |  4 --
 Allura/allura/config/middleware.py                 | 16 +++---
 Allura/allura/controllers/auth.py                  |  4 +-
 Allura/allura/controllers/base.py                  |  2 +-
 Allura/allura/controllers/basetest_project_root.py |  7 +--
 Allura/allura/controllers/discuss.py               |  2 +-
 Allura/allura/controllers/feed.py                  |  2 +-
 Allura/allura/controllers/project.py               |  2 +-
 Allura/allura/controllers/repository.py            |  4 +-
 Allura/allura/controllers/rest.py                  |  4 +-
 Allura/allura/controllers/root.py                  |  7 +--
 Allura/allura/controllers/search.py                |  2 +-
 Allura/allura/controllers/site_admin.py            |  6 +--
 Allura/allura/controllers/static.py                |  2 +-
 Allura/allura/controllers/trovecategories.py       |  4 +-
 Allura/allura/ext/admin/admin_main.py              |  4 +-
 Allura/allura/ext/admin/widgets.py                 |  2 +-
 .../ext/personal_dashboard/dashboard_main.py       |  2 +-
 Allura/allura/ext/project_home/project_main.py     |  2 +-
 Allura/allura/ext/search/search_main.py            |  2 +-
 Allura/allura/ext/user_profile/user_main.py        |  4 +-
 Allura/allura/lib/app_globals.py                   |  4 +-
 Allura/allura/lib/base.py                          | 19 +-------
 Allura/allura/lib/custom_middleware.py             |  4 +-
 Allura/allura/lib/decorators.py                    |  4 +-
 Allura/allura/lib/helpers.py                       |  4 +-
 Allura/allura/lib/macro.py                         |  4 +-
 Allura/allura/lib/mail_util.py                     |  4 +-
 Allura/allura/lib/multifactor.py                   |  2 +-
 Allura/allura/lib/patches.py                       |  2 +-
 Allura/allura/lib/plugin.py                        |  4 +-
 Allura/allura/lib/repository.py                    |  4 +-
 Allura/allura/lib/search.py                        |  4 +-
 Allura/allura/lib/security.py                      |  4 +-
 Allura/allura/lib/spam/akismetfilter.py            |  4 +-
 Allura/allura/lib/spam/mollomfilter.py             |  4 +-
 Allura/allura/lib/spam/stopforumspamfilter.py      |  2 +-
 Allura/allura/lib/stats.py                         |  2 +-
 Allura/allura/lib/utils.py                         | 31 ++++++------
 Allura/allura/lib/validators.py                    |  2 +-
 Allura/allura/lib/widgets/auth_widgets.py          |  4 +-
 Allura/allura/lib/widgets/discuss.py               |  2 +-
 Allura/allura/lib/widgets/form_fields.py           |  2 +-
 Allura/allura/lib/widgets/forms.py                 |  2 +-
 Allura/allura/lib/widgets/project_list.py          |  2 +-
 Allura/allura/lib/widgets/subscriptions.py         |  2 +-
 Allura/allura/lib/widgets/user_profile.py          |  6 +--
 Allura/allura/model/artifact.py                    |  4 +-
 Allura/allura/model/attachments.py                 |  4 +-
 Allura/allura/model/auth.py                        |  4 +-
 Allura/allura/model/discuss.py                     |  2 +-
 Allura/allura/model/index.py                       |  2 +-
 Allura/allura/model/monq_model.py                  |  2 +-
 Allura/allura/model/neighborhood.py                |  4 +-
 Allura/allura/model/notification.py                |  2 +-
 Allura/allura/model/oauth.py                       |  2 +-
 Allura/allura/model/project.py                     |  4 +-
 Allura/allura/model/repo_refresh.py                |  2 +-
 Allura/allura/model/repository.py                  |  4 +-
 Allura/allura/model/session.py                     |  2 +-
 Allura/allura/model/timeline.py                    |  2 +-
 Allura/allura/scripts/create_deleted_comments.py   |  2 +-
 Allura/allura/scripts/create_sitemap_files.py      |  8 +--
 Allura/allura/scripts/refresh_last_commits.py      |  2 +-
 Allura/allura/scripts/refreshrepo.py               |  2 +-
 Allura/allura/scripts/reindex_projects.py          |  2 +-
 Allura/allura/tasks/activity_tasks.py              |  2 +-
 Allura/allura/tasks/admin_tasks.py                 |  2 +-
 Allura/allura/tasks/export_tasks.py                |  2 +-
 Allura/allura/tasks/index_tasks.py                 |  4 +-
 Allura/allura/tasks/mail_tasks.py                  |  2 +-
 Allura/allura/tasks/repo_tasks.py                  |  2 +-
 Allura/allura/tests/decorators.py                  |  2 +-
 Allura/allura/tests/functional/test_admin.py       |  2 +-
 Allura/allura/tests/functional/test_auth.py        |  2 +-
 Allura/allura/tests/functional/test_home.py        |  2 +-
 Allura/allura/tests/functional/test_nav.py         |  2 +-
 .../allura/tests/functional/test_neighborhood.py   |  4 +-
 .../tests/functional/test_personal_dashboard.py    |  2 +-
 Allura/allura/tests/functional/test_rest.py        |  2 +-
 Allura/allura/tests/functional/test_root.py        |  2 +-
 Allura/allura/tests/functional/test_site_admin.py  |  2 +-
 Allura/allura/tests/model/test_artifact.py         |  2 +-
 Allura/allura/tests/model/test_auth.py             |  2 +-
 Allura/allura/tests/model/test_discussion.py       |  2 +-
 Allura/allura/tests/model/test_filesystem.py       |  6 +--
 Allura/allura/tests/model/test_notification.py     |  2 +-
 Allura/allura/tests/model/test_project.py          |  2 +-
 Allura/allura/tests/model/test_repo.py             |  2 +-
 .../tests/scripts/test_create_sitemap_files.py     |  2 +-
 .../allura/tests/scripts/test_delete_projects.py   | 10 ++--
 .../tests/templates/jinja_master/test_lib.py       |  2 +-
 Allura/allura/tests/test_app.py                    |  2 +-
 Allura/allura/tests/test_globals.py                |  2 +-
 Allura/allura/tests/test_helpers.py                |  2 +-
 Allura/allura/tests/test_plugin.py                 | 57 +++++++++++-----------
 Allura/allura/tests/test_security.py               |  2 +-
 Allura/allura/tests/test_tasks.py                  |  2 +-
 Allura/allura/tests/test_webhooks.py               |  2 +-
 Allura/allura/tests/unit/patches.py                |  2 +-
 .../tests/unit/test_helpers/test_set_context.py    |  2 +-
 Allura/allura/tests/unit/test_post_model.py        |  2 +-
 Allura/allura/tests/unit/test_repo.py              |  2 +-
 Allura/allura/webhooks.py                          |  4 +-
 Allura/allura/websetup/bootstrap.py                |  2 +-
 Allura/allura/websetup/schema.py                   | 14 ++++--
 Allura/docs/development/testing.rst                |  2 +-
 AlluraTest/alluratest/controller.py                | 23 +++++----
 ForgeActivity/forgeactivity/main.py                |  4 +-
 .../forgeactivity/tests/functional/test_root.py    |  2 +-
 ForgeActivity/forgeactivity/widgets/follow.py      |  2 +-
 ForgeBlog/forgeblog/command/rssfeeds.py            |  6 +--
 ForgeBlog/forgeblog/main.py                        |  6 +--
 ForgeBlog/forgeblog/model/blog.py                  |  2 +-
 ForgeBlog/forgeblog/tests/functional/test_feeds.py |  2 +-
 ForgeBlog/forgeblog/tests/test_app.py              |  2 +-
 ForgeBlog/forgeblog/tests/test_commands.py         |  2 +-
 ForgeBlog/forgeblog/tests/test_roles.py            |  2 +-
 ForgeBlog/forgeblog/tests/unit/__init__.py         |  2 +-
 ForgeBlog/forgeblog/tests/unit/test_blog_post.py   |  2 +-
 ForgeChat/forgechat/main.py                        |  2 +-
 .../forgediscussion/controllers/forum.py           |  2 +-
 .../forgediscussion/controllers/root.py            |  4 +-
 ForgeDiscussion/forgediscussion/forum_main.py      |  4 +-
 ForgeDiscussion/forgediscussion/import_support.py  |  2 +-
 ForgeDiscussion/forgediscussion/model/forum.py     |  2 +-
 ForgeDiscussion/forgediscussion/tasks.py           |  2 +-
 .../forgediscussion/tests/functional/test_forum.py |  2 +-
 .../tests/functional/test_import.py                |  2 +-
 ForgeDiscussion/forgediscussion/tests/test_app.py  |  2 +-
 .../forgediscussion/tests/test_forum_roles.py      |  2 +-
 .../forgediscussion/widgets/forum_widgets.py       |  2 +-
 ForgeGit/forgegit/controllers.py                   |  2 +-
 ForgeGit/forgegit/git_main.py                      |  2 +-
 ForgeGit/forgegit/model/git_repo.py                |  2 +-
 .../forgegit/tests/functional/test_controllers.py  |  2 +-
 ForgeGit/forgegit/tests/model/test_repository.py   |  2 +-
 ForgeGit/forgegit/tests/test_git_app.py            |  2 +-
 ForgeGit/forgegit/tests/test_tasks.py              |  2 +-
 ForgeImporters/forgeimporters/base.py              |  4 +-
 ForgeImporters/forgeimporters/forge/tracker.py     |  4 +-
 ForgeImporters/forgeimporters/github/__init__.py   |  2 +-
 ForgeImporters/forgeimporters/github/code.py       |  4 +-
 ForgeImporters/forgeimporters/github/tasks.py      |  4 +-
 .../forgeimporters/github/tests/test_oauth.py      |  2 +-
 ForgeImporters/forgeimporters/github/tracker.py    |  4 +-
 ForgeImporters/forgeimporters/github/wiki.py       |  4 +-
 .../forgeimporters/trac/tests/test_tickets.py      |  2 +-
 ForgeImporters/forgeimporters/trac/tickets.py      |  4 +-
 ForgeLink/forgelink/link_main.py                   |  4 +-
 ForgeLink/forgelink/tests/test_app.py              |  2 +-
 ForgeSVN/forgesvn/controllers.py                   |  2 +-
 ForgeSVN/forgesvn/model/svn.py                     |  2 +-
 ForgeSVN/forgesvn/svn_main.py                      |  2 +-
 .../forgesvn/tests/functional/test_controllers.py  |  2 +-
 ForgeSVN/forgesvn/tests/model/test_repository.py   |  2 +-
 .../forgesvn/tests/model/test_svnimplementation.py |  2 +-
 ForgeSVN/forgesvn/tests/test_svn_app.py            |  2 +-
 ForgeSVN/forgesvn/tests/test_tasks.py              |  2 +-
 ForgeShortUrl/forgeshorturl/main.py                |  2 +-
 ForgeShortUrl/forgeshorturl/model/shorturl.py      |  2 +-
 .../forgeshorturl/tests/functional/test.py         |  2 +-
 .../forgetracker/command/fix_discussion.py         |  2 +-
 ForgeTracker/forgetracker/import_support.py        |  2 +-
 ForgeTracker/forgetracker/model/ticket.py          |  2 +-
 ForgeTracker/forgetracker/plugins.py               |  2 +-
 ForgeTracker/forgetracker/search.py                |  2 +-
 ForgeTracker/forgetracker/tasks.py                 |  2 +-
 .../forgetracker/tests/functional/test_rest.py     |  2 +-
 .../forgetracker/tests/functional/test_root.py     |  4 +-
 ForgeTracker/forgetracker/tests/test_app.py        |  2 +-
 .../forgetracker/tests/test_tracker_roles.py       |  2 +-
 ForgeTracker/forgetracker/tests/unit/__init__.py   |  7 ++-
 .../forgetracker/tests/unit/test_globals_model.py  |  2 +-
 .../tests/unit/test_milestone_controller.py        |  2 +-
 .../tests/unit/test_root_controller.py             |  2 +-
 .../tests/unit/test_ticket_custom_fields_form.py   |  2 +-
 .../forgetracker/tests/unit/test_ticket_form.py    |  2 +-
 .../forgetracker/tests/unit/test_ticket_model.py   |  2 +-
 ForgeTracker/forgetracker/tracker_main.py          |  4 +-
 ForgeTracker/forgetracker/widgets/ticket_form.py   |  2 +-
 .../forgeuserstats/controllers/userstats.py        |  2 +-
 ForgeUserStats/forgeuserstats/main.py              |  2 +-
 ForgeUserStats/forgeuserstats/model/stats.py       |  2 +-
 ForgeUserStats/forgeuserstats/tests/test_model.py  |  2 +-
 ForgeUserStats/forgeuserstats/tests/test_stats.py  |  2 +-
 ForgeWiki/forgewiki/model/wiki.py                  |  4 +-
 ForgeWiki/forgewiki/tests/test_app.py              |  2 +-
 ForgeWiki/forgewiki/tests/test_models.py           |  2 +-
 ForgeWiki/forgewiki/tests/test_wiki_roles.py       |  2 +-
 ForgeWiki/forgewiki/wiki_main.py                   |  4 +-
 requirements.txt                                   |  5 +-
 scripts/migrations/000-fix-tracker-fields.py       |  2 +-
 scripts/migrations/001-restore-labels.py           |  2 +-
 .../migrations/002-fix-tracker-thread-subjects.py  |  2 +-
 scripts/migrations/007-update-acls.py              |  2 +-
 scripts/migrations/010-fix-home-permissions.py     |  2 +-
 scripts/migrations/012-uninstall-home.py           |  2 +-
 scripts/migrations/013-update-ordinals.py          |  2 +-
 .../015-add-neighborhood_id-to-blog-posts.py       |  2 +-
 .../migrations/020-remove-wiki-title-slashes.py    |  2 +-
 .../migrations/024-migrate-custom-profile-text.py  |  2 +-
 .../033-change-comment-anon-permissions.py         |  2 +-
 ...34-update_subscriptions_ticket_and_mr_titles.py |  2 +-
 scripts/perf/call_count.py                         |  2 +-
 scripts/perf/load-up-forum.py                      |  2 +-
 scripts/perf/md_perf.py                            |  2 +-
 scripts/project-import.py                          |  2 +-
 scripts/publicize-neighborhood.py                  |  2 +-
 scripts/rethumb.py                                 |  2 +-
 scripts/scrub-allura-data.py                       |  2 +-
 scripts/teamforge-import.py                        |  2 +-
 220 files changed, 371 insertions(+), 388 deletions(-)

diff --git a/Allura/allura/__init__.py b/Allura/allura/__init__.py
index ebf903b..15c3ab2 100644
--- a/Allura/allura/__init__.py
+++ b/Allura/allura/__init__.py
@@ -18,6 +18,6 @@
 #       under the License.
 
 """The allura package"""
-from paste.registry import StackedObjectProxy
+from tg.support.registry import StackedObjectProxy
 
 credentials = StackedObjectProxy(name='credentials')
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index 9481eed..82a550b 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -27,7 +27,7 @@ import pkg_resources
 from tg import expose, redirect, flash, validate
 from tg.decorators import without_trailing_slash
 from tg import config as tg_config
-from pylons import request, app_globals as g, tmpl_context as c
+from tg import request, app_globals as g, tmpl_context as c
 from paste.deploy.converters import asbool, asint
 from bson import ObjectId
 from bson.errors import InvalidId
diff --git a/Allura/allura/command/base.py b/Allura/allura/command/base.py
index 66b46d5..9a7689a 100644
--- a/Allura/allura/command/base.py
+++ b/Allura/allura/command/base.py
@@ -19,11 +19,12 @@ import os
 import logging
 import shlex
 
-import pylons
+import tg
 from paste.script import command
 from paste.deploy import appconfig
 from paste.deploy.converters import asbool
-from paste.registry import Registry
+from tg.support.registry import Registry
+from tg.wsgiapp import RequestLocals
 
 import activitystream
 import ming
@@ -104,12 +105,12 @@ class Command(command.Command):
             ming.configure(**conf)
             if asbool(conf.get('activitystream.recording.enabled', False)):
                 activitystream.configure(**h.convert_bools(conf, prefix='activitystream.'))
-            pylons.tmpl_context.user = M.User.anonymous()
+            tg.tmpl_context.user = M.User.anonymous()
         else:
             # Probably being called from another script (websetup, perhaps?)
             log = logging.getLogger('allura.command')
-            conf = pylons.config
-        self.tools = pylons.app_globals.entry_points['tool'].values()
+            conf = tg.config
+        self.tools = tg.app_globals.entry_points['tool'].values()
         for ep in h.iter_entry_points('allura.command_init'):
             log.info('Running command_init for %s', ep.name)
             ep.load()(conf)
@@ -118,10 +119,12 @@ class Command(command.Command):
     def setup_globals(self):
         import allura.lib.app_globals
         self.registry.prepare()
-        self.registry.register(pylons.tmpl_context, EmptyClass())
-        self.registry.register(pylons.app_globals, self.globals)
-        self.registry.register(
-            allura.credentials, allura.lib.security.Credentials())
+        self.registry.register(allura.credentials, allura.lib.security.Credentials())
+        # turbogears has its own special magic wired up for its globals, can't use a regular Registry
+        tgl = RequestLocals()
+        tgl.tmpl_context = EmptyClass()
+        tgl.app_globals = self.globals
+        tg.request_local.context._push_object(tgl)
 
     def teardown_globals(self):
         self.registry.cleanup()
diff --git a/Allura/allura/command/reclone_repo.py b/Allura/allura/command/reclone_repo.py
index d401b0b..51e5ca6 100644
--- a/Allura/allura/command/reclone_repo.py
+++ b/Allura/allura/command/reclone_repo.py
@@ -17,7 +17,7 @@
 
 import warnings
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 
diff --git a/Allura/allura/command/script.py b/Allura/allura/command/script.py
index 1f2c93a..7bc3b8c 100644
--- a/Allura/allura/command/script.py
+++ b/Allura/allura/command/script.py
@@ -20,8 +20,8 @@ import os.path
 import cProfile
 import warnings
 
-from pylons import tmpl_context as c
-import pylons
+from tg import tmpl_context as c
+import tg
 import webob
 
 from ming.orm import session
@@ -52,7 +52,7 @@ class ScriptCommand(base.Command):
             self.basic_setup()
             request = webob.Request.blank('--script--', environ={
                 'paste.registry': self.registry})
-            self.registry.register(pylons.request, request)
+            tg.request_local.context.request = request
             if self.options.pdb:
                 base.log.info('Installing exception hook')
                 sys.excepthook = utils.postmortem_hook
diff --git a/Allura/allura/command/show_models.py b/Allura/allura/command/show_models.py
index 6de6035..ac2ef86 100644
--- a/Allura/allura/command/show_models.py
+++ b/Allura/allura/command/show_models.py
@@ -21,7 +21,7 @@ from contextlib import contextmanager
 from itertools import groupby
 
 from paste.deploy.converters import asbool
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from pymongo.errors import DuplicateKeyError, InvalidDocument, OperationFailure
 
 from ming.orm import mapper, session, Mapper
diff --git a/Allura/allura/command/taskd.py b/Allura/allura/command/taskd.py
index 409e701..d305c74 100644
--- a/Allura/allura/command/taskd.py
+++ b/Allura/allura/command/taskd.py
@@ -25,7 +25,6 @@ import signal
 import sys
 
 import faulthandler
-import pylons
 from setproctitle import setproctitle, getproctitle
 import tg
 from paste.deploy import loadapp
@@ -103,7 +102,7 @@ class TaskdCommand(base.Command):
         name = '%s pid %s' % (os.uname()[1], os.getpid())
         wsgi_app = loadapp('config:%s#task' %
                            self.args[0], relative_to=os.getcwd())
-        poll_interval = asint(pylons.config.get('monq.poll_interval', 10))
+        poll_interval = asint(tg.config.get('monq.poll_interval', 10))
         only = self.options.only
         if only:
             only = only.split(',')
diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py
index 50028c1..c21af19 100644
--- a/Allura/allura/config/app_cfg.py
+++ b/Allura/allura/config/app_cfg.py
@@ -65,9 +65,8 @@ class ForgeConfig(AppConfig):
         self.disable_request_extensions = True
 
     def after_init_config(self):
-        config['pylons.strict_c'] = True
+        config['tg.strict_tmpl_context'] = True
 
-    def setup_routes(self):
         map = Mapper()
         # Setup a default route for the root of object dispatch
         map.connect('*url', controller=self.root_controller,
@@ -106,9 +105,9 @@ class ForgeConfig(AppConfig):
         jinja2_env.filters['filter'] = lambda s,t=None: filter(t and jinja2_env.tests[t], s)
         jinja2_env.filters['nl2br'] = helpers.nl2br_jinja_filter
         jinja2_env.globals.update({'hasattr': hasattr})
-        config['pylons.app_globals'].jinja2_env = jinja2_env
+        config['tg.app_globals'].jinja2_env = jinja2_env
         # Jinja's unable to request c's attributes without strict_c
-        config['pylons.strict_c'] = True
+        config['tg.strict_tmpl_context'] = True
         self.render_functions.jinja = tg.render.render_jinja
 
 
@@ -116,7 +115,7 @@ class JinjaEngine(ew.TemplateEngine):
 
     @property
     def _environ(self):
-        return config['pylons.app_globals'].jinja2_env
+        return config['tg.app_globals'].jinja2_env
 
     def load(self, template_name):
         try:
diff --git a/Allura/allura/config/environment.py b/Allura/allura/config/environment.py
index 35676fd..bf0f5b6 100644
--- a/Allura/allura/config/environment.py
+++ b/Allura/allura/config/environment.py
@@ -19,10 +19,6 @@
 
 """WSGI environment setup for allura."""
 
-import pylons.middleware
-import tg
-import tg.error
-
 from allura.config.app_cfg import base_config
 
 __all__ = ['load_environment']
diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py
index 99f9329..decce40 100644
--- a/Allura/allura/config/middleware.py
+++ b/Allura/allura/config/middleware.py
@@ -20,13 +20,12 @@
 """WSGI middleware initialization for the allura application."""
 import mimetypes
 
-import pylons.middleware  # needed within tg.error :(
 import tg
 import tg.error
 import pkg_resources
 from tg import config
 from paste.deploy.converters import asbool, aslist, asint
-from paste.registry import RegistryManager
+from tg.support.registry import RegistryManager
 from routes.middleware import RoutesMiddleware
 from pylons.middleware import StatusCodeRedirect
 from beaker.middleware import SessionMiddleware
@@ -178,7 +177,7 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf):
         # Converts exceptions to HTTP errors, shows traceback in debug mode
         # don't use TG footer with extra CSS & images that take time to load
         tg.error.footer_html = '<!-- %s %s -->'
-        app = tg.error.ErrorHandler(app, global_conf, **config['pylons.errorware'])
+        app = tg.error.ErrorHandler(app, global_conf, **config['tg.errorware'])
 
         app = SetRequestHostFromConfig(app, config)
 
@@ -209,16 +208,15 @@ def allura_globals_middleware(app):
 
 
 def get_tg_vars(context):
-    import pylons
     import tg
     from allura.lib import helpers as h
     from urllib import quote, quote_plus
-    context.setdefault('g', pylons.app_globals)
-    context.setdefault('c', pylons.tmpl_context)
+    context.setdefault('g', tg.app_globals)
+    context.setdefault('c', tg.tmpl_context)
     context.setdefault('h', h)
-    context.setdefault('request', pylons.request)
-    context.setdefault('response', pylons.response)
-    context.setdefault('url', pylons.url)
+    context.setdefault('request', tg.request)
+    context.setdefault('response', tg.response)
+    context.setdefault('url', tg.url)
     context.setdefault('tg', dict(
         config=tg.config,
         flash_obj=tg.flash,
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 3333b66..e10fdd0 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -25,8 +25,8 @@ import bson
 import tg
 from tg import expose, flash, redirect, validate, config, session
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request, response
+from tg import tmpl_context as c, app_globals as g
+from tg import request, response
 from webob import exc as wexc
 from paste.deploy.converters import asbool
 from cryptography.hazmat.primitives.twofactor import InvalidToken
diff --git a/Allura/allura/controllers/base.py b/Allura/allura/controllers/base.py
index 6a6ab28..ef91a32 100644
--- a/Allura/allura/controllers/base.py
+++ b/Allura/allura/controllers/base.py
@@ -21,7 +21,7 @@ from tg import expose
 from webob import exc
 from crank.objectdispatcher import ObjectDispatcher
 from tg import redirect, flash
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 
 log = logging.getLogger(__name__)
diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index b80d94d..0a5047d 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -21,8 +21,8 @@
 import logging
 from urllib import unquote
 
-from pylons import tmpl_context as c
-from pylons import request
+from tg import tmpl_context as c
+from tg import request
 from webob import exc
 from tg import expose
 from paste.deploy.converters import asbool
@@ -88,9 +88,6 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
             count -= 1
             assert count > 0, 'Timeout waiting for test project to appear'
 
-    def _cleanup_request(self):
-        pass
-
     @expose()
     def _lookup(self, name, *remainder):
         if not h.re_project_name.match(name):
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 34f085d..9aec747 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -24,7 +24,7 @@ from tg import expose, redirect, validate, request, flash, response
 from tg.decorators import with_trailing_slash, without_trailing_slash, before_render, before_validate
 from decorator import decorator
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from webob import exc
 
 from ming.base import Object
diff --git a/Allura/allura/controllers/feed.py b/Allura/allura/controllers/feed.py
index 2fef9f3..9a9c2ae 100644
--- a/Allura/allura/controllers/feed.py
+++ b/Allura/allura/controllers/feed.py
@@ -18,7 +18,7 @@
 from tg import expose, validate, request, response
 from tg.decorators import without_trailing_slash
 from formencode import validators as V
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from webob import exc
 
 from allura import model as M
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index d7c2d3d..5c7e253 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -23,7 +23,7 @@ from urllib import unquote
 from bson import ObjectId
 from tg import expose, flash, redirect, validate, request, config, session
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from paste.deploy.converters import asbool
 from webob import exc
 import jinja2
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 650065c..8cae021 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -24,8 +24,8 @@ from collections import defaultdict, OrderedDict
 
 from ming.utils import LazyProperty
 from paste.deploy.converters import asbool
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request, response
+from tg import tmpl_context as c, app_globals as g
+from tg import request, response
 from webob import exc
 import tg
 from tg import redirect, expose, flash, validate
diff --git a/Allura/allura/controllers/rest.py b/Allura/allura/controllers/rest.py
index 2913bee..6e9f78b 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -25,8 +25,8 @@ import oauth2 as oauth
 from paste.util.converters import asbool
 from webob import exc
 from tg import expose, flash, redirect, config
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request, response
+from tg import tmpl_context as c, app_globals as g
+from tg import request, response
 
 from ming.orm import session
 from ming.utils import LazyProperty
diff --git a/Allura/allura/controllers/root.py b/Allura/allura/controllers/root.py
index 76987e9..7a6bee2 100644
--- a/Allura/allura/controllers/root.py
+++ b/Allura/allura/controllers/root.py
@@ -23,8 +23,8 @@ import logging
 from tg import expose, request, config, session, redirect
 from tg.decorators import with_trailing_slash
 from tg.flash import TGFlash
-from pylons import tmpl_context as c
-from pylons import response
+from tg import tmpl_context as c
+from tg import response
 from paste.deploy.converters import asbool
 
 from allura.app import SitemapEntry
@@ -108,9 +108,6 @@ class RootController(WsgiDispatchController):
             # https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en#defining_optimal_cache-control_policy
             response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
 
-    def _cleanup_request(self):
-        pass
-
     @expose()
     @with_trailing_slash
     def index(self, **kw):
diff --git a/Allura/allura/controllers/search.py b/Allura/allura/controllers/search.py
index eaf8446..3fe6f8a 100644
--- a/Allura/allura/controllers/search.py
+++ b/Allura/allura/controllers/search.py
@@ -18,7 +18,7 @@
 from tg import expose, validate, request
 from tg.decorators import with_trailing_slash, without_trailing_slash
 from formencode import validators as V
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from webob import exc
 import pymongo
 
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index d5d91f1..d173800 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -25,9 +25,9 @@ from tg.decorators import with_trailing_slash, without_trailing_slash
 import bson
 import tg
 from paste.deploy.converters import aslist
-from pylons import app_globals as g
-from pylons import tmpl_context as c
-from pylons import request
+from tg import app_globals as g
+from tg import tmpl_context as c
+from tg import request
 from formencode import validators, Invalid
 from webob.exc import HTTPNotFound, HTTPFound
 from ming.odm import ThreadLocalORMSession
diff --git a/Allura/allura/controllers/static.py b/Allura/allura/controllers/static.py
index 89a94ab..15b638c 100644
--- a/Allura/allura/controllers/static.py
+++ b/Allura/allura/controllers/static.py
@@ -21,7 +21,7 @@ from tg import expose
 from tg.decorators import without_trailing_slash
 from webob import exc
 
-from pylons import app_globals as g
+from tg import app_globals as g
 from allura.lib import helpers as h
 from allura.lib import utils
 
diff --git a/Allura/allura/controllers/trovecategories.py b/Allura/allura/controllers/trovecategories.py
index 392de1c..149b1bc 100644
--- a/Allura/allura/controllers/trovecategories.py
+++ b/Allura/allura/controllers/trovecategories.py
@@ -18,11 +18,11 @@ import re
 from collections import OrderedDict
 
 from tg import expose, flash, redirect, validate, config
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from string import digits, lowercase
 from tg.decorators import without_trailing_slash
 from webob.exc import HTTPForbidden, HTTPNotFound
-from pylons import app_globals as g
+from tg import app_globals as g
 
 from allura import model as M
 from allura.controllers import BaseController
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index 4b7ec42..6e49e6d 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -26,8 +26,8 @@ import json
 from operator import itemgetter, attrgetter
 import pkg_resources
 
-from pylons import tmpl_context as c, app_globals as g, response
-from pylons import request
+from tg import tmpl_context as c, app_globals as g, response
+from tg import request
 from paste.deploy.converters import asbool, aslist
 from tg import expose, redirect, flash, validate, config, jsonify
 from tg.decorators import with_trailing_slash, without_trailing_slash
diff --git a/Allura/allura/ext/admin/widgets.py b/Allura/allura/ext/admin/widgets.py
index 547092e..6fed753 100644
--- a/Allura/allura/ext/admin/widgets.py
+++ b/Allura/allura/ext/admin/widgets.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 import ew as ew_core
 from ew import jinja2_ew as ew
diff --git a/Allura/allura/ext/personal_dashboard/dashboard_main.py b/Allura/allura/ext/personal_dashboard/dashboard_main.py
index f3fb479..fb83cb7 100644
--- a/Allura/allura/ext/personal_dashboard/dashboard_main.py
+++ b/Allura/allura/ext/personal_dashboard/dashboard_main.py
@@ -17,7 +17,7 @@
 
 import logging
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from tg import expose, redirect, config
 from itertools import islice, ifilter
 from ming.orm import session
diff --git a/Allura/allura/ext/project_home/project_main.py b/Allura/allura/ext/project_home/project_main.py
index a02b807..0710ea6 100644
--- a/Allura/allura/ext/project_home/project_main.py
+++ b/Allura/allura/ext/project_home/project_main.py
@@ -18,7 +18,7 @@
 import logging
 
 import pkg_resources
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import expose, redirect
 from tg.decorators import with_trailing_slash
 
diff --git a/Allura/allura/ext/search/search_main.py b/Allura/allura/ext/search/search_main.py
index 9f8a92b..91bb1da 100644
--- a/Allura/allura/ext/search/search_main.py
+++ b/Allura/allura/ext/search/search_main.py
@@ -18,7 +18,7 @@
 import logging
 
 import pkg_resources
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import expose, validate
 from tg.decorators import with_trailing_slash
 from formencode import validators as V
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index 50bd64a..a6f218f 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -21,8 +21,8 @@ import pkg_resources
 from datetime import datetime
 
 from formencode import validators
-from pylons import request
-from pylons import tmpl_context as c, app_globals as g
+from tg import request
+from tg import tmpl_context as c, app_globals as g
 from pytz import timezone
 from tg import expose, redirect, validate, flash
 from webob import exc
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 1e63594..4b0a282 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -39,8 +39,8 @@ import pygments.lexers
 import pygments.formatters
 import pygments.util
 from tg import config
-from pylons import request
-from pylons import tmpl_context as c
+from tg import request
+from tg import tmpl_context as c
 from paste.deploy.converters import asbool, asint, aslist
 from pypeline.markup import markup as pypeline_markup
 from ming.odm import session
diff --git a/Allura/allura/lib/base.py b/Allura/allura/lib/base.py
index 8000e88..148c3e8 100644
--- a/Allura/allura/lib/base.py
+++ b/Allura/allura/lib/base.py
@@ -18,8 +18,6 @@
 #       under the License.
 
 """The base Controller API."""
-from webob import exc
-import pylons
 from tg import TGController
 
 __all__ = ['WsgiDispatchController']
@@ -39,19 +37,6 @@ class WsgiDispatchController(TGController):
         '''Responsible for setting all the values we need to be set on pylons.tmpl_context'''
         raise NotImplementedError, '_setup_request'
 
-    def _cleanup_request(self):
-        raise NotImplementedError, '_cleanup_request'
-
     def __call__(self, environ, start_response):
-        try:
-            self._setup_request()
-            response = super(WsgiDispatchController, self).__call__(
-                environ, start_response)
-            return self.cleanup_iterator(response)
-        except exc.HTTPException, err:
-            return err(environ, start_response)
-
-    def cleanup_iterator(self, response):
-        for chunk in response:
-            yield chunk
-        self._cleanup_request()
+        self._setup_request()
+        return super(WsgiDispatchController, self).__call__(environ, start_response)
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index e558080..bd27868 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -23,7 +23,7 @@ import tg
 import pkg_resources
 from paste import fileapp
 from paste.deploy.converters import aslist
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from pylons.util import call_wsgi_application
 from timermiddleware import Timer, TimerMiddleware
 from webob import exc, Request
@@ -189,7 +189,7 @@ class CSRFMiddleware(object):
         if cookie is None:
             cookie = h.cryptographic_nonce()
         if req.method == 'POST':
-            param = req.str_POST.pop(self._param_name, None)
+            param = req.POST.pop(self._param_name, None)
             if cookie != param:
                 log.warning('CSRF attempt detected, %r != %r', cookie, param)
                 environ.pop('HTTP_COOKIE', None)  # effectively kill the existing session
diff --git a/Allura/allura/lib/decorators.py b/Allura/allura/lib/decorators.py
index 5f37daf..589b327 100644
--- a/Allura/allura/lib/decorators.py
+++ b/Allura/allura/lib/decorators.py
@@ -32,8 +32,8 @@ from tg.decorators import before_validate
 from tg import request, redirect, session, config
 from tg.render import render
 from webob import exc
-from pylons import tmpl_context as c
-from pylons import response
+from tg import tmpl_context as c
+from tg import response
 from webob.exc import HTTPFound, WSGIHTTPException
 
 from allura.lib import helpers as h
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 70c768f..57f200d 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -53,8 +53,8 @@ from bson import ObjectId
 from paste.deploy import appconfig
 from pymongo.errors import InvalidId
 from contextlib import contextmanager
-from pylons import tmpl_context as c, app_globals as g
-from pylons import response, request
+from tg import tmpl_context as c, app_globals as g
+from tg import response, request
 from tg.decorators import before_validate
 from formencode.variabledecode import variable_decode
 import formencode
diff --git a/Allura/allura/lib/macro.py b/Allura/allura/lib/macro.py
index 191a413..3996826 100644
--- a/Allura/allura/lib/macro.py
+++ b/Allura/allura/lib/macro.py
@@ -26,8 +26,8 @@ from operator import attrgetter
 from urlparse import urlparse, urlunparse
 
 import pymongo
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from paste.deploy.converters import asint
 from BeautifulSoup import BeautifulSoup
 
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index ae72f93..ea906bf 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -26,8 +26,8 @@ from email import header
 import tg
 from paste.deploy.converters import asbool, asint, aslist
 from formencode import validators as fev
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 
 from allura.lib.utils import ConfigProxy
 from allura.lib import exceptions as exc
diff --git a/Allura/allura/lib/multifactor.py b/Allura/allura/lib/multifactor.py
index a617392..ec0249d 100644
--- a/Allura/allura/lib/multifactor.py
+++ b/Allura/allura/lib/multifactor.py
@@ -28,7 +28,7 @@ import errno
 import bson
 from allura.lib.exceptions import InvalidRecoveryCode, MultifactorRateLimitError
 from tg import config
-from pylons import app_globals as g
+from tg import app_globals as g
 from paste.deploy.converters import asint
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives.twofactor import InvalidToken
diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index 67ba105..8e0dcf8 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -20,7 +20,7 @@ import re
 import webob
 import tg.decorators
 from decorator import decorator
-from pylons import request
+from tg import request
 import mock
 import simplejson
 
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 921d989..f64c8ca 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -42,7 +42,7 @@ except ImportError:
 import pkg_resources
 import tg
 from tg import config, request, redirect, response
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from webob import exc, Request
 from paste.deploy.converters import asbool, asint
 
@@ -1376,7 +1376,7 @@ class ThemeProvider(object):
         return note, set_cookie
 
     def get_site_notification(self):
-        from pylons import request, response
+        from tg import request, response
         tool_name = c.app.config.tool_name if c.app else ''
         r = self._get_site_notification(
             request.path_qs,
diff --git a/Allura/allura/lib/repository.py b/Allura/allura/lib/repository.py
index 82d09c4..6250026 100644
--- a/Allura/allura/lib/repository.py
+++ b/Allura/allura/lib/repository.py
@@ -18,8 +18,8 @@
 import logging
 from urllib import quote
 
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from tg import expose, redirect, flash, validate, config
 from tg.decorators import with_trailing_slash, without_trailing_slash
 from webob import exc
diff --git a/Allura/allura/lib/search.py b/Allura/allura/lib/search.py
index 53669eb..370cef6 100644
--- a/Allura/allura/lib/search.py
+++ b/Allura/allura/lib/search.py
@@ -25,8 +25,8 @@ import bson
 import markdown
 import jinja2
 from tg import redirect, url
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from pysolr import SolrError
 
 from allura.lib import helpers as h
diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index 41691f4..544bc76 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -21,8 +21,8 @@ This module provides the security predicates used in decorating various models.
 import logging
 from collections import defaultdict
 
-from pylons import tmpl_context as c
-from pylons import request
+from tg import tmpl_context as c
+from tg import request
 from webob import exc
 from itertools import chain
 from ming.utils import LazyProperty
diff --git a/Allura/allura/lib/spam/akismetfilter.py b/Allura/allura/lib/spam/akismetfilter.py
index 26cccbd..2ea4c13 100644
--- a/Allura/allura/lib/spam/akismetfilter.py
+++ b/Allura/allura/lib/spam/akismetfilter.py
@@ -17,8 +17,8 @@
 
 import logging
 
-from pylons import request
-from pylons import tmpl_context as c
+from tg import request
+from tg import tmpl_context as c
 
 from allura.lib import helpers as h
 from allura.lib import utils
diff --git a/Allura/allura/lib/spam/mollomfilter.py b/Allura/allura/lib/spam/mollomfilter.py
index f2d6b68..ddd2e86 100644
--- a/Allura/allura/lib/spam/mollomfilter.py
+++ b/Allura/allura/lib/spam/mollomfilter.py
@@ -17,8 +17,8 @@
 
 import logging
 
-from pylons import request
-from pylons import tmpl_context as c
+from tg import request
+from tg import tmpl_context as c
 
 from allura.lib import helpers as h
 from allura.lib import utils
diff --git a/Allura/allura/lib/spam/stopforumspamfilter.py b/Allura/allura/lib/spam/stopforumspamfilter.py
index 0e263be..4e7a497 100644
--- a/Allura/allura/lib/spam/stopforumspamfilter.py
+++ b/Allura/allura/lib/spam/stopforumspamfilter.py
@@ -20,7 +20,7 @@ import csv
 from sys import getsizeof
 
 import ipaddress
-from pylons import request
+from tg import request
 
 from allura.lib import utils
 from allura.lib.spam import SpamFilter
diff --git a/Allura/allura/lib/stats.py b/Allura/allura/lib/stats.py
index 9864e30..d5244b1 100644
--- a/Allura/allura/lib/stats.py
+++ b/Allura/allura/lib/stats.py
@@ -18,7 +18,7 @@
 from __future__ import with_statement
 from time import time
 from contextlib import contextmanager
-from pylons import request
+from tg import request
 
 
 class StatsRecord(object):
diff --git a/Allura/allura/lib/utils.py b/Allura/allura/lib/utils.py
index 7198386..971d53c 100644
--- a/Allura/allura/lib/utils.py
+++ b/Allura/allura/lib/utils.py
@@ -34,7 +34,6 @@ from urlparse import urlparse
 
 import tg
 import emoji
-import pylons
 import json
 from formencode import Invalid
 from collections import OrderedDict
@@ -248,7 +247,7 @@ class AntiSpam(object):
     def __init__(self, request=None, num_honey=2, timestamp=None, spinner=None):
         self.num_honey = num_honey
         if request is None or request.method == 'GET':
-            self.request = pylons.request
+            self.request = tg.request
             self.timestamp = timestamp if timestamp else int(time.time())
             self.spinner = spinner if spinner else self.make_spinner()
             self.timestamp_text = str(self.timestamp)
@@ -348,13 +347,13 @@ class AntiSpam(object):
         octets = self.client_ip.split('.')
         ip_chunk = '.'.join(octets[0:3])
         plain = '%d:%s:%s' % (
-            timestamp, ip_chunk, pylons.config.get('spinner_secret', 'abcdef'))
+            timestamp, ip_chunk, tg.config.get('spinner_secret', 'abcdef'))
         return hashlib.sha1(plain).digest()
 
     @classmethod
     def validate_request(cls, request=None, now=None, params=None):
         if request is None:
-            request = pylons.request
+            request = tg.request
         if params is None:
             params = request.params
         new_params = dict(params)
@@ -369,7 +368,7 @@ class AntiSpam(object):
                     now = time.time()
                 if obj.timestamp > now + 5:
                     raise ValueError('Post from the future')
-                if now - obj.timestamp > int(pylons.config.get('spam.form_post_expiration', 24 * 60 * 60)):
+                if now - obj.timestamp > int(tg.config.get('spam.form_post_expiration', 24 * 60 * 60)):
                     raise ValueError('Post from the distant past')
                 if obj.spinner != expected_spinner:
                     raise ValueError('Bad spinner value')
@@ -403,7 +402,7 @@ class AntiSpam(object):
                     # request.params is immutable, but will reflect changes to request.POST
                     tg.request.POST.update(new_params)
             except (ValueError, TypeError, binascii.Error):
-                testing = pylons.request.environ.get('paste.testing', False)
+                testing = tg.request.environ.get('paste.testing', False)
                 if testing:
                     # re-raise so we can see problems more easily
                     raise
@@ -545,19 +544,19 @@ def serve_file(fp, filename, content_type, last_modified=None,
         etag = u'{0}?{1}'.format(filename, last_modified).encode('utf-8')
     if etag:
         etag_cache(etag)
-    pylons.response.headers['Content-Type'] = ''
-    pylons.response.content_type = content_type.encode('utf-8')
-    pylons.response.cache_expires = cache_expires or asint(
+    tg.response.headers['Content-Type'] = ''
+    tg.response.content_type = content_type.encode('utf-8')
+    tg.response.cache_expires = cache_expires or asint(
         tg.config.get('files_expires_header_secs', 60 * 60))
-    pylons.response.last_modified = last_modified
+    tg.response.last_modified = last_modified
     if size:
-        pylons.response.content_length = size
-    if 'Pragma' in pylons.response.headers:
-        del pylons.response.headers['Pragma']
-    if 'Cache-Control' in pylons.response.headers:
-        del pylons.response.headers['Cache-Control']
+        tg.response.content_length = size
+    if 'Pragma' in tg.response.headers:
+        del tg.response.headers['Pragma']
+    if 'Cache-Control' in tg.response.headers:
+        del tg.response.headers['Cache-Control']
     if not embed:
-        pylons.response.headers.add(
+        tg.response.headers.add(
             'Content-Disposition',
             'attachment;filename="%s"' % filename.encode('utf-8'))
     # http://code.google.com/p/modwsgi/wiki/FileWrapperExtension
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index 1a38905..d78947f 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -20,7 +20,7 @@ import re
 from bson import ObjectId
 import formencode as fe
 from formencode import validators as fev
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from . import helpers as h
 from datetime import datetime
 
diff --git a/Allura/allura/lib/widgets/auth_widgets.py b/Allura/allura/lib/widgets/auth_widgets.py
index b7772ab..3233015 100644
--- a/Allura/allura/lib/widgets/auth_widgets.py
+++ b/Allura/allura/lib/widgets/auth_widgets.py
@@ -19,12 +19,12 @@ import ew as ew_core
 import ew.jinja2_ew as ew
 from ew.core import validator
 
-from pylons import request, tmpl_context as c
+from tg import request, tmpl_context as c
 from formencode import Invalid
 from webob import exc
 
 from .forms import ForgeForm
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from allura.lib import plugin
 from allura import model as M
diff --git a/Allura/allura/lib/widgets/discuss.py b/Allura/allura/lib/widgets/discuss.py
index e07e73c..6918196 100644
--- a/Allura/allura/lib/widgets/discuss.py
+++ b/Allura/allura/lib/widgets/discuss.py
@@ -20,7 +20,7 @@ from formencode import validators as fev
 import json
 import ew as ew_core
 import ew.jinja2_ew as ew
-from pylons import app_globals as g
+from tg import app_globals as g
 from  tg import config
 
 from allura.lib import utils
diff --git a/Allura/allura/lib/widgets/form_fields.py b/Allura/allura/lib/widgets/form_fields.py
index 900e46e..68badf6 100644
--- a/Allura/allura/lib/widgets/form_fields.py
+++ b/Allura/allura/lib/widgets/form_fields.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import request, url
 import json
 import logging
diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py
index ac49ce3..7820157 100644
--- a/Allura/allura/lib/widgets/forms.py
+++ b/Allura/allura/lib/widgets/forms.py
@@ -18,7 +18,7 @@
 import logging
 import warnings
 
-from pylons import app_globals as g, tmpl_context as c
+from tg import app_globals as g, tmpl_context as c
 from formencode import validators as fev
 import formencode
 import ew as ew_core
diff --git a/Allura/allura/lib/widgets/project_list.py b/Allura/allura/lib/widgets/project_list.py
index 9c60781..1d511b5 100644
--- a/Allura/allura/lib/widgets/project_list.py
+++ b/Allura/allura/lib/widgets/project_list.py
@@ -18,7 +18,7 @@
 import ew as ew_core
 import ew.jinja2_ew as ew
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from paste.deploy.converters import asbool
 
 from allura import model as M
diff --git a/Allura/allura/lib/widgets/subscriptions.py b/Allura/allura/lib/widgets/subscriptions.py
index 142463d..83d3037 100644
--- a/Allura/allura/lib/widgets/subscriptions.py
+++ b/Allura/allura/lib/widgets/subscriptions.py
@@ -17,7 +17,7 @@
 
 import ew as ew_core
 import ew.jinja2_ew as ew
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.lib import validators as V
 from allura.lib.widgets import form_fields as ffw
diff --git a/Allura/allura/lib/widgets/user_profile.py b/Allura/allura/lib/widgets/user_profile.py
index c37cde9..3c51f94 100644
--- a/Allura/allura/lib/widgets/user_profile.py
+++ b/Allura/allura/lib/widgets/user_profile.py
@@ -24,9 +24,9 @@ from jinja2 import Markup
 from paste.deploy.converters import asbool
 import tg
 from formencode import validators as fev
-from pylons import app_globals as g
-from pylons import request
-from pylons import tmpl_context as c
+from tg import app_globals as g
+from tg import request
+from tg import tmpl_context as c
 from allura.lib import helpers as h
 from allura.lib.plugin import AuthenticationProvider
 from .forms import ForgeForm
diff --git a/Allura/allura/model/artifact.py b/Allura/allura/model/artifact.py
index bf0716c..4df6cd3 100644
--- a/Allura/allura/model/artifact.py
+++ b/Allura/allura/model/artifact.py
@@ -20,8 +20,8 @@ from collections import defaultdict
 from datetime import datetime
 
 import pymongo
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from ming import schema as S
 from ming.orm import state, session
 from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty
diff --git a/Allura/allura/model/attachments.py b/Allura/allura/model/attachments.py
index 568f5b0..fa67134 100644
--- a/Allura/allura/model/attachments.py
+++ b/Allura/allura/model/attachments.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import FieldProperty
 from ming import schema as S
 
@@ -49,7 +49,7 @@ class BaseAttachment(File):
         return self.artifact.url() + 'attachment/' + h.urlquote(self.filename)
 
     def is_embedded(self):
-        from pylons import request
+        from tg import request
         return self.filename in request.environ.get('allura.macro.att_embedded', [])
 
     @classmethod
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 8ebef71..6a2f999 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -28,8 +28,8 @@ import re
 from pytz import timezone
 import pymongo
 from tg import config
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from ming import schema as S
 from ming import Field, collection
 from ming.orm import session, state
diff --git a/Allura/allura/model/discuss.py b/Allura/allura/model/discuss.py
index c6cbc58..973d196 100644
--- a/Allura/allura/model/discuss.py
+++ b/Allura/allura/model/discuss.py
@@ -22,7 +22,7 @@ from datetime import datetime
 import jinja2
 import pymongo
 from pymongo.errors import DuplicateKeyError
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 import tg
 
 from ming import schema
diff --git a/Allura/allura/model/index.py b/Allura/allura/model/index.py
index 61a036a..300b9ba 100644
--- a/Allura/allura/model/index.py
+++ b/Allura/allura/model/index.py
@@ -24,7 +24,7 @@ from urllib import unquote
 
 import bson
 import pymongo
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming import collection, Field, Index
 from ming import schema as S
diff --git a/Allura/allura/model/monq_model.py b/Allura/allura/model/monq_model.py
index 7f25a4f..b28ca12 100644
--- a/Allura/allura/model/monq_model.py
+++ b/Allura/allura/model/monq_model.py
@@ -22,7 +22,7 @@ import logging
 from datetime import datetime, timedelta
 
 import pymongo
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from tg import config
 from paste.deploy.converters import asbool
 
diff --git a/Allura/allura/model/neighborhood.py b/Allura/allura/model/neighborhood.py
index 59b9075..789f5ea 100644
--- a/Allura/allura/model/neighborhood.py
+++ b/Allura/allura/model/neighborhood.py
@@ -25,8 +25,8 @@ from ming.orm import FieldProperty, RelationProperty
 from ming.orm.declarative import MappedClass
 from ming.utils import LazyProperty
 
-from pylons import request
-from pylons import tmpl_context as c, app_globals as g
+from tg import request
+from tg import tmpl_context as c, app_globals as g
 
 from allura.lib import plugin
 
diff --git a/Allura/allura/model/notification.py b/Allura/allura/model/notification.py
index c4e2c24..080ef05 100644
--- a/Allura/allura/model/notification.py
+++ b/Allura/allura/model/notification.py
@@ -39,7 +39,7 @@ from bson import ObjectId
 from datetime import datetime, timedelta
 from collections import defaultdict
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from tg import config
 import pymongo
 import jinja2
diff --git a/Allura/allura/model/oauth.py b/Allura/allura/model/oauth.py
index d467dc1..9d93d37 100644
--- a/Allura/allura/model/oauth.py
+++ b/Allura/allura/model/oauth.py
@@ -18,7 +18,7 @@
 import logging
 
 import oauth2 as oauth
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from paste.deploy.converters import aslist
 from tg import config
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 106f776..d4edf27 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -26,8 +26,8 @@ import re
 from xml.etree import ElementTree as ET
 
 from tg import config
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from paste.deploy.converters import asbool, aslist
 import formencode as fe
 from webob import exc
diff --git a/Allura/allura/model/repo_refresh.py b/Allura/allura/model/repo_refresh.py
index b6677b6..9712164 100644
--- a/Allura/allura/model/repo_refresh.py
+++ b/Allura/allura/model/repo_refresh.py
@@ -25,7 +25,7 @@ import bson
 import tg
 import jinja2
 from paste.deploy.converters import asint
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from ming.base import Object
 from ming.orm import mapper, session, ThreadLocalORMSession
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index dc97527..b4b6fa3 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -34,8 +34,8 @@ from difflib import SequenceMatcher
 
 import tg
 from paste.deploy.converters import asint, asbool
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 import pymongo
 import pymongo.errors
 import bson
diff --git a/Allura/allura/model/session.py b/Allura/allura/model/session.py
index 3399456..2ab5961 100644
--- a/Allura/allura/model/session.py
+++ b/Allura/allura/model/session.py
@@ -115,7 +115,7 @@ class ArtifactSessionExtension(ManagedSessionExtension):
     def after_flush(self, obj=None):
         "Update artifact references, and add/update this artifact to solr"
         if not getattr(self.session, 'disable_index', False):
-            from pylons import app_globals as g
+            from tg import app_globals as g
             from .index import ArtifactReference, Shortlink
             from .session import main_orm_session
             # Ensure artifact references & shortlinks exist for new objects
diff --git a/Allura/allura/model/timeline.py b/Allura/allura/model/timeline.py
index 66ecdaf..ee50462 100644
--- a/Allura/allura/model/timeline.py
+++ b/Allura/allura/model/timeline.py
@@ -19,7 +19,7 @@ import bson
 import logging
 
 from ming.odm import Mapper
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from activitystream import ActivityDirector
 from activitystream.base import NodeBase, ActivityObjectBase
diff --git a/Allura/allura/scripts/create_deleted_comments.py b/Allura/allura/scripts/create_deleted_comments.py
index 509752c..7b3c455 100644
--- a/Allura/allura/scripts/create_deleted_comments.py
+++ b/Allura/allura/scripts/create_deleted_comments.py
@@ -20,7 +20,7 @@ import argparse
 import logging
 
 from ming.odm import session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.scripts import ScriptTask
 from allura import model as M
diff --git a/Allura/allura/scripts/create_sitemap_files.py b/Allura/allura/scripts/create_sitemap_files.py
index 5bd3bb6..40e4642 100644
--- a/Allura/allura/scripts/create_sitemap_files.py
+++ b/Allura/allura/scripts/create_sitemap_files.py
@@ -33,9 +33,9 @@ from datetime import datetime
 import argparse
 
 from jinja2 import Template
-import pylons
+import tg
 import webob
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 from tg import config
 
@@ -78,11 +78,11 @@ class CreateSitemapFiles(ScriptTask):
     def execute(cls, options):
         # This script will indirectly call app.sidebar_menu() for every app in
         # every project. Some of the sidebar_menu methods expect the
-        # pylons.request threadlocal object to be present. So, we're faking it.
+        # tg.request threadlocal object to be present. So, we're faking it.
         #
         # The fact that this isn't a 'real' request doesn't matter for the
         # purposes of the sitemap.
-        pylons.request._push_object(webob.Request.blank('/'))
+        tg.request_local.context.request = webob.Request.blank('/')
 
         output_path = options.output_dir
         if os.path.exists(output_path):
diff --git a/Allura/allura/scripts/refresh_last_commits.py b/Allura/allura/scripts/refresh_last_commits.py
index 0dd7235..49b2772 100644
--- a/Allura/allura/scripts/refresh_last_commits.py
+++ b/Allura/allura/scripts/refresh_last_commits.py
@@ -21,7 +21,7 @@ from datetime import datetime
 from contextlib import contextmanager
 
 import faulthandler
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession, session
 
 from allura import model as M
diff --git a/Allura/allura/scripts/refreshrepo.py b/Allura/allura/scripts/refreshrepo.py
index 9050400..8556f87 100644
--- a/Allura/allura/scripts/refreshrepo.py
+++ b/Allura/allura/scripts/refreshrepo.py
@@ -21,7 +21,7 @@ import faulthandler
 from datetime import datetime
 
 from paste.util.converters import asbool
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 
 from allura import model as M
diff --git a/Allura/allura/scripts/reindex_projects.py b/Allura/allura/scripts/reindex_projects.py
index 0f8f3be..37ff222 100644
--- a/Allura/allura/scripts/reindex_projects.py
+++ b/Allura/allura/scripts/reindex_projects.py
@@ -19,7 +19,7 @@ import argparse
 import logging
 
 from pymongo.errors import InvalidDocument
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from allura.scripts import ScriptTask
 from allura import model as M
diff --git a/Allura/allura/tasks/activity_tasks.py b/Allura/allura/tasks/activity_tasks.py
index 312d9ec..f6bf8b6 100644
--- a/Allura/allura/tasks/activity_tasks.py
+++ b/Allura/allura/tasks/activity_tasks.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import app_globals as g
+from tg import app_globals as g
 from activitystream.storage.mingstorage import Activity
 
 from allura.lib.decorators import task
diff --git a/Allura/allura/tasks/admin_tasks.py b/Allura/allura/tasks/admin_tasks.py
index 65f2775..7a71444 100644
--- a/Allura/allura/tasks/admin_tasks.py
+++ b/Allura/allura/tasks/admin_tasks.py
@@ -17,7 +17,7 @@
 
 import inspect
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 from allura.lib.decorators import task
diff --git a/Allura/allura/tasks/export_tasks.py b/Allura/allura/tasks/export_tasks.py
index d63c40f..49771ae 100644
--- a/Allura/allura/tasks/export_tasks.py
+++ b/Allura/allura/tasks/export_tasks.py
@@ -21,7 +21,7 @@ import logging
 import shutil
 
 import tg
-from pylons import app_globals as g, tmpl_context as c
+from tg import app_globals as g, tmpl_context as c
 
 from allura.tasks import mail_tasks
 from allura.lib.decorators import task
diff --git a/Allura/allura/tasks/index_tasks.py b/Allura/allura/tasks/index_tasks.py
index 792eeab..631ec14 100644
--- a/Allura/allura/tasks/index_tasks.py
+++ b/Allura/allura/tasks/index_tasks.py
@@ -19,8 +19,8 @@ import sys
 import logging
 from contextlib import contextmanager
 
-from pylons import app_globals as g
-from pylons import tmpl_context as c
+from tg import app_globals as g
+from tg import tmpl_context as c
 
 from allura.lib import helpers as h
 from allura.lib.decorators import task
diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py
index 938f358..d60533f 100644
--- a/Allura/allura/tasks/mail_tasks.py
+++ b/Allura/allura/tasks/mail_tasks.py
@@ -19,7 +19,7 @@ import logging
 import HTMLParser
 import re
 
-from pylons import tmpl_context as c, app_globals as g, config
+from tg import tmpl_context as c, app_globals as g, config
 from bson import ObjectId
 import markupsafe
 
diff --git a/Allura/allura/tasks/repo_tasks.py b/Allura/allura/tasks/repo_tasks.py
index 41a1ba7..c84977f 100644
--- a/Allura/allura/tasks/repo_tasks.py
+++ b/Allura/allura/tasks/repo_tasks.py
@@ -19,7 +19,7 @@ import shutil
 import logging
 import traceback
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from ming.odm import session
 
 from allura.lib.decorators import task
diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index d54a6c2..7c42206 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -21,7 +21,7 @@ from functools import wraps
 import contextlib
 
 from ming.orm.ormsession import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from mock import patch
 import tg
 from paste.deploy.converters import asbool
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 6f2bd96..3b8d90a 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -27,7 +27,7 @@ import PIL
 from nose.tools import assert_equals, assert_in, assert_not_in, assert_is_not_none, assert_greater
 from ming.orm.ormsession import ThreadLocalORMSession
 from tg import expose
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 import mock
 
 from allura.tests import TestController
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index b0ddf5e..02c7823 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -42,7 +42,7 @@ from nose.tools import (
     assert_false,
     assert_raises
 )
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from webob import exc
 
 from allura.tests import TestController
diff --git a/Allura/allura/tests/functional/test_home.py b/Allura/allura/tests/functional/test_home.py
index 0dee4c7..cc7ccc2 100644
--- a/Allura/allura/tests/functional/test_home.py
+++ b/Allura/allura/tests/functional/test_home.py
@@ -19,7 +19,7 @@ import json
 import re
 import os
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_equal, assert_not_in, assert_in
 from ming.orm import ThreadLocalORMSession
 
diff --git a/Allura/allura/tests/functional/test_nav.py b/Allura/allura/tests/functional/test_nav.py
index 0945d09..8fb2f78 100644
--- a/Allura/allura/tests/functional/test_nav.py
+++ b/Allura/allura/tests/functional/test_nav.py
@@ -18,7 +18,7 @@
 import mock
 import json
 from tg import config
-from pylons import app_globals as g
+from tg import app_globals as g
 
 from allura.tests import TestController
 from allura.lib import helpers as h
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index 55a492c..dd22da4 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -27,7 +27,7 @@ from tg import config
 from nose.tools import assert_equal, assert_in, assert_not_equal
 from ming.orm.ormsession import ThreadLocalORMSession, session
 from paste.httpexceptions import HTTPFound
-from pylons import app_globals as g, tmpl_context as c
+from tg import app_globals as g, tmpl_context as c
 
 import allura
 from allura import model as M
@@ -908,7 +908,7 @@ class TestNeighborhood(TestController):
                       extra_environ=dict(username='root'))
 
     def test_add_a_project_link(self):
-        from pylons import tmpl_context as c
+        from tg import tmpl_context as c
         # Install Home tool for all neighborhoods
         for nb in M.Neighborhood.query.find().all():
             p = nb.neighborhood_project
diff --git a/Allura/allura/tests/functional/test_personal_dashboard.py b/Allura/allura/tests/functional/test_personal_dashboard.py
index 5e397fc..dc2685e 100644
--- a/Allura/allura/tests/functional/test_personal_dashboard.py
+++ b/Allura/allura/tests/functional/test_personal_dashboard.py
@@ -21,7 +21,7 @@ import tg
 
 from ming.orm import ThreadLocalORMSession, ThreadLocalODMSession
 from nose.tools import assert_equal, assert_in, assert_not_in
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 from allura.lib import helpers as h
diff --git a/Allura/allura/tests/functional/test_rest.py b/Allura/allura/tests/functional/test_rest.py
index 306cdbc..8d12950 100644
--- a/Allura/allura/tests/functional/test_rest.py
+++ b/Allura/allura/tests/functional/test_rest.py
@@ -17,7 +17,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import app_globals as g
+from tg import app_globals as g
 import mock
 from nose.tools import assert_equal, assert_in, assert_not_in
 from ming.odm import ThreadLocalODMSession
diff --git a/Allura/allura/tests/functional/test_root.py b/Allura/allura/tests/functional/test_root.py
index be81292..dfb11f7 100644
--- a/Allura/allura/tests/functional/test_root.py
+++ b/Allura/allura/tests/functional/test_root.py
@@ -28,7 +28,7 @@ functional tests exercise the whole application and its WSGI stack.
 Please read http://pythonpaste.org/webtest/ for more information.
 
 """
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_equal
 from ming.orm.ormsession import ThreadLocalORMSession
 import mock
diff --git a/Allura/allura/tests/functional/test_site_admin.py b/Allura/allura/tests/functional/test_site_admin.py
index c46e2b1..cb61e58 100644
--- a/Allura/allura/tests/functional/test_site_admin.py
+++ b/Allura/allura/tests/functional/test_site_admin.py
@@ -23,7 +23,7 @@ import bson
 from mock import patch, MagicMock
 from nose.tools import assert_equal, assert_in, assert_not_in
 from ming.odm import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import config
 from bson import ObjectId
 
diff --git a/Allura/allura/tests/model/test_artifact.py b/Allura/allura/tests/model/test_artifact.py
index 017d0d3..1e63813 100644
--- a/Allura/allura/tests/model/test_artifact.py
+++ b/Allura/allura/tests/model/test_artifact.py
@@ -23,7 +23,7 @@ Model tests for artifact
 import re
 from datetime import datetime
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_raises, assert_equal
 from nose import with_setup
 from mock import patch
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 5d1841b..79234e2 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -29,7 +29,7 @@ from nose.tools import (
     assert_not_in,
     assert_in,
 )
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from webob import Request
 from mock import patch, Mock
 from datetime import datetime, timedelta
diff --git a/Allura/allura/tests/model/test_discussion.py b/Allura/allura/tests/model/test_discussion.py
index 0258f38..d470c87 100644
--- a/Allura/allura/tests/model/test_discussion.py
+++ b/Allura/allura/tests/model/test_discussion.py
@@ -25,7 +25,7 @@ import time
 from datetime import datetime, timedelta
 from cgi import FieldStorage
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_equals, with_setup
 import mock
 from mock import patch
diff --git a/Allura/allura/tests/model/test_filesystem.py b/Allura/allura/tests/model/test_filesystem.py
index 1f4c1da..30ab9e9 100644
--- a/Allura/allura/tests/model/test_filesystem.py
+++ b/Allura/allura/tests/model/test_filesystem.py
@@ -22,7 +22,7 @@ from unittest import TestCase
 from cStringIO import StringIO
 from io import BytesIO
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import session, Mapper
 from nose.tools import assert_equal
 from mock import patch
@@ -126,7 +126,7 @@ class TestFile(TestCase):
         f = File.from_data(u'te s\u0b6e1.txt', 'test1')
         self.session.flush()
         with patch('allura.lib.utils.tg.request', Request.blank('/')), \
-                patch('allura.lib.utils.pylons.response', Response()) as response, \
+                patch('allura.lib.utils.tg.response', Response()) as response, \
                 patch('allura.lib.utils.etag_cache') as etag_cache:
             response_body = list(f.serve())
             etag_cache.assert_called_once_with(u'{}?{}'.format(f.filename,
@@ -139,7 +139,7 @@ class TestFile(TestCase):
         f = File.from_data(u'te s\u0b6e1.txt', 'test1')
         self.session.flush()
         with patch('allura.lib.utils.tg.request', Request.blank('/')), \
-                patch('allura.lib.utils.pylons.response', Response()) as response, \
+                patch('allura.lib.utils.tg.response', Response()) as response, \
                 patch('allura.lib.utils.etag_cache') as etag_cache:
             response_body = list(f.serve(embed=False))
             etag_cache.assert_called_once_with(u'{}?{}'.format(f.filename,
diff --git a/Allura/allura/tests/model/test_notification.py b/Allura/allura/tests/model/test_notification.py
index f4ba56e..91f88d4 100644
--- a/Allura/allura/tests/model/test_notification.py
+++ b/Allura/allura/tests/model/test_notification.py
@@ -19,7 +19,7 @@ import unittest
 from datetime import timedelta
 import collections
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from nose.tools import assert_equal, assert_in
 from ming.orm import ThreadLocalORMSession
 import mock
diff --git a/Allura/allura/tests/model/test_project.py b/Allura/allura/tests/model/test_project.py
index 2fe3dc8..84eb0af 100644
--- a/Allura/allura/tests/model/test_project.py
+++ b/Allura/allura/tests/model/test_project.py
@@ -22,7 +22,7 @@ Model tests for project
 """
 from nose import with_setup
 from nose.tools import assert_equals, assert_in
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 from formencode import validators as fev
 
diff --git a/Allura/allura/tests/model/test_repo.py b/Allura/allura/tests/model/test_repo.py
index 1020031..95263dc 100644
--- a/Allura/allura/tests/model/test_repo.py
+++ b/Allura/allura/tests/model/test_repo.py
@@ -21,7 +21,7 @@ from collections import defaultdict, OrderedDict
 import unittest
 import mock
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from bson import ObjectId
 from ming.orm import session
 from tg import config
diff --git a/Allura/allura/tests/scripts/test_create_sitemap_files.py b/Allura/allura/tests/scripts/test_create_sitemap_files.py
index df00e98..6f5f1b9 100644
--- a/Allura/allura/tests/scripts/test_create_sitemap_files.py
+++ b/Allura/allura/tests/scripts/test_create_sitemap_files.py
@@ -19,7 +19,7 @@ import os
 from shutil import rmtree
 import xml.etree.ElementTree as ET
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_in
 from testfixtures import TempDirectory
 
diff --git a/Allura/allura/tests/scripts/test_delete_projects.py b/Allura/allura/tests/scripts/test_delete_projects.py
index d0f8620..c128f8c 100644
--- a/Allura/allura/tests/scripts/test_delete_projects.py
+++ b/Allura/allura/tests/scripts/test_delete_projects.py
@@ -17,7 +17,7 @@
 
 from ming.odm import session, Mapper, ThreadLocalODMSession
 from mock import patch
-from pylons import app_globals as g
+from tg import app_globals as g
 from nose.tools import assert_equal
 
 from alluratest.controller import TestController
@@ -100,8 +100,8 @@ class TestDeleteProjects(TestController):
         del_solr.post.assert_called_once_with(pid)
 
     @with_user_project('test-user')
-    @patch('allura.model.auth.request', autospec=True)
-    @patch('allura.lib.helpers.request', autospec=True)
+    @patch('allura.model.auth.request')
+    @patch('allura.lib.helpers.request')
     def test_userproject_does_disable(self, req, req2):
         req.remote_addr = None
         req.user_agent = 'MozFoo'
@@ -146,8 +146,8 @@ class TestDeleteProjects(TestController):
         assert admin.disabled is disable
         assert dev.disabled is disable
 
-    @patch('allura.model.auth.request', autospec=True)
-    @patch('allura.lib.helpers.request', autospec=True)
+    @patch('allura.model.auth.request')
+    @patch('allura.lib.helpers.request')
     def test_disable_users(self, req, req2):
         req.remote_addr = None
         req.user_agent = 'MozFoo'
diff --git a/Allura/allura/tests/templates/jinja_master/test_lib.py b/Allura/allura/tests/templates/jinja_master/test_lib.py
index 2fccafc..b818560 100644
--- a/Allura/allura/tests/templates/jinja_master/test_lib.py
+++ b/Allura/allura/tests/templates/jinja_master/test_lib.py
@@ -32,7 +32,7 @@ class TemplateTest(object):
         setup_config_test()
         forge_config = ForgeConfig()
         forge_config.setup_jinja_renderer()
-        self.jinja2_env = config['pylons.app_globals'].jinja2_env
+        self.jinja2_env = config['tg.app_globals'].jinja2_env
 
 
 class TestRelatedArtifacts(TemplateTest):
diff --git a/Allura/allura/tests/test_app.py b/Allura/allura/tests/test_app.py
index 926a71b..3ddbd04 100644
--- a/Allura/allura/tests/test_app.py
+++ b/Allura/allura/tests/test_app.py
@@ -17,7 +17,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 import mock
 from ming.base import Object
 from nose.tools import assert_equal, assert_raises
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index 2b1cce2..b233479 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -28,7 +28,7 @@ from mock import patch, Mock
 
 from bson import ObjectId
 from nose.tools import with_setup, assert_equal, assert_in, assert_not_in
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 import tg
 
 from ming.orm import ThreadLocalORMSession
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 65c44ac..bada67c 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -24,7 +24,7 @@ import time
 
 import PIL
 from mock import Mock, patch
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import eq_, assert_equals, assert_raises
 from IPython.testing.decorators import skipif, module_not_available
 from datadiff import tools as dd
diff --git a/Allura/allura/tests/test_plugin.py b/Allura/allura/tests/test_plugin.py
index 20c6059..8ccf5d5 100644
--- a/Allura/allura/tests/test_plugin.py
+++ b/Allura/allura/tests/test_plugin.py
@@ -19,7 +19,7 @@ import datetime as dt
 import calendar
 
 import tg
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from webob import Request, exc
 from bson import ObjectId
 from ming.orm.ormsession import ThreadLocalORMSession
@@ -253,8 +253,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_no_note(self, request, response, SiteNotification):
         SiteNotification.current.return_value = None
         assert_is_none(ThemeProvider().get_site_notification())
@@ -262,8 +262,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_closed(self, request, response, SiteNotification):
         SiteNotification.current.return_value._id = 'deadbeef'
         SiteNotification.current.return_value.user_role = None
@@ -275,8 +275,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_impressions_over(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -290,8 +290,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_impressions_under(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -306,8 +306,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_impressions_persistent(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -320,8 +320,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_new_notification(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -336,8 +336,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_no_cookie(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -352,8 +352,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response')
-    @patch('pylons.request')
+    @patch('tg.response')
+    @patch('tg.request')
     def test_get_site_notification_bad_cookie(self, request, response, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'deadbeef'
@@ -397,8 +397,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c')
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response', MagicMock())
-    @patch('pylons.request', MagicMock())
+    @patch('tg.response', MagicMock())
+    @patch('tg.request', MagicMock())
     def test_get_site_notification_with_role(self, SiteNotification, c):
         note = SiteNotification.current.return_value
         note.user_role = 'Test'
@@ -425,8 +425,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response', MagicMock())
-    @patch('pylons.request', MagicMock())
+    @patch('tg.response', MagicMock())
+    @patch('tg.request', MagicMock())
     def test_get_site_notification_without_role(self, SiteNotification):
         note = SiteNotification.current.return_value
         note.user_role = None
@@ -437,8 +437,8 @@ class TestThemeProvider(object):
     @patch('allura.lib.plugin.c', MagicMock())
     @patch('re.search')
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response', MagicMock())
-    @patch('pylons.request', MagicMock())
+    @patch('tg.response', MagicMock())
+    @patch('tg.request', MagicMock())
     def test_get_site_notification_with_page_regex(self, SiteNotification, search):
         note = SiteNotification.current.return_value
         note.user_role = None
@@ -453,8 +453,8 @@ class TestThemeProvider(object):
 
     @patch('allura.lib.plugin.c')
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response', MagicMock())
-    @patch('pylons.request', MagicMock())
+    @patch('tg.response', MagicMock())
+    @patch('tg.request', MagicMock())
     def test_get_site_notification_with_page_tool_type(self, SiteNotification, c):
         note = SiteNotification.current.return_value
         note.user_role = None
@@ -472,10 +472,9 @@ class TestThemeProvider(object):
         assert_is(ThemeProvider().get_site_notification(), None)
 
     @patch('allura.lib.plugin.c')
-    @patch('pylons.request')
+    @patch('tg.request')
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.response', MagicMock())
-    @patch('pylons.request', MagicMock())
+    @patch('tg.response', MagicMock())
     def test_get_site_notification_with_page_tool_type_page_regex(self, SiteNotification, request, c):
         note = SiteNotification.current.return_value
         note.user_role = None
@@ -518,7 +517,7 @@ class TestThemeProvider(object):
         assert get_note[1] == 'test_id-1-False'
 
     @patch('allura.model.notification.SiteNotification')
-    @patch('pylons.request')
+    @patch('tg.request')
     def test_get_site_notifications_with_api_cookie(self, request, SiteNotification):
         note = SiteNotification.current.return_value
         note._id = 'test_id'
diff --git a/Allura/allura/tests/test_security.py b/Allura/allura/tests/test_security.py
index 44b2831..940388c 100644
--- a/Allura/allura/tests/test_security.py
+++ b/Allura/allura/tests/test_security.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_equal
 
 from ming.odm import ThreadLocalODMSession
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 2d27256..274a291 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -26,7 +26,7 @@ import logging
 
 import tg
 import mock
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from datadiff.tools import assert_equal
 from nose.tools import assert_in, assert_less
 from ming.orm import FieldProperty, Mapper
diff --git a/Allura/allura/tests/test_webhooks.py b/Allura/allura/tests/test_webhooks.py
index 5b8df07..3b5a004 100644
--- a/Allura/allura/tests/test_webhooks.py
+++ b/Allura/allura/tests/test_webhooks.py
@@ -30,7 +30,7 @@ from nose.tools import (
 from datadiff import tools as dd
 from formencode import Invalid
 from ming.odm import session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import config
 
 from allura import model as M
diff --git a/Allura/allura/tests/unit/patches.py b/Allura/allura/tests/unit/patches.py
index afd5758..eaa6404 100644
--- a/Allura/allura/tests/unit/patches.py
+++ b/Allura/allura/tests/unit/patches.py
@@ -16,7 +16,7 @@
 #       under the License.
 
 from mock import Mock, patch
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.tests.unit.factories import (
     create_project,
diff --git a/Allura/allura/tests/unit/test_helpers/test_set_context.py b/Allura/allura/tests/unit/test_helpers/test_set_context.py
index 8b56a0f..89e5977 100644
--- a/Allura/allura/tests/unit/test_helpers/test_set_context.py
+++ b/Allura/allura/tests/unit/test_helpers/test_set_context.py
@@ -16,7 +16,7 @@
 #       under the License.
 
 from nose.tools import assert_raises
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from bson import ObjectId
 
 from allura.lib.helpers import set_context
diff --git a/Allura/allura/tests/unit/test_post_model.py b/Allura/allura/tests/unit/test_post_model.py
index f972688..2f9a4d3 100644
--- a/Allura/allura/tests/unit/test_post_model.py
+++ b/Allura/allura/tests/unit/test_post_model.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.lib import helpers as h
 from allura import model as M
diff --git a/Allura/allura/tests/unit/test_repo.py b/Allura/allura/tests/unit/test_repo.py
index 33c10d3..786d413 100644
--- a/Allura/allura/tests/unit/test_repo.py
+++ b/Allura/allura/tests/unit/test_repo.py
@@ -21,7 +21,7 @@ from mock import patch, Mock, MagicMock, call
 from nose.tools import assert_equal
 from datadiff import tools as dd
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 from allura.controllers.repository import topo_sort
diff --git a/Allura/allura/webhooks.py b/Allura/allura/webhooks.py
index d902e71..57871e6 100644
--- a/Allura/allura/webhooks.py
+++ b/Allura/allura/webhooks.py
@@ -27,8 +27,8 @@ import requests
 from bson import ObjectId
 from tg import expose, validate, redirect, flash, config
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c
-from pylons import response, request
+from tg import tmpl_context as c
+from tg import response, request
 from formencode import validators as fev, schema, Invalid
 from ming.odm import session
 from webob import exc
diff --git a/Allura/allura/websetup/bootstrap.py b/Allura/allura/websetup/bootstrap.py
index fbbc211..d282b5d 100644
--- a/Allura/allura/websetup/bootstrap.py
+++ b/Allura/allura/websetup/bootstrap.py
@@ -25,7 +25,7 @@ import shutil
 from textwrap import dedent
 
 import tg
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from paste.deploy.converters import asbool
 import ew
 
diff --git a/Allura/allura/websetup/schema.py b/Allura/allura/websetup/schema.py
index 88c57a4..86b0f39 100644
--- a/Allura/allura/websetup/schema.py
+++ b/Allura/allura/websetup/schema.py
@@ -22,10 +22,11 @@
 import logging
 
 import activitystream
+import tg
 from tg import config
-import pylons
 from paste.deploy.converters import asbool
-from paste.registry import Registry
+from tg.support.registry import Registry
+from tg.wsgiapp import RequestLocals
 
 from allura.lib import helpers as h
 
@@ -38,10 +39,15 @@ def setup_schema(command, conf, vars):
     import ming
     import allura
 
+    # turbogears has its own special magic wired up for its globals, can't use a regular Registry
+    tgl = RequestLocals()
+    tgl.tmpl_context = EmptyClass()
+    tgl.app_globals = config['tg.app_globals']
+    tg.request_local.context._push_object(tgl)
+
     REGISTRY.prepare()
-    REGISTRY.register(pylons.tmpl_context, EmptyClass())
-    REGISTRY.register(pylons.app_globals, config['pylons.app_globals'])
     REGISTRY.register(allura.credentials, allura.lib.security.Credentials())
+
     ming.configure(**conf)
     if asbool(conf.get('activitystream.recording.enabled', False)):
         activitystream.configure(**h.convert_bools(conf, prefix='activitystream.'))
diff --git a/Allura/docs/development/testing.rst b/Allura/docs/development/testing.rst
index bcff43f..69e9c97 100644
--- a/Allura/docs/development/testing.rst
+++ b/Allura/docs/development/testing.rst
@@ -60,7 +60,7 @@ fully-loaded wsgi app, you can do something like this:
 
 .. code-block:: python
 
-    from pylons import tmpl_context as c
+    from tg import tmpl_context as c
 
     from alluratest.controller import setup_unit_test
     from allura.lib import helpers a h
diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index b28af46..4ce4e31 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -26,10 +26,10 @@ from formencode import variabledecode
 from paste.deploy import loadapp
 from paste.deploy.converters import asbool
 from paste.script.appinstall import SetupCommand
-from pylons import tmpl_context as c, app_globals as g
-from pylons import url, request, response, session
-import pylons
+from tg import tmpl_context as c, app_globals as g
+from tg import url, request, response, session
 import tg
+from tg.wsgiapp import RequestLocals
 from webob import Response, Request
 import ew
 from ming.orm import ThreadLocalORMSession
@@ -84,7 +84,7 @@ def setup_config_test(config_file=None, force=False):
     '''
     if not config_file:
         config_file = get_config_file()
-    already_loaded = pylons.config.get('pylons.app_globals')
+    already_loaded = tg.config.get('tg.app_globals')
     if not already_loaded or force:
         loadapp('config:' + config_file)
 setup_config_test.__test__ = False
@@ -132,12 +132,17 @@ def setup_unit_test():
     REGISTRY.prepare()
     REGISTRY.register(ew.widget_context,
                       ew.core.WidgetContext('http', ew.ResourceManager()))
-    REGISTRY.register(g, Globals())
-    REGISTRY.register(c, mock.Mock())
-    REGISTRY.register(url, lambda: None)
-    REGISTRY.register(request, Request.blank('/', remote_addr='127.0.0.1'))
-    REGISTRY.register(response, Response())
     REGISTRY.register(allura.credentials, allura.lib.security.Credentials())
+
+    # turbogears has its own special magic wired up for its globals, can't use a regular Registry
+    tgl = RequestLocals()
+    tgl.app_globals = Globals()
+    tgl.tmpl_context = mock.Mock()
+    tgl.url = lambda: None
+    tgl.request = Request.blank('/', remote_addr='127.0.0.1')
+    tgl.response = Response()
+    tg.request_local.context._push_object(tgl)
+
     c.model_cache = None
     ThreadLocalORMSession.close_all()
 setup_unit_test.__test__ = False  # sometimes __test__ above isn't sufficient
diff --git a/ForgeActivity/forgeactivity/main.py b/ForgeActivity/forgeactivity/main.py
index 0786db6..d66a9b2 100644
--- a/ForgeActivity/forgeactivity/main.py
+++ b/ForgeActivity/forgeactivity/main.py
@@ -22,8 +22,8 @@ from itertools import islice, ifilter
 
 from bson import ObjectId
 from ming.orm import session
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request, response
+from tg import tmpl_context as c, app_globals as g
+from tg import request, response
 from tg import expose, validate, config
 from tg.decorators import with_trailing_slash, without_trailing_slash
 from paste.deploy.converters import asbool, asint
diff --git a/ForgeActivity/forgeactivity/tests/functional/test_root.py b/ForgeActivity/forgeactivity/tests/functional/test_root.py
index a2a812e..e41f7fc 100644
--- a/ForgeActivity/forgeactivity/tests/functional/test_root.py
+++ b/ForgeActivity/forgeactivity/tests/functional/test_root.py
@@ -22,7 +22,7 @@ from tg import config
 from bson import ObjectId
 import dateutil.parser
 from nose.tools import assert_equal
-from pylons import app_globals as g
+from tg import app_globals as g
 from activitystream.storage.mingstorage import Activity
 from ming.odm import ThreadLocalODMSession
 
diff --git a/ForgeActivity/forgeactivity/widgets/follow.py b/ForgeActivity/forgeactivity/widgets/follow.py
index 1aed295..97e2f97 100644
--- a/ForgeActivity/forgeactivity/widgets/follow.py
+++ b/ForgeActivity/forgeactivity/widgets/follow.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from formencode import validators as fev
 import ew as ew_core
 import ew.jinja2_ew as ew
diff --git a/ForgeBlog/forgeblog/command/rssfeeds.py b/ForgeBlog/forgeblog/command/rssfeeds.py
index 42b5edd..3cce7f3 100644
--- a/ForgeBlog/forgeblog/command/rssfeeds.py
+++ b/ForgeBlog/forgeblog/command/rssfeeds.py
@@ -25,7 +25,7 @@ import base
 from allura.command import base as allura_base
 
 from ming.orm import session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 from forgeblog import model as BM
@@ -59,9 +59,9 @@ class RssFeedsCommand(base.BlogCommand):
         # activity, User.url() will be called. This method defers to an
         # AuthenticationProvider, which depends on a request being setup in
         # the current thread. So, we set one up here.
-        import pylons
+        import tg
         import webob
-        pylons.request._push_object(webob.Request.blank('/'))
+        tg.request_local.context.request = webob.Request.blank('/')
 
         self.basic_setup()
         self.process_feed = exceptionless(
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 407e435..1cf9099 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -24,9 +24,9 @@ import json
 import pymongo
 from tg import config, expose, validate, redirect, flash, jsonify
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c
-from pylons import app_globals as g
-from pylons import request
+from tg import tmpl_context as c
+from tg import app_globals as g
+from tg import request
 from paste.deploy.converters import asbool
 import formencode
 from formencode import validators
diff --git a/ForgeBlog/forgeblog/model/blog.py b/ForgeBlog/forgeblog/model/blog.py
index 0cbd8df..5fafd43 100644
--- a/ForgeBlog/forgeblog/model/blog.py
+++ b/ForgeBlog/forgeblog/model/blog.py
@@ -21,7 +21,7 @@ import re
 from datetime import datetime
 from random import randint
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from tg import config as tg_config
 from pymongo.errors import DuplicateKeyError
 
diff --git a/ForgeBlog/forgeblog/tests/functional/test_feeds.py b/ForgeBlog/forgeblog/tests/functional/test_feeds.py
index d5f29e8..39a090c 100644
--- a/ForgeBlog/forgeblog/tests/functional/test_feeds.py
+++ b/ForgeBlog/forgeblog/tests/functional/test_feeds.py
@@ -20,7 +20,7 @@ import datetime
 
 from nose.tools import assert_in, assert_not_in
 from ming.orm.ormsession import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from alluratest.controller import TestController
 from allura import model as M
diff --git a/ForgeBlog/forgeblog/tests/test_app.py b/ForgeBlog/forgeblog/tests/test_app.py
index e043929..ac50f8b 100644
--- a/ForgeBlog/forgeblog/tests/test_app.py
+++ b/ForgeBlog/forgeblog/tests/test_app.py
@@ -22,7 +22,7 @@ import json
 import os
 
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from cStringIO import StringIO
 from ming.orm import ThreadLocalORMSession
 
diff --git a/ForgeBlog/forgeblog/tests/test_commands.py b/ForgeBlog/forgeblog/tests/test_commands.py
index 7f2d0f7..6fb32fe 100644
--- a/ForgeBlog/forgeblog/tests/test_commands.py
+++ b/ForgeBlog/forgeblog/tests/test_commands.py
@@ -16,7 +16,7 @@
 #       under the License.
 
 from datetime import datetime, timedelta
-from pylons import app_globals as g
+from tg import app_globals as g
 from datadiff.tools import assert_equal
 from IPython.testing.decorators import module_not_available, skipif
 import pkg_resources
diff --git a/ForgeBlog/forgeblog/tests/test_roles.py b/ForgeBlog/forgeblog/tests/test_roles.py
index e270bec..3fe6a64 100644
--- a/ForgeBlog/forgeblog/tests/test_roles.py
+++ b/ForgeBlog/forgeblog/tests/test_roles.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura import model as M
diff --git a/ForgeBlog/forgeblog/tests/unit/__init__.py b/ForgeBlog/forgeblog/tests/unit/__init__.py
index dbef2b5..565758a 100644
--- a/ForgeBlog/forgeblog/tests/unit/__init__.py
+++ b/ForgeBlog/forgeblog/tests/unit/__init__.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 
 from allura.websetup import bootstrap
diff --git a/ForgeBlog/forgeblog/tests/unit/test_blog_post.py b/ForgeBlog/forgeblog/tests/unit/test_blog_post.py
index fadfcf0..b62447e 100644
--- a/ForgeBlog/forgeblog/tests/unit/test_blog_post.py
+++ b/ForgeBlog/forgeblog/tests/unit/test_blog_post.py
@@ -17,7 +17,7 @@
 
 from datetime import datetime
 from nose.tools import assert_equal, assert_true
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from forgeblog import model as M
 from forgeblog.tests.unit import BlogTestWithModel
diff --git a/ForgeChat/forgechat/main.py b/ForgeChat/forgechat/main.py
index 8e01426..981af26 100644
--- a/ForgeChat/forgechat/main.py
+++ b/ForgeChat/forgechat/main.py
@@ -24,7 +24,7 @@ from datetime import date, time, datetime, timedelta
 # Non-stdlib imports
 from tg import expose, validate, redirect, flash
 from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c, request
+from tg import tmpl_context as c, request
 from formencode import validators
 
 # Pyforge-specific imports
diff --git a/ForgeDiscussion/forgediscussion/controllers/forum.py b/ForgeDiscussion/forgediscussion/controllers/forum.py
index 338764d..8fc2d6b 100644
--- a/ForgeDiscussion/forgediscussion/controllers/forum.py
+++ b/ForgeDiscussion/forgediscussion/controllers/forum.py
@@ -23,7 +23,7 @@ from allura.lib.search import mapped_artifacts_from_index_ids
 
 from tg import expose, validate, redirect
 from tg import request
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from webob import exc
 from formencode import validators
 
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index 7ba008c..0a12864 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -25,8 +25,8 @@ from collections import OrderedDict
 
 from tg import expose, validate, redirect, flash
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from formencode import validators
 from webob import exc
 import pymongo
diff --git a/ForgeDiscussion/forgediscussion/forum_main.py b/ForgeDiscussion/forgediscussion/forum_main.py
index 7e957a3..311886f 100644
--- a/ForgeDiscussion/forgediscussion/forum_main.py
+++ b/ForgeDiscussion/forgediscussion/forum_main.py
@@ -22,8 +22,8 @@ import json
 import os
 
 # Non-stdlib imports
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from tg import expose, redirect, flash, validate, jsonify
 from tg.decorators import with_trailing_slash
 from bson import ObjectId
diff --git a/ForgeDiscussion/forgediscussion/import_support.py b/ForgeDiscussion/forgediscussion/import_support.py
index 5318ec5..a5a3cc0 100644
--- a/ForgeDiscussion/forgediscussion/import_support.py
+++ b/ForgeDiscussion/forgediscussion/import_support.py
@@ -22,7 +22,7 @@ from datetime import datetime
 from ming import schema as S
 from ming.orm import ThreadLocalORMSession, session
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 
diff --git a/ForgeDiscussion/forgediscussion/model/forum.py b/ForgeDiscussion/forgediscussion/model/forum.py
index 481fe92..5bc91f4 100644
--- a/ForgeDiscussion/forgediscussion/model/forum.py
+++ b/ForgeDiscussion/forgediscussion/model/forum.py
@@ -20,7 +20,7 @@ import logging
 from itertools import chain
 
 import pymongo
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming import schema
 from ming.utils import LazyProperty
 from ming.orm import FieldProperty, RelationProperty, ForeignIdProperty, Mapper
diff --git a/ForgeDiscussion/forgediscussion/tasks.py b/ForgeDiscussion/forgediscussion/tasks.py
index 9566818..cfd5320 100644
--- a/ForgeDiscussion/forgediscussion/tasks.py
+++ b/ForgeDiscussion/forgediscussion/tasks.py
@@ -17,7 +17,7 @@
 
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from allura.lib.decorators import task
 
 log = logging.getLogger(__name__)
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
index 421f49a..44cc42f 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
@@ -29,7 +29,7 @@ import pymongo
 import webtest
 
 from ming.odm import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import config
 
 from nose.tools import assert_equal, assert_in, assert_not_in, assert_true, assert_false, assert_raises
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_import.py b/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
index 38290e8..879b21c 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_import.py
@@ -22,7 +22,7 @@ from nose.tools import assert_equal
 
 import ming
 from tg import config
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura import model as M
 from allura.lib import helpers as h
diff --git a/ForgeDiscussion/forgediscussion/tests/test_app.py b/ForgeDiscussion/forgediscussion/tests/test_app.py
index 90f83bf..4e23cfa 100644
--- a/ForgeDiscussion/forgediscussion/tests/test_app.py
+++ b/ForgeDiscussion/forgediscussion/tests/test_app.py
@@ -25,7 +25,7 @@ import os
 from operator import attrgetter
 
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from cStringIO import StringIO
 from ming.orm import ThreadLocalORMSession
 from cgi import FieldStorage
diff --git a/ForgeDiscussion/forgediscussion/tests/test_forum_roles.py b/ForgeDiscussion/forgediscussion/tests/test_forum_roles.py
index 44d6989..4bc0eef 100644
--- a/ForgeDiscussion/forgediscussion/tests/test_forum_roles.py
+++ b/ForgeDiscussion/forgediscussion/tests/test_forum_roles.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura import model as M
diff --git a/ForgeDiscussion/forgediscussion/widgets/forum_widgets.py b/ForgeDiscussion/forgediscussion/widgets/forum_widgets.py
index 3dbe2c7..5dba9f2 100644
--- a/ForgeDiscussion/forgediscussion/widgets/forum_widgets.py
+++ b/ForgeDiscussion/forgediscussion/widgets/forum_widgets.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from formencode import validators as fev
 
 import ew as ew_core
diff --git a/ForgeGit/forgegit/controllers.py b/ForgeGit/forgegit/controllers.py
index 93e9364..d939576 100644
--- a/ForgeGit/forgegit/controllers.py
+++ b/ForgeGit/forgegit/controllers.py
@@ -17,7 +17,7 @@
 
 from tg import expose, redirect
 from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.controllers import repository
 
diff --git a/ForgeGit/forgegit/git_main.py b/ForgeGit/forgegit/git_main.py
index cfdb7b0..27abc42 100644
--- a/ForgeGit/forgegit/git_main.py
+++ b/ForgeGit/forgegit/git_main.py
@@ -19,7 +19,7 @@
 import logging
 
 # Non-stdlib imports
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.utils import LazyProperty
 from ming.orm.ormsession import ThreadLocalORMSession
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index f75e21f..3b4d237 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -27,7 +27,7 @@ from time import time
 import tg
 import git
 import gitdb
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from pymongo.errors import DuplicateKeyError
 from paste.deploy.converters import asbool
 
diff --git a/ForgeGit/forgegit/tests/functional/test_controllers.py b/ForgeGit/forgegit/tests/functional/test_controllers.py
index 4bcffce..a4db828 100644
--- a/ForgeGit/forgegit/tests/functional/test_controllers.py
+++ b/ForgeGit/forgegit/tests/functional/test_controllers.py
@@ -28,7 +28,7 @@ from nose.tools import assert_equal, assert_in, assert_not_in, assert_not_equal,
 import tg
 import pkg_resources
 from nose.tools import assert_regexp_matches
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 from mock import patch, PropertyMock
 
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index 9412cb4..e277ce0 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -26,7 +26,7 @@ import datetime
 import email.iterators
 
 import mock
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 import tg
 from ming.base import Object
 from ming.orm import ThreadLocalORMSession, session
diff --git a/ForgeGit/forgegit/tests/test_git_app.py b/ForgeGit/forgegit/tests/test_git_app.py
index 0566249..c03e242 100644
--- a/ForgeGit/forgegit/tests/test_git_app.py
+++ b/ForgeGit/forgegit/tests/test_git_app.py
@@ -18,7 +18,7 @@
 import unittest
 from nose.tools import assert_equals
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 
 from alluratest.controller import setup_basic_test, setup_global_objects
diff --git a/ForgeGit/forgegit/tests/test_tasks.py b/ForgeGit/forgegit/tests/test_tasks.py
index 3f003d6..26d1ee5 100644
--- a/ForgeGit/forgegit/tests/test_tasks.py
+++ b/ForgeGit/forgegit/tests/test_tasks.py
@@ -19,7 +19,7 @@ import unittest
 import mock
 
 from ming.orm import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura.lib import helpers as h
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index fb2fa21..e6a64b9 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -32,8 +32,8 @@ except ImportError:
 from BeautifulSoup import BeautifulSoup
 from tg import expose, validate, flash, redirect, config
 from tg.decorators import with_trailing_slash
-from pylons import app_globals as g
-from pylons import tmpl_context as c
+from tg import app_globals as g
+from tg import tmpl_context as c
 from formencode import validators as fev, schema
 from webob import exc
 
diff --git a/ForgeImporters/forgeimporters/forge/tracker.py b/ForgeImporters/forgeimporters/forge/tracker.py
index 2937b63..32ec0eb 100644
--- a/ForgeImporters/forgeimporters/forge/tracker.py
+++ b/ForgeImporters/forgeimporters/forge/tracker.py
@@ -19,8 +19,8 @@ import os
 import json
 
 import dateutil.parser
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 from ming.orm import session, ThreadLocalORMSession
 
 from tg import (
diff --git a/ForgeImporters/forgeimporters/github/__init__.py b/ForgeImporters/forgeimporters/github/__init__.py
index 1dc4ca1..e294ee1 100644
--- a/ForgeImporters/forgeimporters/github/__init__.py
+++ b/ForgeImporters/forgeimporters/github/__init__.py
@@ -24,7 +24,7 @@ from datetime import datetime
 
 from tg import config, session, redirect, request, expose
 from tg.decorators import without_trailing_slash
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from requests_oauthlib import OAuth2Session
 import requests
 from formencode import validators as fev
diff --git a/ForgeImporters/forgeimporters/github/code.py b/ForgeImporters/forgeimporters/github/code.py
index 410b3bb..9d6e5f5 100644
--- a/ForgeImporters/forgeimporters/github/code.py
+++ b/ForgeImporters/forgeimporters/github/code.py
@@ -15,8 +15,8 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 from formencode import validators as fev
 from tg import (
     expose,
diff --git a/ForgeImporters/forgeimporters/github/tasks.py b/ForgeImporters/forgeimporters/github/tasks.py
index d74a9cd..db12c4d 100644
--- a/ForgeImporters/forgeimporters/github/tasks.py
+++ b/ForgeImporters/forgeimporters/github/tasks.py
@@ -15,8 +15,8 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 
 from ming.orm import ThreadLocalORMSession
 
diff --git a/ForgeImporters/forgeimporters/github/tests/test_oauth.py b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
index 0bf8f4e..7656289 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_oauth.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
@@ -18,7 +18,7 @@
 from unittest import TestCase
 
 from mock import Mock, patch, MagicMock
-from pylons import tmpl_context as c, config
+from tg import tmpl_context as c, config
 from webob.exc import HTTPFound
 
 from allura.tests import TestController
diff --git a/ForgeImporters/forgeimporters/github/tracker.py b/ForgeImporters/forgeimporters/github/tracker.py
index 1f8d186..0c54f3f 100644
--- a/ForgeImporters/forgeimporters/github/tracker.py
+++ b/ForgeImporters/forgeimporters/github/tracker.py
@@ -41,8 +41,8 @@ from allura.lib import helpers as h
 from allura.lib.plugin import ImportIdConverter
 from allura.lib.decorators import require_post
 from ming.orm import session, ThreadLocalORMSession
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 
 from forgetracker import model as TM
 from forgeimporters.base import (
diff --git a/ForgeImporters/forgeimporters/github/wiki.py b/ForgeImporters/forgeimporters/github/wiki.py
index 5b787d9..91c9594 100644
--- a/ForgeImporters/forgeimporters/github/wiki.py
+++ b/ForgeImporters/forgeimporters/github/wiki.py
@@ -25,8 +25,8 @@ from paste.deploy.converters import aslist
 
 from BeautifulSoup import BeautifulSoup
 import git
-from pylons import app_globals as g
-from pylons import tmpl_context as c
+from tg import app_globals as g
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 from formencode import validators as fev
 from tg import (
diff --git a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
index e3c8f7e..1e98584 100644
--- a/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tests/test_tickets.py
@@ -21,7 +21,7 @@ import os
 from unittest import TestCase
 from mock import Mock, patch
 from ming.orm import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from IPython.testing.decorators import module_not_available, skipif
 
 from allura.tests import TestController
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index 466b4f7..50c867a 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -21,8 +21,8 @@ import re
 from formencode import validators as fev
 
 from ming.orm import session
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 from tg import (
     expose,
     flash,
diff --git a/ForgeLink/forgelink/link_main.py b/ForgeLink/forgelink/link_main.py
index cece76e..cc00d00 100644
--- a/ForgeLink/forgelink/link_main.py
+++ b/ForgeLink/forgelink/link_main.py
@@ -21,8 +21,8 @@ import json
 
 # Non-stdlib imports
 from tg import expose, jsonify, redirect
-from pylons import tmpl_context as c
-from pylons import request
+from tg import tmpl_context as c
+from tg import request
 from formencode import validators as fev
 
 # Pyforge-specific imports
diff --git a/ForgeLink/forgelink/tests/test_app.py b/ForgeLink/forgelink/tests/test_app.py
index f4bbe84..2976341 100644
--- a/ForgeLink/forgelink/tests/test_app.py
+++ b/ForgeLink/forgelink/tests/test_app.py
@@ -19,7 +19,7 @@ import tempfile
 import json
 
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.tests import decorators as td
 from allura import model as M
diff --git a/ForgeSVN/forgesvn/controllers.py b/ForgeSVN/forgesvn/controllers.py
index 35af8e7..8a13c7a 100644
--- a/ForgeSVN/forgesvn/controllers.py
+++ b/ForgeSVN/forgesvn/controllers.py
@@ -17,7 +17,7 @@
 
 from tg import expose, redirect
 from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.controllers import repository
 from allura.controllers.feed import FeedController
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index afcdd12..1ded9e3 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -34,7 +34,7 @@ import tg
 import pysvn
 from paste.deploy.converters import asbool, asint
 from pymongo.errors import DuplicateKeyError
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from ming.base import Object
 from ming.orm import Mapper, FieldProperty
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index 60bb345..8c97630 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -17,7 +17,7 @@
 
 #-*- python -*-
 import logging
-from pylons import tmpl_context as c, request
+from tg import tmpl_context as c, request
 
 # Non-stdlib imports
 from ming.utils import LazyProperty
diff --git a/ForgeSVN/forgesvn/tests/functional/test_controllers.py b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
index 2154c6e..85f8e51 100644
--- a/ForgeSVN/forgesvn/tests/functional/test_controllers.py
+++ b/ForgeSVN/forgesvn/tests/functional/test_controllers.py
@@ -21,7 +21,7 @@ import os
 
 import tg
 import pkg_resources
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 from mock import patch
 from nose.tools import assert_equal
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py b/ForgeSVN/forgesvn/tests/model/test_repository.py
index f4c49e8..d4323f0 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -25,7 +25,7 @@ from datetime import datetime
 from zipfile import ZipFile
 
 from collections import defaultdict
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 import mock
 from nose.tools import assert_equal, assert_in
 from datadiff.tools import assert_equals
diff --git a/ForgeSVN/forgesvn/tests/model/test_svnimplementation.py b/ForgeSVN/forgesvn/tests/model/test_svnimplementation.py
index 70cf129..99fed05 100644
--- a/ForgeSVN/forgesvn/tests/model/test_svnimplementation.py
+++ b/ForgeSVN/forgesvn/tests/model/test_svnimplementation.py
@@ -17,7 +17,7 @@
 
 from mock import Mock, patch
 from nose.tools import assert_equal
-from pylons import app_globals as g
+from tg import app_globals as g
 
 from alluratest.controller import setup_unit_test
 from allura.model.repository import Commit
diff --git a/ForgeSVN/forgesvn/tests/test_svn_app.py b/ForgeSVN/forgesvn/tests/test_svn_app.py
index 6ea576a..a962424 100644
--- a/ForgeSVN/forgesvn/tests/test_svn_app.py
+++ b/ForgeSVN/forgesvn/tests/test_svn_app.py
@@ -18,7 +18,7 @@
 import unittest
 from nose.tools import assert_equals
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 
 from alluratest.controller import setup_basic_test, setup_global_objects
diff --git a/ForgeSVN/forgesvn/tests/test_tasks.py b/ForgeSVN/forgesvn/tests/test_tasks.py
index c928efb..2e0e99b 100644
--- a/ForgeSVN/forgesvn/tests/test_tasks.py
+++ b/ForgeSVN/forgesvn/tests/test_tasks.py
@@ -23,7 +23,7 @@ import os
 
 import tg
 import mock
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from paste.deploy.converters import asbool
 from nose.tools import assert_equal
 
diff --git a/ForgeShortUrl/forgeshorturl/main.py b/ForgeShortUrl/forgeshorturl/main.py
index 2be5b7f..66a5075 100644
--- a/ForgeShortUrl/forgeshorturl/main.py
+++ b/ForgeShortUrl/forgeshorturl/main.py
@@ -28,7 +28,7 @@ from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.search import SearchResults, SearchHelp
 
 from webob import exc
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from datetime import datetime
 from formencode import validators
 from formencode.compound import All
diff --git a/ForgeShortUrl/forgeshorturl/model/shorturl.py b/ForgeShortUrl/forgeshorturl/model/shorturl.py
index 6682632..e8b0c29 100644
--- a/ForgeShortUrl/forgeshorturl/model/shorturl.py
+++ b/ForgeShortUrl/forgeshorturl/model/shorturl.py
@@ -17,7 +17,7 @@
 
 import pymongo
 from tg import config
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import FieldProperty, ForeignIdProperty, session
 from datetime import datetime
 from allura.model.auth import User
diff --git a/ForgeShortUrl/forgeshorturl/tests/functional/test.py b/ForgeShortUrl/forgeshorturl/tests/functional/test.py
index f2c2e1c..d4aa712 100644
--- a/ForgeShortUrl/forgeshorturl/tests/functional/test.py
+++ b/ForgeShortUrl/forgeshorturl/tests/functional/test.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import config
 from nose.tools import assert_equal
 import mock
diff --git a/ForgeTracker/forgetracker/command/fix_discussion.py b/ForgeTracker/forgetracker/command/fix_discussion.py
index 95bddb4..a0d090d 100644
--- a/ForgeTracker/forgetracker/command/fix_discussion.py
+++ b/ForgeTracker/forgetracker/command/fix_discussion.py
@@ -18,7 +18,7 @@
 from bson import ObjectId
 from bson.errors import InvalidId
 from ming.orm import ThreadLocalORMSession
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.command import base
 from allura import model as M
diff --git a/ForgeTracker/forgetracker/import_support.py b/ForgeTracker/forgetracker/import_support.py
index affe94b..bc2aa73 100644
--- a/ForgeTracker/forgetracker/import_support.py
+++ b/ForgeTracker/forgetracker/import_support.py
@@ -22,7 +22,7 @@ from datetime import datetime
 from cStringIO import StringIO
 
 # Non-stdlib imports
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 
 # Pyforge-specific imports
diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 3e37ea6..9d5611c 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -25,7 +25,7 @@ import os
 
 import pymongo
 from pymongo.errors import OperationFailure
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 from pprint import pformat
 from paste.deploy.converters import aslist, asbool
 import jinja2
diff --git a/ForgeTracker/forgetracker/plugins.py b/ForgeTracker/forgetracker/plugins.py
index c610de8..676deb2 100644
--- a/ForgeTracker/forgetracker/plugins.py
+++ b/ForgeTracker/forgetracker/plugins.py
@@ -18,6 +18,6 @@
 import logging
 
 from tg import config
-from pylons import app_globals as g
+from tg import app_globals as g
 
 log = logging.getLogger(__name__)
diff --git a/ForgeTracker/forgetracker/search.py b/ForgeTracker/forgetracker/search.py
index 0225997..86e46b4 100644
--- a/ForgeTracker/forgetracker/search.py
+++ b/ForgeTracker/forgetracker/search.py
@@ -14,7 +14,7 @@
 #       KIND, either express or implied.  See the License for the
 #       specific language governing permissions and limitations
 #       under the License.
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.lib.search import search
 
diff --git a/ForgeTracker/forgetracker/tasks.py b/ForgeTracker/forgetracker/tasks.py
index 0fdebc5..5ad4214 100644
--- a/ForgeTracker/forgetracker/tasks.py
+++ b/ForgeTracker/forgetracker/tasks.py
@@ -18,7 +18,7 @@
 import logging
 from datetime import datetime
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from allura.lib.decorators import task
 from allura.lib import helpers as h
diff --git a/ForgeTracker/forgetracker/tests/functional/test_rest.py b/ForgeTracker/forgetracker/tests/functional/test_rest.py
index 46e5b9a..b44a881 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_rest.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_rest.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from datadiff.tools import assert_equal
 from nose.tools import assert_not_equal
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index 8fd0144..5cdb2b1 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -40,8 +40,8 @@ from nose.tools import (
     assert_not_equal,
 )
 from formencode.variabledecode import variable_encode
-from pylons import tmpl_context as c
-from pylons import app_globals as g
+from tg import tmpl_context as c
+from tg import app_globals as g
 from tg import config
 
 from alluratest.controller import TestController, setup_basic_test
diff --git a/ForgeTracker/forgetracker/tests/test_app.py b/ForgeTracker/forgetracker/tests/test_app.py
index 707a094..cfc0596 100644
--- a/ForgeTracker/forgetracker/tests/test_app.py
+++ b/ForgeTracker/forgetracker/tests/test_app.py
@@ -21,7 +21,7 @@ import operator
 import os
 
 from nose.tools import assert_equal, assert_true
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from cgi import FieldStorage
 from cStringIO import StringIO
 from ming.orm import ThreadLocalORMSession
diff --git a/ForgeTracker/forgetracker/tests/test_tracker_roles.py b/ForgeTracker/forgetracker/tests/test_tracker_roles.py
index 92bed3f..242646c 100644
--- a/ForgeTracker/forgetracker/tests/test_tracker_roles.py
+++ b/ForgeTracker/forgetracker/tests/test_tracker_roles.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from alluratest.controller import setup_basic_test, setup_global_objects
 from allura import model as M
diff --git a/ForgeTracker/forgetracker/tests/unit/__init__.py b/ForgeTracker/forgetracker/tests/unit/__init__.py
index ee9af84..1ef9b92 100644
--- a/ForgeTracker/forgetracker/tests/unit/__init__.py
+++ b/ForgeTracker/forgetracker/tests/unit/__init__.py
@@ -15,13 +15,12 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
-from pylons import request
+from tg import tmpl_context as c
+import tg
 from ming.orm.ormsession import ThreadLocalORMSession
 from webob import Request
 
 from allura.websetup import bootstrap
-from allura.websetup.schema import REGISTRY
 from allura.lib import helpers as h
 from allura.lib import plugin
 from allura import model as M
@@ -48,7 +47,7 @@ class TrackerTestWithModel(object):
         c.project.install_app('Tickets', 'bugs')
         ThreadLocalORMSession.flush_all()
         h.set_context('test', 'bugs', neighborhood='Projects')
-        REGISTRY.register(request, Request.blank('/'))  # borrowed from setup_unit_test but we need just this
+        tg.request_local.context.request = Request.blank('/')
 
     def tearDown(self):
         ThreadLocalORMSession.close_all()
diff --git a/ForgeTracker/forgetracker/tests/unit/test_globals_model.py b/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
index 700a222..47b36ba 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_globals_model.py
@@ -19,7 +19,7 @@ from datetime import datetime, timedelta
 
 import mock
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 
 import forgetracker
diff --git a/ForgeTracker/forgetracker/tests/unit/test_milestone_controller.py b/ForgeTracker/forgetracker/tests/unit/test_milestone_controller.py
index b77cf74..e7c36c5 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_milestone_controller.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_milestone_controller.py
@@ -22,7 +22,7 @@ from mock import Mock
 from nose.tools import assert_equal
 
 from allura.lib import helpers as h
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from forgetracker.tracker_main import MilestoneController
 
 
diff --git a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
index 7a88f72..c7bef18 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
@@ -19,7 +19,7 @@ import unittest
 
 from mock import Mock, patch
 from ming.orm.ormsession import session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from nose.tools import assert_equal
 
 from allura.lib import helpers as h
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_custom_fields_form.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_custom_fields_form.py
index 3c8ea70..60576d1 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_custom_fields_form.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_custom_fields_form.py
@@ -18,7 +18,7 @@
 from ming.orm.ormsession import ThreadLocalORMSession
 from ming.base import Object
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from forgetracker.tests.unit import TrackerTestWithModel
 from forgetracker.widgets import ticket_form
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_form.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_form.py
index a0743eb..a11a088 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_form.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_form.py
@@ -17,7 +17,7 @@
 
 from ming.orm.ormsession import ThreadLocalORMSession
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from forgetracker.tests.unit import TrackerTestWithModel
 from forgetracker.widgets import ticket_form
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
index 3b6f318..99ba7de 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from datetime import datetime
 import urllib2
 
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 135df0e..1be5070 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -29,8 +29,8 @@ import pkg_resources
 from tg import expose, validate, redirect, flash, url, jsonify
 from tg.decorators import with_trailing_slash, without_trailing_slash
 from paste.deploy.converters import aslist
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request, response
+from tg import tmpl_context as c, app_globals as g
+from tg import request, response
 from formencode import validators
 from bson import ObjectId
 from bson.son import SON
diff --git a/ForgeTracker/forgetracker/widgets/ticket_form.py b/ForgeTracker/forgetracker/widgets/ticket_form.py
index 5481eb2..64c0863 100644
--- a/ForgeTracker/forgetracker/widgets/ticket_form.py
+++ b/ForgeTracker/forgetracker/widgets/ticket_form.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from formencode import validators as fev
 from webhelpers.html.builder import literal
 
diff --git a/ForgeUserStats/forgeuserstats/controllers/userstats.py b/ForgeUserStats/forgeuserstats/controllers/userstats.py
index ffd2e58..8ab2db2 100644
--- a/ForgeUserStats/forgeuserstats/controllers/userstats.py
+++ b/ForgeUserStats/forgeuserstats/controllers/userstats.py
@@ -19,7 +19,7 @@ import re
 
 from tg import expose, validate, redirect
 from tg.decorators import with_trailing_slash
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from webob import exc
 
 from allura.controllers import BaseController
diff --git a/ForgeUserStats/forgeuserstats/main.py b/ForgeUserStats/forgeuserstats/main.py
index daa19ef..580b3a6 100644
--- a/ForgeUserStats/forgeuserstats/main.py
+++ b/ForgeUserStats/forgeuserstats/main.py
@@ -17,7 +17,7 @@
 
 #-*- python -*-
 import logging
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from datetime import datetime
 
 from allura.app import Application, SitemapEntry
diff --git a/ForgeUserStats/forgeuserstats/model/stats.py b/ForgeUserStats/forgeuserstats/model/stats.py
index 2da4618..340f857 100644
--- a/ForgeUserStats/forgeuserstats/model/stats.py
+++ b/ForgeUserStats/forgeuserstats/model/stats.py
@@ -19,7 +19,7 @@ from ming.orm import FieldProperty
 from ming import schema as S
 from datetime import datetime, timedelta
 from ming.orm import Mapper
-from pylons import request
+from tg import request
 
 from allura.lib import plugin
 from allura.model.session import main_orm_session
diff --git a/ForgeUserStats/forgeuserstats/tests/test_model.py b/ForgeUserStats/forgeuserstats/tests/test_model.py
index 3804063..b9eff67 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_model.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_model.py
@@ -19,7 +19,7 @@ import pkg_resources
 import unittest
 from datetime import datetime, timedelta
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from tg import config
 import mock
 
diff --git a/ForgeUserStats/forgeuserstats/tests/test_stats.py b/ForgeUserStats/forgeuserstats/tests/test_stats.py
index fda1bc7..aa08385 100644
--- a/ForgeUserStats/forgeuserstats/tests/test_stats.py
+++ b/ForgeUserStats/forgeuserstats/tests/test_stats.py
@@ -18,7 +18,7 @@
 import pkg_resources
 import unittest
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from alluratest.controller import TestController, setup_basic_test, setup_global_objects
 from allura.tests import decorators as td
diff --git a/ForgeWiki/forgewiki/model/wiki.py b/ForgeWiki/forgewiki/model/wiki.py
index e55d464..edd1685 100644
--- a/ForgeWiki/forgewiki/model/wiki.py
+++ b/ForgeWiki/forgewiki/model/wiki.py
@@ -20,8 +20,8 @@ import difflib
 import os
 
 # g is a namespace for globally accessable app helpers
-from pylons import app_globals as g
-from pylons import tmpl_context as context
+from tg import app_globals as g
+from tg import tmpl_context as context
 
 from ming import schema
 from ming.orm import FieldProperty, ForeignIdProperty, Mapper, session
diff --git a/ForgeWiki/forgewiki/tests/test_app.py b/ForgeWiki/forgewiki/tests/test_app.py
index 086d258..7934540 100644
--- a/ForgeWiki/forgewiki/tests/test_app.py
+++ b/ForgeWiki/forgewiki/tests/test_app.py
@@ -23,7 +23,7 @@ import os
 
 from cStringIO import StringIO
 from nose.tools import assert_equal
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import ThreadLocalORMSession
 
 from allura import model as M
diff --git a/ForgeWiki/forgewiki/tests/test_models.py b/ForgeWiki/forgewiki/tests/test_models.py
index 2ab2f00..3c6c7ef 100644
--- a/ForgeWiki/forgewiki/tests/test_models.py
+++ b/ForgeWiki/forgewiki/tests/test_models.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import session
 
 from allura.tests import TestController
diff --git a/ForgeWiki/forgewiki/tests/test_wiki_roles.py b/ForgeWiki/forgewiki/tests/test_wiki_roles.py
index 64b5f03..9750f0d 100644
--- a/ForgeWiki/forgewiki/tests/test_wiki_roles.py
+++ b/ForgeWiki/forgewiki/tests/test_wiki_roles.py
@@ -15,7 +15,7 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from nose.tools import assert_equal
 
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 5e7b4f5..ac60545 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -25,8 +25,8 @@ from urllib import unquote
 # Non-stdlib imports
 from tg import expose, validate, redirect, flash, jsonify
 from tg.decorators import with_trailing_slash, without_trailing_slash
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
+from tg import tmpl_context as c, app_globals as g
+from tg import request
 from formencode import validators
 from webob import exc
 from ming.orm import session
diff --git a/requirements.txt b/requirements.txt
index 1a6b730..6c6de7d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -49,10 +49,10 @@ textile==2.1.5
 # dep of colander
 translationstring==0.4
 TimerMiddleware==0.4.4
-TurboGears2==2.2.2
+TurboGears2==2.3.0
 # dep of html5lib
 webencodings==0.5.1
-WebOb==1.1.1
+WebOb==1.3.1
 
 # dependencies for cryptography
 cryptography==2.6.1
@@ -66,6 +66,7 @@ asn1crypto==0.24.0
 
 # tg2 deps (not used directly)
 Babel==1.3
+backlash==0.1.4
 crank==0.8.1
 Mako==0.9.1
 MarkupSafe==1.0
diff --git a/scripts/migrations/000-fix-tracker-fields.py b/scripts/migrations/000-fix-tracker-fields.py
index 5d2b6b1..072aeb9 100644
--- a/scripts/migrations/000-fix-tracker-fields.py
+++ b/scripts/migrations/000-fix-tracker-fields.py
@@ -18,7 +18,7 @@
 import sys
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import session
 
diff --git a/scripts/migrations/001-restore-labels.py b/scripts/migrations/001-restore-labels.py
index ef68c09..2e33da7 100644
--- a/scripts/migrations/001-restore-labels.py
+++ b/scripts/migrations/001-restore-labels.py
@@ -19,7 +19,7 @@ import sys
 import json
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import session, MappedClass
 
diff --git a/scripts/migrations/002-fix-tracker-thread-subjects.py b/scripts/migrations/002-fix-tracker-thread-subjects.py
index 81861a0..df42446 100644
--- a/scripts/migrations/002-fix-tracker-thread-subjects.py
+++ b/scripts/migrations/002-fix-tracker-thread-subjects.py
@@ -18,7 +18,7 @@
 import sys
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import session
 
diff --git a/scripts/migrations/007-update-acls.py b/scripts/migrations/007-update-acls.py
index 0f97ee1..1cc8f3b 100644
--- a/scripts/migrations/007-update-acls.py
+++ b/scripts/migrations/007-update-acls.py
@@ -20,7 +20,7 @@ from optparse import OptionParser
 from pprint import pformat
 
 import bson
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.base import Object
 
 from allura import model as M
diff --git a/scripts/migrations/010-fix-home-permissions.py b/scripts/migrations/010-fix-home-permissions.py
index 4506a17..1b669d5 100644
--- a/scripts/migrations/010-fix-home-permissions.py
+++ b/scripts/migrations/010-fix-home-permissions.py
@@ -19,7 +19,7 @@ import sys
 import logging
 from collections import OrderedDict
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import session
 from bson import ObjectId
 
diff --git a/scripts/migrations/012-uninstall-home.py b/scripts/migrations/012-uninstall-home.py
index c59fdb2..9c5bd79 100644
--- a/scripts/migrations/012-uninstall-home.py
+++ b/scripts/migrations/012-uninstall-home.py
@@ -18,7 +18,7 @@
 import sys
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import session
 from bson import ObjectId
 from mock import Mock, patch
diff --git a/scripts/migrations/013-update-ordinals.py b/scripts/migrations/013-update-ordinals.py
index f26f112..0568fa0 100644
--- a/scripts/migrations/013-update-ordinals.py
+++ b/scripts/migrations/013-update-ordinals.py
@@ -18,7 +18,7 @@
 import sys
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm import session
 from ming.orm.ormsession import ThreadLocalORMSession
 
diff --git a/scripts/migrations/015-add-neighborhood_id-to-blog-posts.py b/scripts/migrations/015-add-neighborhood_id-to-blog-posts.py
index 8c4abd9..1fa8542 100644
--- a/scripts/migrations/015-add-neighborhood_id-to-blog-posts.py
+++ b/scripts/migrations/015-add-neighborhood_id-to-blog-posts.py
@@ -17,7 +17,7 @@
 
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from ming.orm.ormsession import ThreadLocalORMSession
 
 from forgeblog import model as BM
diff --git a/scripts/migrations/020-remove-wiki-title-slashes.py b/scripts/migrations/020-remove-wiki-title-slashes.py
index 34db4ce..0df73f7 100644
--- a/scripts/migrations/020-remove-wiki-title-slashes.py
+++ b/scripts/migrations/020-remove-wiki-title-slashes.py
@@ -17,7 +17,7 @@
 
 import logging
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import ThreadLocalORMSession
 
diff --git a/scripts/migrations/024-migrate-custom-profile-text.py b/scripts/migrations/024-migrate-custom-profile-text.py
index 18a82da..060b70e 100644
--- a/scripts/migrations/024-migrate-custom-profile-text.py
+++ b/scripts/migrations/024-migrate-custom-profile-text.py
@@ -18,7 +18,7 @@
 import logging
 import re
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import ThreadLocalORMSession
 
diff --git a/scripts/migrations/033-change-comment-anon-permissions.py b/scripts/migrations/033-change-comment-anon-permissions.py
index b5a710c..f0b7da8 100644
--- a/scripts/migrations/033-change-comment-anon-permissions.py
+++ b/scripts/migrations/033-change-comment-anon-permissions.py
@@ -18,7 +18,7 @@
 import sys
 import logging
 from ming.orm import ThreadLocalORMSession, session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from allura import model as M
 from forgediscussion.model import ForumPost
 from allura.lib import utils, security
diff --git a/scripts/migrations/034-update_subscriptions_ticket_and_mr_titles.py b/scripts/migrations/034-update_subscriptions_ticket_and_mr_titles.py
index 4ca1cf8..94904c8 100644
--- a/scripts/migrations/034-update_subscriptions_ticket_and_mr_titles.py
+++ b/scripts/migrations/034-update_subscriptions_ticket_and_mr_titles.py
@@ -18,7 +18,7 @@
 import logging
 import re
 import sys
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from bson import ObjectId
 
 from ming.odm import session
diff --git a/scripts/perf/call_count.py b/scripts/perf/call_count.py
index 671e6f2..e94c238 100755
--- a/scripts/perf/call_count.py
+++ b/scripts/perf/call_count.py
@@ -24,7 +24,7 @@ import random
 import string
 import csv
 
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from testfixtures import LogCapture
 from mock import patch
 from ming.odm import ThreadLocalODMSession
diff --git a/scripts/perf/load-up-forum.py b/scripts/perf/load-up-forum.py
index 2184411..ee8f93d 100644
--- a/scripts/perf/load-up-forum.py
+++ b/scripts/perf/load-up-forum.py
@@ -19,7 +19,7 @@
 import logging
 import uuid
 from ming.orm import ThreadLocalORMSession, session
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 from allura import model as M
 from forgediscussion.model import ForumPost, Forum
 from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, ArgumentTypeError
diff --git a/scripts/perf/md_perf.py b/scripts/perf/md_perf.py
index e8d0f70..d4511da 100644
--- a/scripts/perf/md_perf.py
+++ b/scripts/perf/md_perf.py
@@ -56,7 +56,7 @@ try:
 except ImportError:
     RE2_INSTALLED = False
 
-from pylons import app_globals as g
+from tg import app_globals as g
 
 MAX_OUTPUT = 99999
 DUMMYTEXT = None
diff --git a/scripts/project-import.py b/scripts/project-import.py
index 462c4d6..9833bc2 100644
--- a/scripts/project-import.py
+++ b/scripts/project-import.py
@@ -26,7 +26,7 @@ import sys
 
 import colander as col
 from ming.orm import session, ThreadLocalORMSession
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from allura import model as M
 from allura.lib import helpers as h
diff --git a/scripts/publicize-neighborhood.py b/scripts/publicize-neighborhood.py
index 9cc6494..b2d208c 100644
--- a/scripts/publicize-neighborhood.py
+++ b/scripts/publicize-neighborhood.py
@@ -19,7 +19,7 @@ import logging
 import sys
 
 from ming.orm import ThreadLocalORMSession
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from allura import model as M
 from allura.lib import helpers as h
diff --git a/scripts/rethumb.py b/scripts/rethumb.py
index fa27f32..4dbfc04 100644
--- a/scripts/rethumb.py
+++ b/scripts/rethumb.py
@@ -18,7 +18,7 @@
 import sys
 
 import PIL
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 
 from ming.orm import ThreadLocalORMSession, state, Mapper
 
diff --git a/scripts/scrub-allura-data.py b/scripts/scrub-allura-data.py
index 211cfdc..226ea13 100644
--- a/scripts/scrub-allura-data.py
+++ b/scripts/scrub-allura-data.py
@@ -20,7 +20,7 @@ import sys
 
 from ming.orm import ThreadLocalORMSession
 import mock
-from pylons import tmpl_context as c, app_globals as g
+from tg import tmpl_context as c, app_globals as g
 
 from allura import model as M
 from forgediscussion import model as DM
diff --git a/scripts/teamforge-import.py b/scripts/teamforge-import.py
index b668128..aed92cd 100644
--- a/scripts/teamforge-import.py
+++ b/scripts/teamforge-import.py
@@ -18,7 +18,7 @@
 import logging
 from getpass import getpass
 from optparse import OptionParser
-from pylons import tmpl_context as c
+from tg import tmpl_context as c
 import re
 import os
 from time import mktime


[allura] 03/08: [#8273] TG 2.3.0: root override; appconfig

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit a7cbe6736a003a54c52675ae92e99cab1d9cebaf
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu Mar 21 12:13:17 2019 -0400

    [#8273] TG 2.3.0: root override; appconfig
---
 Allura/allura/config/app_cfg.py    | 15 +++++++++------
 Allura/allura/config/middleware.py |  8 ++------
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py
index c21af19..cc26995 100644
--- a/Allura/allura/config/app_cfg.py
+++ b/Allura/allura/config/app_cfg.py
@@ -52,24 +52,26 @@ log = logging.getLogger(__name__)
 
 class ForgeConfig(AppConfig):
 
-    def __init__(self, root_controller='root'):
-        AppConfig.__init__(self)
-        self.root_controller = root_controller
+    def __init__(self, root_controller=None):
+        AppConfig.__init__(self, minimal=True, root_controller=root_controller)
         self.package = allura
         self.renderers = ['json', 'genshi', 'mako', 'jinja']
-        self.default_renderer = 'genshi'
+        self.default_renderer = 'jinja'
         self.use_sqlalchemy = False
-        self.use_toscawidgets = True
+        self.use_toscawidgets = False
         self.use_transaction_manager = False
+        self.enable_routes = True
         self.handle_status_codes = [403, 404]
         self.disable_request_extensions = True
 
     def after_init_config(self):
         config['tg.strict_tmpl_context'] = True
 
+    def setup_routes(self):
         map = Mapper()
         # Setup a default route for the root of object dispatch
-        map.connect('*url', controller=self.root_controller,
+        # tg.root_controller is set by AppConfig.__init__
+        map.connect('*url', controller=self.get('tg.root_controller', 'root'),
                     action='routes_placeholder')
         config['routes.map'] = map
 
@@ -132,4 +134,5 @@ class JinjaEngine(ew.TemplateEngine):
             text = template.render(**context)
             return literal(text)
 
+
 base_config = ForgeConfig()
diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py
index decce40..21e78b4 100644
--- a/Allura/allura/config/middleware.py
+++ b/Allura/allura/config/middleware.py
@@ -62,13 +62,9 @@ from allura.lib import helpers as h
 
 __all__ = ['make_app']
 
-# Use base_config to setup the necessary PasteDeploy application factory.
-# make_base_app will wrap the TG2 app with all the middleware it needs.
-make_base_app = base_config.setup_tg_wsgi_app(load_environment)
-
 
 def make_app(global_conf, full_stack=True, **app_conf):
-    root = app_conf.get('override_root', 'root')
+    root = app_conf.get('override_root', None)
     return _make_core_app(root, global_conf, full_stack, **app_conf)
 
 
@@ -173,7 +169,7 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf):
     app = RegistryManager(app, streaming=True)
 
     # "task" wsgi would get a 2nd request to /error/document if we used this middleware
-    if config.get('override_root') != 'task':
+    if config.get('override_root') not in ('task', 'basetest_project_root'):
         # Converts exceptions to HTTP errors, shows traceback in debug mode
         # don't use TG footer with extra CSS & images that take time to load
         tg.error.footer_html = '<!-- %s %s -->'


[allura] 04/08: [#8273] TG 2.3.0: small test fixes

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit cecff40e1eb8402a8d1ab211d86f2115b685de13
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu Mar 21 12:14:39 2019 -0400

    [#8273] TG 2.3.0: small test fixes
---
 Allura/allura/controllers/discuss.py                  |  2 +-
 Allura/allura/lib/patches.py                          |  8 ++++----
 Allura/allura/templates/widgets/post_widget.html      |  2 +-
 Allura/allura/tests/functional/test_admin.py          |  2 +-
 Allura/allura/tests/functional/test_auth.py           | 19 +++++++++++++------
 .../forgeimporters/github/tests/test_oauth.py         |  4 +++-
 ForgeImporters/forgeimporters/tests/test_base.py      |  6 +++---
 ForgeWiki/forgewiki/tests/functional/test_root.py     |  1 -
 8 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 9aec747..3984c73 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -414,7 +414,7 @@ class PostController(BaseController):
                              kw=kw)
 
     @h.vardec
-    @expose()
+    @expose('json')
     @require_post()
     @validate(pass_validator, error_handler=error_handler)
     def moderate(self, **kw):
diff --git a/Allura/allura/lib/patches.py b/Allura/allura/lib/patches.py
index 8e0dcf8..9e1734a 100644
--- a/Allura/allura/lib/patches.py
+++ b/Allura/allura/lib/patches.py
@@ -22,7 +22,7 @@ import tg.decorators
 from decorator import decorator
 from tg import request
 import mock
-import simplejson
+import json
 
 from allura.lib import helpers as h
 
@@ -97,7 +97,7 @@ def apply():
     # and may attempt to render JSON data as HTML if the URL ends in .html
     original_tg_jsonify_GenericJSON_encode = tg.jsonify.GenericJSON.encode
     escape_pattern_with_lt = re.compile(
-        simplejson.encoder.ESCAPE.pattern.rstrip(']') + '<' + ']')
+        json.encoder.ESCAPE.pattern.rstrip(']') + '<' + ']')
 
     @h.monkeypatch(tg.jsonify.GenericJSON)
     def encode(self, o):
@@ -105,8 +105,8 @@ def apply():
         # encode_basestring_ascii() and encode_basestring_ascii may likely be c-compiled
         # and thus not monkeypatchable
         with h.push_config(self, ensure_ascii=False), \
-                h.push_config(simplejson.encoder, ESCAPE=escape_pattern_with_lt), \
-                mock.patch.dict(simplejson.encoder.ESCAPE_DCT, {'<': r'\u003C'}):
+                h.push_config(json.encoder, ESCAPE=escape_pattern_with_lt), \
+                mock.patch.dict(json.encoder.ESCAPE_DCT, {'<': r'\u003C'}):
             return original_tg_jsonify_GenericJSON_encode(self, o)
 
 
diff --git a/Allura/allura/templates/widgets/post_widget.html b/Allura/allura/templates/widgets/post_widget.html
index 4349d4d..bd03f92 100644
--- a/Allura/allura/templates/widgets/post_widget.html
+++ b/Allura/allura/templates/widgets/post_widget.html
@@ -23,7 +23,7 @@
 {% else %}
   {% set params = '?page={}&limit={}'.format(page, limit) %}
 {% endif %}
-{% set shortlink_url = h.absurl(url.current() + params + '#' + value.slug) %}
+{% set shortlink_url = h.absurl(request.path + params + '#' + value.slug) %}
 
 <div>
   <div id="{{value.slug}}" class="discussion-post{%if value.is_meta %} meta_post{% endif %}">
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 3b8d90a..a18b0c2 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -972,7 +972,7 @@ class TestProjectAdmin(TestController):
         with mock.patch.dict(g.entry_points, eps):
             main_page = self.app.get('/admin/')
             foo_page = main_page.click(description='Foo Settings')
-            url = foo_page.environ['PATH_INFO']
+            url = foo_page.request.path
             assert url.endswith('/admin/ext/foo'), url
             assert_equals('here the foo settings go', foo_page.body)
 
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 02c7823..fb4069b 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -54,7 +54,7 @@ from allura.lib import helpers as h
 
 
 def unentity(s):
-    return s.replace('&quot;', '"')
+    return s.replace('&quot;', '"').replace('&#34;', '"')
 
 
 class TestAuth(TestController):
@@ -1523,6 +1523,7 @@ To reset your password on %s, please visit the following URL:
         ap.authenticate_request()._id = user._id
         ap.by_username().username = user.username
         self.app.get('/auth/forgotten_password', status=404)
+        self.app.get('/').follow()  # establish session
         self.app.post('/auth/set_new_password',
                       {'pw': 'foo', 'pw2': 'foo', '_session_id': self.app.cookies['_session_id']},
                       status=404)
@@ -1611,11 +1612,17 @@ class TestOAuth(TestController):
         ThreadLocalORMSession.flush_all()
         req = Request.from_request.return_value = {'oauth_consumer_key': 'api_key'}
         r = self.app.post('/rest/oauth/request_token', params={'key': 'value'})
-        Request.from_request.assert_called_once_with(
-            'POST', 'http://localhost/rest/oauth/request_token',
-            headers={'Host': 'localhost', 'Content-Type': 'application/x-www-form-urlencoded; charset="utf-8"'},
-            parameters={'key': 'value'},
-            query_string='')
+
+        # dict-ify webob.EnvironHeaders
+        call = Request.from_request.call_args_list[0]
+        call[1]['headers'] = dict(call[1]['headers'])
+        # then check equality
+        assert_equal(Request.from_request.call_args_list, [
+            mock.call('POST', 'http://localhost/rest/oauth/request_token',
+                      headers={'Host': 'localhost:80', 'Content-Type': 'application/x-www-form-urlencoded'},
+                      parameters={'key': 'value'},
+                      query_string='')
+        ])
         Server().verify_request.assert_called_once_with(req, consumer_token.consumer, None)
         request_token = M.OAuthRequestToken.query.get(consumer_token_id=consumer_token._id)
         assert_is_not_none(request_token)
diff --git a/ForgeImporters/forgeimporters/github/tests/test_oauth.py b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
index 7656289..a903623 100644
--- a/ForgeImporters/forgeimporters/github/tests/test_oauth.py
+++ b/ForgeImporters/forgeimporters/github/tests/test_oauth.py
@@ -63,6 +63,8 @@ class TestGitHubOAuthMixin(TestController, TestCase):
     @patch('forgeimporters.github.session', MagicMock())
     @patch('forgeimporters.github.request', MagicMock())
     def test_oauth_callback_complete(self):
-        with patch.object(self.mix, 'oauth_callback_complete') as _mock, raises(HTTPFound):
+        with patch.object(self.mix, 'oauth_callback_complete') as _mock, \
+                patch('forgeimporters.github.redirect') as tg_redir:
             self.mix.oauth_callback()
         self.assertEqual(_mock.call_count, 1)
+        self.assertEqual(tg_redir.call_count, 1)
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index f7eb706..cb96ed2 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -309,13 +309,13 @@ class TestProjectToolsImportController(TestController):
                 ep('importer3', importer=TI3),
             ]
             import_main_page = admin_page.click('Import')
-        url = import_main_page.environ['PATH_INFO']
+        url = import_main_page.request.path
         assert url.endswith('/admin/ext/import/'), url
 
         with mock.patch.object(base.ToolImporter, 'by_name') as by_name:
             by_name.return_value = TI1
             import1_page = import_main_page.click('Import', href=r'importer1$')
-        url = import1_page.environ['PATH_INFO']
+        url = import1_page.request.path
         assert url.endswith('/admin/ext/import/importer1'), url
         assert_equal(import1_page.body, 'test importer 1 controller webpage')
 
@@ -328,7 +328,7 @@ class TestProjectToolsImportController(TestController):
         admin_page = self.app.get('/admin/')
         with h.push_config(config, hidden_importers='importer1'):
             import_main_page = admin_page.click('Import')
-        url = import_main_page.environ['PATH_INFO']
+        url = import_main_page.request.path
         assert url.endswith('/admin/ext/import/'), url
         assert not import_main_page.html.find('a', href='importer1')
         assert import_main_page.html.find('a', href='importer2')
diff --git a/ForgeWiki/forgewiki/tests/functional/test_root.py b/ForgeWiki/forgewiki/tests/functional/test_root.py
index 6ee5d32..fa906f2 100644
--- a/ForgeWiki/forgewiki/tests/functional/test_root.py
+++ b/ForgeWiki/forgewiki/tests/functional/test_root.py
@@ -61,7 +61,6 @@ class TestRootController(TestController):
                          extra_environ=dict(username='*anonymous'))
         assert 'Create Page' not in r, r
 
-    @td.with_wiki
     def test_create_wiki_page(self):
         url = u"/p/test/wiki/create_wiki_page/"
         r = self.app.get(url)


[allura] 08/08: [#8273] Upgrade TG 2.3.1

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit c61442ac5718623a317e7846e0d0d36baabd98d6
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri Mar 22 18:06:56 2019 -0400

    [#8273] Upgrade TG 2.3.1
---
 Allura/allura/lib/helpers.py | 5 +++--
 requirements.txt             | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 57f200d..5b2fe56 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -594,9 +594,10 @@ def render_genshi_plaintext(template_name, **template_vars):
 
 @tg.expose(content_type='text/plain')
 def json_validation_error(controller, **kwargs):
+    exc = request.validation['exception']
     result = dict(status='Validation Error',
-                  errors=c.validation_exception.unpack_errors(),
-                  value=c.validation_exception.value,
+                  errors={fld: str(err) for fld, err in exc.error_dict.iteritems()},
+                  value=exc.value,
                   params=kwargs)
     response.status = 400
     return json.dumps(result, indent=2)
diff --git a/requirements.txt b/requirements.txt
index 6c6de7d..11aa5da 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -49,7 +49,7 @@ textile==2.1.5
 # dep of colander
 translationstring==0.4
 TimerMiddleware==0.4.4
-TurboGears2==2.3.0
+TurboGears2==2.3.1
 # dep of html5lib
 webencodings==0.5.1
 WebOb==1.3.1


[allura] 06/08: [#8273] TG 2.3.0: root controller single-run fix for oauth

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 4dbf351ba6f443c62970963e15ec701dd15ada34
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri Mar 22 17:06:33 2019 -0400

    [#8273] TG 2.3.0: root controller single-run fix for oauth
---
 Allura/allura/controllers/rest.py           | 14 +++++++-------
 Allura/allura/tests/functional/test_auth.py | 10 +++++-----
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/Allura/allura/controllers/rest.py b/Allura/allura/controllers/rest.py
index 6e9f78b..f654d0c 100644
--- a/Allura/allura/controllers/rest.py
+++ b/Allura/allura/controllers/rest.py
@@ -116,7 +116,7 @@ class RestController(object):
 
 class OAuthNegotiator(object):
 
-    @LazyProperty
+    @property
     def server(self):
         result = oauth.Server()
         result.add_signature_method(oauth.SignatureMethod_PLAINTEXT())
@@ -165,8 +165,8 @@ class OAuthNegotiator(object):
         consumer = consumer_token.consumer
         try:
             self.server.verify_request(req, consumer, access_token.as_token())
-        except:
-            log.error('Invalid signature')
+        except oauth.Error as e:
+            log.error('Invalid signature %s %s', type(e), e)
             raise exc.HTTPUnauthorized
         return access_token
 
@@ -187,8 +187,8 @@ class OAuthNegotiator(object):
         consumer = consumer_token.consumer
         try:
             self.server.verify_request(req, consumer, None)
-        except:
-            log.error('Invalid signature')
+        except oauth.Error as e:
+            log.error('Invalid signature %s %s', type(e), e)
             raise exc.HTTPUnauthorized
         req_token = M.OAuthRequestToken(
             consumer_token_id=consumer_token._id,
@@ -259,8 +259,8 @@ class OAuthNegotiator(object):
         consumer = consumer_token.consumer
         try:
             self.server.verify_request(req, consumer, rtok)
-        except:
-            log.error('Invalid signature')
+        except oauth.Error as e:
+            log.error('Invalid signature %s %s', type(e), e)
             raise exc.HTTPUnauthorized
         acc_token = M.OAuthAccessToken(
             consumer_token_id=consumer_token._id,
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index fb4069b..9ab4560 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -22,10 +22,7 @@ import json
 from urlparse import urlparse, parse_qs
 from urllib import urlencode
 
-from allura.lib.multifactor import TotpService, RecoveryCodeService
-from allura.tests.decorators import audits, out_audits
 from bson import ObjectId
-
 import re
 from ming.orm.ormsession import ThreadLocalORMSession, session
 from tg import config, expose
@@ -44,13 +41,16 @@ from nose.tools import (
 )
 from tg import tmpl_context as c, app_globals as g
 from webob import exc
+import oauth2
 
 from allura.tests import TestController
 from allura.tests import decorators as td
+from allura.tests.decorators import audits, out_audits
 from alluratest.controller import setup_trove_categories
 from allura import model as M
 from allura.lib import plugin
 from allura.lib import helpers as h
+from allura.lib.multifactor import TotpService, RecoveryCodeService
 
 
 def unentity(s):
@@ -1639,7 +1639,7 @@ class TestOAuth(TestController):
     @mock.patch('allura.controllers.rest.oauth.Server')
     @mock.patch('allura.controllers.rest.oauth.Request')
     def test_request_token_invalid(self, Request, Server):
-        Server().verify_request.side_effect = ValueError
+        Server().verify_request.side_effect = oauth2.Error('test_request_token_invalid')
         M.OAuthConsumerToken.consumer = mock.Mock()
         user = M.User.by_username('test-user')
         M.OAuthConsumerToken(
@@ -1810,7 +1810,7 @@ class TestOAuth(TestController):
             validation_pin='good',
         )
         ThreadLocalORMSession.flush_all()
-        Server().verify_request.side_effect = ValueError
+        Server().verify_request.side_effect = oauth2.Error('test_access_token_bad_sig')
         self.app.get('/rest/oauth/access_token', status=401)
 
     @mock.patch('allura.controllers.rest.oauth.Server')


[allura] 01/08: [#8273] upgrade TG 2.2.2 webob 1.1.1

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 330ab363a61ef66872a2c299c635d54b920b97c3
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri Mar 2 11:04:05 2018 -0500

    [#8273] upgrade TG 2.2.2 webob 1.1.1
    
    Some failures with "." in URL will persist until TG 2.3.2
---
 Allura/allura/app.py                               |  6 +++---
 Allura/allura/controllers/attachments.py           |  2 +-
 Allura/allura/controllers/auth.py                  |  6 +++---
 Allura/allura/controllers/base.py                  |  4 ++--
 Allura/allura/controllers/discuss.py               | 24 +++++++++++-----------
 Allura/allura/controllers/project.py               |  8 ++++----
 Allura/allura/controllers/repository.py            |  4 ++--
 Allura/allura/controllers/site_admin.py            | 12 +++++------
 Allura/allura/ext/admin/admin_main.py              |  2 +-
 Allura/allura/ext/user_profile/user_main.py        |  8 ++++----
 Allura/allura/lib/base.py                          | 16 ---------------
 Allura/allura/lib/repository.py                    |  4 ++--
 .../allura/tests/scripts/test_delete_projects.py   |  2 ++
 ForgeBlog/forgeblog/main.py                        |  4 ++--
 ForgeChat/forgechat/main.py                        |  2 +-
 .../forgediscussion/controllers/root.py            |  2 +-
 ForgeDiscussion/forgediscussion/forum_main.py      |  2 +-
 ForgeSVN/forgesvn/svn_main.py                      |  2 +-
 ForgeShortUrl/forgeshorturl/main.py                |  8 ++++----
 ForgeTracker/forgetracker/tracker_main.py          | 14 ++++++-------
 ForgeWiki/forgewiki/wiki_main.py                   |  6 +++---
 requirements.txt                                   | 12 ++++++-----
 22 files changed, 69 insertions(+), 81 deletions(-)

diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index b687be0..9481eed 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -917,7 +917,7 @@ class DefaultAdminController(BaseController, AdminControllerMixin):
         require_access(self.app, 'configure')
         self.app.config.options['mount_label'] = mount_label
         g.post_event('project_menu_updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose('jinja:allura:templates/app_admin_options.html')
     def options(self):
@@ -972,7 +972,7 @@ class DefaultAdminController(BaseController, AdminControllerMixin):
                          + self.app.config.options.mount_point
                          + '/')
             else:
-                redirect(request.referer)
+                redirect(request.referer or '/')
 
     @without_trailing_slash
     @expose()
@@ -1024,7 +1024,7 @@ class DefaultAdminController(BaseController, AdminControllerMixin):
             for ace in old_acl:
                 if (ace.permission == perm) and (ace.access == model.ACE.DENY):
                     self.app.config.acl.append(ace)
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class WebhooksLookup(BaseController, AdminControllerMixin):
diff --git a/Allura/allura/controllers/attachments.py b/Allura/allura/controllers/attachments.py
index 34ef984..11bf24d 100644
--- a/Allura/allura/controllers/attachments.py
+++ b/Allura/allura/controllers/attachments.py
@@ -115,7 +115,7 @@ class AttachmentController(BaseController):
             self.handle_post(delete, **kw)
             if is_ajax(request):
                 return
-            redirect(request.referer)
+            redirect(request.referer or '/')
         if self.artifact.deleted:
             raise exc.HTTPNotFound
         embed = False
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 514d842..3333b66 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -265,7 +265,7 @@ class AuthController(BaseController):
             flash('Verification link sent')
         else:
             flash('No such address', 'error')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     def _verify_addr(self, addr, do_auth_check=True):
         confirmed_by_other = M.EmailAddress.find(dict(email=addr.email, confirmed=True)).all() if addr else []
@@ -681,7 +681,7 @@ class PreferencesController(BaseController):
     @require_post()
     def user_message(self, allow_user_messages=False):
         c.user.set_pref('disable_user_messages', not allow_user_messages)
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose('jinja:allura:templates/user_totp.html')
     @without_trailing_slash
@@ -1204,7 +1204,7 @@ class SubscriptionsController(BaseController):
         if email_format:
             c.user.set_pref('email_format', email_format)
 
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class OAuthController(BaseController):
diff --git a/Allura/allura/controllers/base.py b/Allura/allura/controllers/base.py
index 2cf0c70..6a6ab28 100644
--- a/Allura/allura/controllers/base.py
+++ b/Allura/allura/controllers/base.py
@@ -19,7 +19,7 @@ import logging
 
 from tg import expose
 from webob import exc
-from tg.controllers.dispatcher import ObjectDispatcher
+from crank.objectdispatcher import ObjectDispatcher
 from tg import redirect, flash
 from pylons import tmpl_context as c
 
@@ -40,7 +40,7 @@ class BaseController(object):
             msg = '{} rate limit exceeded. '.format(message)
             log.warn(msg + c.app.config.url())
             flash(msg + 'Please try again later.', 'error')
-            redirect(redir)
+            redirect(redir or '/')
 
 
 class DispatchIndex(object):
diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index fdc89cc..34f085d 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -95,7 +95,7 @@ class DiscussionController(BaseController, FeedController):
             self.moderate = ModerationController(self)
 
     def error_handler(self, *args, **kwargs):
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @h.vardec
     @expose()
@@ -110,7 +110,7 @@ class DiscussionController(BaseController, FeedController):
                 thread.unsubscribe()
             session(self.M.Thread)._get().skip_mod_date = True
             session(self.M.Thread)._get().skip_last_updated = True
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     def get_feed(self, project, app, user):
         """Return a :class:`allura.controllers.feed.FeedArgs` object describing
@@ -212,7 +212,7 @@ class ThreadController(BaseController, FeedController):
                     show_moderate=kw.get('show_moderate'))
 
     def error_handler(self, *args, **kwargs):
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @memorable_forget()
     @h.vardec
@@ -233,7 +233,7 @@ class ThreadController(BaseController, FeedController):
         if self.thread.ref:
             require_access(self.thread.ref.artifact, 'post')
         self.thread.labels = labels.split(',')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     def flag_as_spam(self, **kw):
@@ -264,14 +264,14 @@ def handle_post_or_reply(thread, edit_widget, rate_limit, kw, parent_post_id=Non
     if not kw['text']:
         flash('Your post was not saved. You must provide content.',
               'error')
-        redirect(request.referer)
+        redirect(request.referer or '/')
     file_info = kw.get('file_info', None)
     p = thread.add_post(parent_id=parent_post_id, **kw)
     p.add_multiple_attachments(file_info)
     if thread.artifact:
         thread.artifact.mod_date = datetime.utcnow()
     flash('Message posted')
-    redirect(request.referer)
+    redirect(request.referer or '/')
 
 
 class PostController(BaseController):
@@ -327,7 +327,7 @@ class PostController(BaseController):
                                        target=self.post.thread.artifact or self.post.thread,
                                        related_nodes=[self.post.app_config.project],
                                        tags=['comment'])
-            redirect(request.referer)
+            redirect(request.referer or '/')
         elif request.method == 'GET':
             if self.post.deleted:
                 raise exc.HTTPNotFound
@@ -357,7 +357,7 @@ class PostController(BaseController):
     @without_trailing_slash
     @expose('json:')
     @require_post()
-    def update_markdown(self, text=None, **kw):  
+    def update_markdown(self, text=None, **kw):
         if has_access(self.post, 'moderate'):
             self.post.text = text
             self.post.edit_count = self.post.edit_count + 1
@@ -393,11 +393,11 @@ class PostController(BaseController):
         if r in utils.get_reaction_emoji_list():
             self.post.post_reaction(r, c.user)
         else:
-            status = 'error' 
+            status = 'error'
         return dict(status=status, counts=self.post.react_counts)
 
     def error_handler(self, *args, **kwargs):
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @memorable_forget()
     @h.vardec
@@ -439,7 +439,7 @@ class PostController(BaseController):
     def attach(self, file_info=None):
         require_access(self.post, 'moderate')
         self.post.add_multiple_attachments(file_info)
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     def _lookup(self, id, *remainder):
@@ -539,7 +539,7 @@ class ModerationController(BaseController):
                         posted.approve()
                         g.spam_checker.submit_ham(posted.text, artifact=posted, user=posted.author())
                         posted.thread.post_to_feed(posted)
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class PostRestController(PostController):
diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py
index 0a6cbfa..d7c2d3d 100644
--- a/Allura/allura/controllers/project.py
+++ b/Allura/allura/controllers/project.py
@@ -881,7 +881,7 @@ class NeighborhoodAwardsController(object):
                     icon.filename, icon.file, content_type=icon.type,
                     square=True, thumbnail_size=(48, 48),
                     thumbnail_meta=dict(award_id=award._id))
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
@@ -902,7 +902,7 @@ class NeighborhoodAwardsController(object):
             award.comment = comment
             with h.push_context(recipient_q._id):
                 g.post_event('project_updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class AwardController(object):
@@ -970,7 +970,7 @@ class AwardController(object):
                     g.post_event('project_updated')
             M.AwardFile.query.remove(dict(award_id=self.award._id))
             self.award.delete()
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class GrantController(object):
@@ -1012,7 +1012,7 @@ class GrantController(object):
         self.grant.delete()
         with h.push_context(self.project._id):
             g.post_event('project_updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class ProjectImporterController(object):
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 0989e0c..650065c 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -111,7 +111,7 @@ class RepoRootController(BaseController, FeedController):
         allura.tasks.repo_tasks.refresh.post()
         if request.referer:
             flash('Repository is being refreshed')
-            redirect(request.referer)
+            redirect(request.referer or '/')
         else:
             return '%r refresh queued.\n' % c.app.repo
 
@@ -152,7 +152,7 @@ class RepoRootController(BaseController, FeedController):
                     raise
                 except Exception, ex:
                     flash(str(ex), 'error')
-                    redirect(request.referer)
+                    redirect(request.referer or '/')
 
     @property
     def mr_widget(self):
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 830bcb4..d5d91f1 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -509,7 +509,7 @@ class SiteNotificationController(object):
     def delete(self):
         self.note.delete()
         ThreadLocalORMSession().flush_all()
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class TaskManagerController(object):
@@ -694,7 +694,7 @@ class AdminUserDetailsController(object):
             flash('Comment added', 'ok')
         else:
             flash('Can not add comment "%s" for user %s' % (comment, user))
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
@@ -713,7 +713,7 @@ class AdminUserDetailsController(object):
             AuthenticationProvider.get(request).deactivate_user(user)
             AuthenticationProvider.get(request).enable_user(user, audit=False)
             flash('Set user status to pending')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
@@ -725,7 +725,7 @@ class AdminUserDetailsController(object):
         AuthenticationProvider.get(request).set_password(user, None, pwd)
         h.auditlog_user('Set random password', user=user)
         flash('Password is set', 'ok')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
@@ -738,7 +738,7 @@ class AdminUserDetailsController(object):
             allura.controllers.auth.AuthController().password_recovery_hash(email)
         except HTTPFound:
             pass  # catch redirect to '/'
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @h.vardec
     @expose()
@@ -748,7 +748,7 @@ class AdminUserDetailsController(object):
         if not user or user.is_anonymous():
             raise HTTPNotFound()
         allura.controllers.auth.PreferencesController()._update_emails(user, admin=True, form_params=kw)
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class StatsSiteAdminExtension(SiteAdminExtension):
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index e0c5369..4b7ec42 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -707,7 +707,7 @@ class ProjectAdminController(BaseController):
             re.search(c.project.url() + r'(admin\/|)' + tool[0]['mount_point']+ r'\/*', request.referer):
             # Redirect to root when deleting currect module
             redirect('../')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose('jinja:allura.ext.admin:templates/export.html')
     def export(self, tools=None, with_attachments=False):
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index 1189174..50bd64a 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -124,21 +124,21 @@ class UserProfileController(BaseController, FeedController):
     def _check_can_message(self, from_user, to_user):
         if from_user is User.anonymous():
             flash('You must be logged in to send user messages.', 'info')
-            redirect(request.referer)
+            redirect(request.referer or '/')
 
         if not (from_user and from_user.get_pref('email_address')):
             flash('In order to send messages, you must have an email address '
                   'associated with your account.', 'info')
-            redirect(request.referer)
+            redirect(request.referer or '/')
 
         if not (to_user and to_user.get_pref('email_address')):
             flash('This user can not receive messages because they do not have '
                   'an email address associated with their account.', 'info')
-            redirect(request.referer)
+            redirect(request.referer or '/')
 
         if to_user.get_pref('disable_user_messages'):
             flash('This user has disabled direct email messages', 'info')
-            redirect(request.referer)
+            redirect(request.referer or '/')
 
     @expose('jinja:allura.ext.user_profile:templates/user_index.html')
     def index(self, **kw):
diff --git a/Allura/allura/lib/base.py b/Allura/allura/lib/base.py
index b0c9050..8000e88 100644
--- a/Allura/allura/lib/base.py
+++ b/Allura/allura/lib/base.py
@@ -55,19 +55,3 @@ class WsgiDispatchController(TGController):
         for chunk in response:
             yield chunk
         self._cleanup_request()
-
-    def _get_dispatchable(self, url_path):
-        """Patch ``TGController._get_dispatchable`` by overriding.
-
-        This fixes a bug in TG 2.1.5 that causes ``request.response_type``
-        to not be created if ``disable_request_extensions = True`` (see
-        allura/config/app_cfg.py).
-
-        ``request.response_type`` must be set because the "trailing slash"
-        decorators use it (see allura/lib/patches.py).
-
-        This entire method can be removed if/when we upgrade to TG >= 2.2.1
-
-        """
-        pylons.request.response_type = None
-        return super(WsgiDispatchController, self)._get_dispatchable(url_path)
diff --git a/Allura/allura/lib/repository.py b/Allura/allura/lib/repository.py
index c176a63..82d09c4 100644
--- a/Allura/allura/lib/repository.py
+++ b/Allura/allura/lib/repository.py
@@ -266,7 +266,7 @@ class RepoAdminController(DefaultAdminController):
     def set_default_branch_name(self, branch_name=None, **kw):
         if (request.method == 'POST') and branch_name:
             self.repo.set_default_branch(branch_name)
-            redirect(request.referer)
+            redirect(request.referer or '/')
         else:
             return dict(app=self.app,
                         default_branch_name=self.app.default_branch_name)
@@ -302,7 +302,7 @@ class RepoAdminController(DefaultAdminController):
             flash(message,
                   'error' if 'Invalid' in message else 'ok')
 
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class RepoAdminRestController(BaseController):
diff --git a/Allura/allura/tests/scripts/test_delete_projects.py b/Allura/allura/tests/scripts/test_delete_projects.py
index 5f222e0..d0f8620 100644
--- a/Allura/allura/tests/scripts/test_delete_projects.py
+++ b/Allura/allura/tests/scripts/test_delete_projects.py
@@ -104,6 +104,7 @@ class TestDeleteProjects(TestController):
     @patch('allura.lib.helpers.request', autospec=True)
     def test_userproject_does_disable(self, req, req2):
         req.remote_addr = None
+        req.user_agent = 'MozFoo'
         req2.url = None
         self.run_script(['u/test-user'])
         assert M.User.by_username('test-user').disabled
@@ -149,6 +150,7 @@ class TestDeleteProjects(TestController):
     @patch('allura.lib.helpers.request', autospec=True)
     def test_disable_users(self, req, req2):
         req.remote_addr = None
+        req.user_agent = 'MozFoo'
         req2.url = None
         self._disable_users(disable=True)
 
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 7205610..407e435 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -519,7 +519,7 @@ class BlogAdminController(DefaultAdminController):
         self.app.config.options[
             'AllowEmailPosting'] = allow_email_posting and True or False
         flash('Blog options updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @without_trailing_slash
     @expose('jinja:forgeblog:templates/blog/admin_exfeed.html')
@@ -563,7 +563,7 @@ class BlogAdminController(DefaultAdminController):
             flash('Invalid link(s): %s' %
                   ','.join(link for link in invalid_list), 'error')
 
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class RootRestController(BaseController, AppRestControllerMixin):
diff --git a/ForgeChat/forgechat/main.py b/ForgeChat/forgechat/main.py
index 64b15e5..8e01426 100644
--- a/ForgeChat/forgechat/main.py
+++ b/ForgeChat/forgechat/main.py
@@ -120,7 +120,7 @@ class AdminController(DefaultAdminController):
 
     @with_trailing_slash
     def index(self, **kw):
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py b/ForgeDiscussion/forgediscussion/controllers/root.py
index 55c2e1f..7ba008c 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -136,7 +136,7 @@ class RootController(BaseController, DispatchIndex, FeedController):
             shortname=forum)
         if discussion.deleted and not has_access(c.app, 'configure')():
             flash('This forum has been removed.')
-            redirect(request.referrer)
+            redirect(request.referer or '/')
         require_access(discussion, 'post')
         thd = discussion.get_discussion_thread(dict(
             headers=dict(Subject=subject)))[0]
diff --git a/ForgeDiscussion/forgediscussion/forum_main.py b/ForgeDiscussion/forgediscussion/forum_main.py
index 60b97d3..7e957a3 100644
--- a/ForgeDiscussion/forgediscussion/forum_main.py
+++ b/ForgeDiscussion/forgediscussion/forum_main.py
@@ -329,7 +329,7 @@ class ForumAdminController(DefaultAdminController):
                 else:
                     forum.acl = []
         flash('Forums updated')
-        redirect(request.referrer)
+        redirect(request.referer or '/')
 
     @h.vardec
     @expose()
diff --git a/ForgeSVN/forgesvn/svn_main.py b/ForgeSVN/forgesvn/svn_main.py
index 37febd3..60bb345 100644
--- a/ForgeSVN/forgesvn/svn_main.py
+++ b/ForgeSVN/forgesvn/svn_main.py
@@ -181,7 +181,7 @@ class SVNImportController(BaseController, AdminControllerMixin):
             M.Notification.post_user(
                 c.user, self.app.repo, 'error',
                 text="Can't import into non empty repository.")
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class SVNCommitBrowserController(BaseController):
diff --git a/ForgeShortUrl/forgeshorturl/main.py b/ForgeShortUrl/forgeshorturl/main.py
index 7316ac4..2be5b7f 100644
--- a/ForgeShortUrl/forgeshorturl/main.py
+++ b/ForgeShortUrl/forgeshorturl/main.py
@@ -200,7 +200,7 @@ class ShortURLAdminController(DefaultAdminController):
 
     @expose()
     def index(self, **kw):
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @without_trailing_slash
     @expose('json:')
@@ -228,7 +228,7 @@ class ShortURLAdminController(DefaultAdminController):
                     names = {'short_url': 'Short url', 'full_url': 'Full URL'}
                     error_msg += '%s: %s ' % (names[msg], c.form_errors[msg])
                     flash(error_msg, 'error')
-                redirect(request.referer)
+                redirect(request.referer or '/')
 
             shorturl = ShortUrl.query.find({
                 'app_config_id': self.app.config._id,
@@ -237,7 +237,7 @@ class ShortURLAdminController(DefaultAdminController):
             if shorturl is not None:
                 if not update:
                     flash('Short url %s already exists' % short_url, 'error')
-                    redirect(request.referer)
+                    redirect(request.referer or '/')
                 else:
                     msg = ('update short url %s from %s to %s'
                            % (short_url, shorturl.full_url, full_url))
@@ -258,7 +258,7 @@ class ShortURLAdminController(DefaultAdminController):
             shorturl.last_updated = datetime.utcnow()
 
             M.AuditLog.log(msg)
-            redirect(request.referer)
+            redirect(request.referer or '/')
         return dict(
             app=self.app,
             url_len=len(ShortUrl.build_short_url(c.app, short_name='')))
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index ad3b2b7..135df0e 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1214,7 +1214,7 @@ class BinController(BaseController, AdminControllerMixin):
     def delbin(self, bin=None):
         require(lambda: bin.app_config_id == self.app.config._id)
         bin.delete()
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @without_trailing_slash
     @h.vardec
@@ -1624,16 +1624,16 @@ class TicketController(BaseController, FeedController):
             tracker = M.AppConfig.query.get(_id=t_id)
             if tracker is None:
                 flash('Select valid tracker', 'error')
-                redirect(request.referer)
+                redirect(request.referer or '/')
 
             if tracker == self.ticket.app.config:
                 flash('Ticket already in a selected tracker', 'info')
-                redirect(request.referer)
+                redirect(request.referer or '/')
 
             if not has_access(tracker, 'admin')():
                 flash('You should have admin access to destination tracker',
                       'error')
-                redirect(request.referer)
+                redirect(request.referer or '/')
 
             new_ticket = self.ticket.move(tracker)
             c.app.globals.invalidate_bin_counts()
@@ -1721,7 +1721,7 @@ class TrackerAdminController(DefaultAdminController):
         for k, v in kw.iteritems():
             self.app.config.options[k] = v
         flash('Options updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     @require_post()
@@ -1731,7 +1731,7 @@ class TrackerAdminController(DefaultAdminController):
                 self.app.globals['show_in_search'][column] = True
             else:
                 self.app.globals['show_in_search'][column] = False
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose()
     def update_tickets(self, **post_data):
@@ -1824,7 +1824,7 @@ class TrackerAdminController(DefaultAdminController):
 
         self.app.globals.custom_fields = custom_fields
         flash('Fields updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class RootRestController(BaseController, AppRestControllerMixin):
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index c62ee0b..5e7b4f5 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -519,7 +519,7 @@ class RootController(BaseController, DispatchIndex, FeedController):
             M.Mailbox.subscribe(type='direct')
         elif unsubscribe:
             M.Mailbox.unsubscribe()
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
 
 class PageController(BaseController, FeedController):
@@ -808,7 +808,7 @@ class PageController(BaseController, FeedController):
         self.page.add_multiple_attachments(file_info)
         if is_ajax(request):
             return
-        redirect(request.referer)
+        redirect(request.referer or '/')
 
     @expose('json:')
     @require_post()
@@ -956,4 +956,4 @@ class WikiAdminController(DefaultAdminController):
         self.app.show_right_bar = show_right_bar
         self.app.allow_email_posting = allow_email_posting
         flash('Wiki options updated')
-        redirect(request.referer)
+        redirect(request.referer or '/')
diff --git a/requirements.txt b/requirements.txt
index 7189d95..1a6b730 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -49,10 +49,10 @@ textile==2.1.5
 # dep of colander
 translationstring==0.4
 TimerMiddleware==0.4.4
-TurboGears2==2.1.5
+TurboGears2==2.2.2
 # dep of html5lib
 webencodings==0.5.1
-WebOb==1.0.8
+WebOb==1.1.1
 
 # dependencies for cryptography
 cryptography==2.6.1
@@ -66,12 +66,14 @@ asn1crypto==0.24.0
 
 # tg2 deps (not used directly)
 Babel==1.3
-Mako==0.3.2
+crank==0.8.1
+Mako==0.9.1
 MarkupSafe==1.0
 Pylons==1.0
-simplejson==2.2.1
+repoze.lru==0.7
+simplejson==3.16.0
 Tempita==0.5.1
-Routes==1.12.3
+Routes==2.4.1
 WebFlash==0.1a9
 WebHelpers==1.3
 


[allura] 07/08: [#8273] TG 2.3.0: signature of TGController.__call__ changed

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit e223aa580e78de982d3b74184d0cd2d01f598ac7
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri Mar 22 17:55:38 2019 -0400

    [#8273] TG 2.3.0: signature of TGController.__call__ changed
---
 Allura/allura/controllers/basetest_project_root.py |  4 ++--
 Allura/allura/controllers/task.py                  | 12 ++++++++----
 Allura/allura/lib/base.py                          |  4 ++--
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index 4d5cad3..5b1adad 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -120,7 +120,7 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
         c.app = app
         return app.root, remainder
 
-    def __call__(self, environ, start_response):
+    def __call__(self, environ, context):
         """ Called from a WebTest 'app' instance.
 
 
@@ -142,7 +142,7 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
             environ['beaker.session'].save()
             environ['beaker.session'].persist()
             c.user = auth.authenticate_request()
-        return WsgiDispatchController.__call__(self, environ, start_response)
+        return WsgiDispatchController.__call__(self, environ, context)
 
 
 class DispatchTest(object):
diff --git a/Allura/allura/controllers/task.py b/Allura/allura/controllers/task.py
index cb666ee..e8669d7 100644
--- a/Allura/allura/controllers/task.py
+++ b/Allura/allura/controllers/task.py
@@ -22,12 +22,16 @@ class TaskController(object):
 
     The purpose of this app is to allow us to replicate the
     normal web request environment as closely as possible
-    when executing celery tasks.
+    when executing taskd tasks.
     '''
 
-    def __call__(self, environ, start_response):
+    def __call__(self, environ, context):
+        # see TGController / CoreDispatcher for reference on how this works on a normal controllers
+
         task = environ['task']
         nocapture = environ['nocapture']
         result = task(restore_context=False, nocapture=nocapture)
-        start_response('200 OK', [])
-        return [result]
+        py_response = context.response
+        py_response.headers['Content-Type'] = 'text/plain'  # `None` default is problematic for some middleware
+        py_response.body = result or ''
+        return py_response
diff --git a/Allura/allura/lib/base.py b/Allura/allura/lib/base.py
index 148c3e8..36b1aa4 100644
--- a/Allura/allura/lib/base.py
+++ b/Allura/allura/lib/base.py
@@ -37,6 +37,6 @@ class WsgiDispatchController(TGController):
         '''Responsible for setting all the values we need to be set on pylons.tmpl_context'''
         raise NotImplementedError, '_setup_request'
 
-    def __call__(self, environ, start_response):
+    def __call__(self, environ, context):
         self._setup_request()
-        return super(WsgiDispatchController, self).__call__(environ, start_response)
+        return super(WsgiDispatchController, self).__call__(environ, context)


[allura] 05/08: [#8273] TG 2.3.0: root controller is only init'd once, so move dynamic code to _lookup; basetestroot now gives precedence to full root-based urls

Posted by br...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8273
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 296bcdd6db3f2394ddc67919ad820870f22b9515
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu Mar 21 17:57:25 2019 -0400

    [#8273] TG 2.3.0: root controller is only init'd once, so move dynamic code to _lookup; basetestroot now gives precedence to full root-based urls
---
 Allura/allura/controllers/basetest_project_root.py | 41 ++++++++++++----------
 Allura/allura/controllers/root.py                  | 20 +++++++----
 Allura/allura/controllers/site_admin.py            |  3 +-
 Allura/allura/model/neighborhood.py                |  5 ---
 .../allura/tests/functional/test_neighborhood.py   |  4 +--
 Allura/allura/tests/functional/test_search.py      |  8 ++---
 6 files changed, 44 insertions(+), 37 deletions(-)

diff --git a/Allura/allura/controllers/basetest_project_root.py b/Allura/allura/controllers/basetest_project_root.py
index 0a5047d..4d5cad3 100644
--- a/Allura/allura/controllers/basetest_project_root.py
+++ b/Allura/allura/controllers/basetest_project_root.py
@@ -42,10 +42,9 @@ log = logging.getLogger(__name__)
 
 
 class BasetestProjectRootController(WsgiDispatchController, ProjectController):
-    '''Root controller for testing -- it behaves just like a
-    ProjectController for test/ except that all tools are mounted,
-    on-demand, at the mount point that is the same as their entry point
-    name.
+    '''Root controller for testing -- it behaves just like the RootController
+    plus acts as shorthand for the ProjectController at /p/test/ plus all tools are mounted,
+    on-demand, at the mount point that is the same as their entry point name.
 
     Also, the test-admin is perpetually logged in here.
 
@@ -58,20 +57,20 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
     '''
 
     def __init__(self):
-        for n in M.Neighborhood.query.find():
-            if n.url_prefix.startswith('//'):
-                continue
-            n.bind_controller(self)
-            if n.url_prefix == '/p/':
-                self.p_nbhd = n
-
-        proxy_root = RootController()
+        self.p_nbhd = M.Neighborhood.query.get(url_prefix='/p/')
+        assert self.p_nbhd
+
         self.dispatch = DispatchTest()
         self.security = SecurityTests()
-        for attr in ('index', 'browse', 'auth', 'nf', 'error', 'categories', 'neighborhood', 'dashboard'):
-            setattr(self, attr, getattr(proxy_root, attr))
-        self.gsearch = proxy_root.search
-        self.rest = RestController()
+
+        # proxy root controller paths
+        self.real_root_controller = RootController()
+        for attr in dir(self.real_root_controller):
+            if not attr.startswith('_'):
+                setattr(self, attr, getattr(self.real_root_controller, attr))
+
+        # neighborhoods & projects handled in _lookup
+
         super(BasetestProjectRootController, self).__init__()
 
     def _setup_request(self):
@@ -90,8 +89,14 @@ class BasetestProjectRootController(WsgiDispatchController, ProjectController):
 
     @expose()
     def _lookup(self, name, *remainder):
-        if not h.re_project_name.match(name):
-            raise exc.HTTPNotFound, name
+        # first try a neighborhood path through the real root controller
+        try:
+            return self.real_root_controller._lookup(name, *remainder)
+        except exc.HTTPNotFound:
+            pass
+
+        # magic shorthand helper lookups so self.app.get('/wiki') instantiates a wiki and calls /p/test/wiki controller
+
         subproject = M.Project.query.get(
             shortname=c.project.shortname + '/' + name,
             neighborhood_id=self.p_nbhd._id)
diff --git a/Allura/allura/controllers/root.py b/Allura/allura/controllers/root.py
index 7a6bee2..c4e1bd4 100644
--- a/Allura/allura/controllers/root.py
+++ b/Allura/allura/controllers/root.py
@@ -26,11 +26,13 @@ from tg.flash import TGFlash
 from tg import tmpl_context as c
 from tg import response
 from paste.deploy.converters import asbool
+from webob import exc
 
 from allura.app import SitemapEntry
 from allura.lib.base import WsgiDispatchController
 from allura.lib import plugin
 from allura.controllers.error import ErrorController
+from allura.controllers.project import NeighborhoodController
 from allura import model as M
 from allura.lib.widgets import project_list as plw
 from allura.ext.personal_dashboard.dashboard_main import DashboardController
@@ -77,16 +79,20 @@ class RootController(WsgiDispatchController):
     rest = RestController()
     categories = TroveCategoryController()
     dashboard = DashboardController()
-
+    browse = ProjectBrowseController()
+    
     def __init__(self):
-        n_url_prefix = '/%s/' % request.path.split('/')[1]
+        super(RootController, self).__init__()
+        self.nf.admin = SiteAdminController()
+        
+    @expose()
+    def _lookup(self, nbhd_mount, *remainder):
+        n_url_prefix = '/%s/' % nbhd_mount
         n = self._lookup_neighborhood(n_url_prefix)
         if n and not n.url_prefix.startswith('//'):
-            n.bind_controller(self)
-        self.browse = ProjectBrowseController()
-        self.nf.admin = SiteAdminController()
-
-        super(RootController, self).__init__()
+            return NeighborhoodController(n), remainder
+        else:
+            raise exc.HTTPNotFound
 
     def _lookup_neighborhood(self, url_prefix):
         n = M.Neighborhood.query.get(url_prefix=url_prefix)
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index d173800..76c09a0 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -65,7 +65,6 @@ class SiteAdminController(object):
 
     def __init__(self):
         self.task_manager = TaskManagerController()
-        c.site_admin_sidebar_menu = self.sidebar_menu()
         self.user = AdminUserDetailsController()
         self.delete_projects = DeleteProjectsController()
         self.site_notifications = SiteNotificationController()
@@ -75,6 +74,8 @@ class SiteAdminController(object):
                             neighborhood=config.get('site_admin_project_nbhd', 'Projects')):
             require_access(c.project, 'admin')
 
+        c.site_admin_sidebar_menu = self.sidebar_menu()
+
     @expose()
     def _lookup(self, name, *remainder):
         for ep_name in sorted(g.entry_points['site_admin'].keys()):
diff --git a/Allura/allura/model/neighborhood.py b/Allura/allura/model/neighborhood.py
index 789f5ea..38356bf 100644
--- a/Allura/allura/model/neighborhood.py
+++ b/Allura/allura/model/neighborhood.py
@@ -152,11 +152,6 @@ class Neighborhood(MappedClass):
         return provider.register_project(
             self, shortname, project_name, user or getattr(c, 'user', None), user_project, private_project, apps)
 
-    def bind_controller(self, controller):
-        from allura.controllers.project import NeighborhoodController
-        controller_attr = self.url_prefix[1:-1]
-        setattr(controller, controller_attr, NeighborhoodController(self))
-
     def get_custom_css(self):
         if self.allow_custom_css:
             return self.css
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index dd22da4..211b745 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -290,10 +290,10 @@ class TestNeighborhood(TestController):
         r = self.app.post('/adobe/_admin/update',
                           params=dict(name='Adobe', css='',
                                       homepage='# MozQ1', tracking_id='U-123456'),
-                          extra_environ=dict(username='root'))
+                          extra_environ=dict(username='root'), status=302)
         r = self.app.post('/adobe/adobe-1/admin/update',
                           params=dict(tracking_id='U-654321'),
-                          extra_environ=dict(username='root'))
+                          extra_environ=dict(username='root'), status=302)
         r = self.app.get('/adobe/adobe-1/admin/overview',
                          extra_environ=dict(username='root'))
         assert "_add_tracking('nbhd', 'U-123456');" in r, r
diff --git a/Allura/allura/tests/functional/test_search.py b/Allura/allura/tests/functional/test_search.py
index 374d5f3..118c0f0 100644
--- a/Allura/allura/tests/functional/test_search.py
+++ b/Allura/allura/tests/functional/test_search.py
@@ -23,11 +23,11 @@ class TestSearch(TestController):
 
     @patch('allura.lib.search.search')
     def test_global_search_controller(self, search):
-        self.app.get('/gsearch/')
+        self.app.get('/search/')
         assert not search.called, search.called
-        self.app.get('/gsearch/', params=dict(q='Root'))
+        self.app.get('/search/', params=dict(q='Root'))
         assert search.called, search.called
 
     def test_project_search_controller(self):
-        self.app.get('/search/')
-        self.app.get('/search/', params=dict(q='Root'))
+        self.app.get('/p/test/search/')
+        self.app.get('/p/test/search/', params=dict(q='Root'))