Commits

Anonymous committed 66c3269 Merge

Merge.

  • Participants
  • Parent commits cf1870d, cbe791a

Comments (0)

Files changed (28)

+include ckan/config/deployment.ini_tmpl
 recursive-include ckan/public *
 recursive-include ckan/templates *
 include CHANGELOG.txt

ckan/config/environment.py

 
 from sqlalchemy import engine_from_config
 from pylons import config
+from pylons.i18n.translation import ugettext
 from genshi.template import TemplateLoader
+from genshi.filters.i18n import Translator
 
 import ckan.lib.app_globals as app_globals
 import ckan.lib.helpers
 from ckan.config.routing import make_map
 from ckan import model
 
-from genshi.filters.i18n import Translator
-from pylons.i18n.translation import ugettext
 
 def load_environment(global_conf, app_conf):
     """Configure the Pylons environment via the ``pylons.config``
                  templates=[os.path.join(root, 'templates')])
 
     # Initialize config with the basic options
-    config.init_app(global_conf, app_conf, package='ckan',
-                    template_engine='genshi', paths=paths)
+    config.init_app(global_conf, app_conf, package='ckan', paths=paths)
 
     config['routes.map'] = make_map()
     config['pylons.app_globals'] = app_globals.Globals()
     # tmpl_options["genshi.loader_callback"] = template_loaded
     config['pylons.app_globals'].genshi_loader = TemplateLoader(
         template_paths, auto_reload=True, callback=template_loaded)
-    # HACK! For some reason callback=template_loaded in previous line does
-    # *not* work (this required 1h to track down!!)
-    # This does work ...
-    tmpl_options = config['buffet.template_options']
-    tmpl_options["genshi.loader_callback"] = template_loaded
 
     # CONFIGURATION OPTIONS HERE (note: all config options will override
     # any Pylons config options)

ckan/config/middleware.py

 """Pylons middleware initialization"""
+from beaker.middleware import CacheMiddleware, SessionMiddleware
 from paste.cascade import Cascade
 from paste.registry import RegistryManager
 from paste.urlparser import StaticURLParser
 from paste.deploy.converters import asbool
-
 from pylons import config
-from pylons.error import error_template
-from pylons.middleware import ErrorHandler, StaticJavascripts, StatusCodeRedirect
+from pylons.middleware import ErrorHandler, StatusCodeRedirect
 from pylons.wsgiapp import PylonsApp
+from routes.middleware import RoutesMiddleware
 
 from ckan.config.environment import load_environment
 
-def make_app(global_conf, full_stack=True, **app_conf):
+def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
     """Create a Pylons WSGI application and return it
 
     ``global_conf``
         the [DEFAULT] section of the Paste ini file.
 
     ``full_stack``
-        Whether or not this application provides a full WSGI stack (by
-        default, meaning it handles its own exceptions and errors).
-        Disable full_stack when this application is "managed" by
-        another WSGI middleware.
+        Whether this application provides a full WSGI stack (by default,
+        meaning it handles its own exceptions and errors). Disable
+        full_stack when this application is "managed" by another WSGI
+        middleware.
+
+    ``static_files``
+        Whether this application serves its own static files; disable
+        when another web server is responsible for serving them.
 
     ``app_conf``
-        The application's local configuration. Normally specified in the
-        [app:<name>] section of the Paste ini file (where <name>
+        The application's local configuration. Normally specified in
+        the [app:<name>] section of the Paste ini file (where <name>
         defaults to main).
+
     """
     # Configure the Pylons environment
     load_environment(global_conf, app_conf)
     # The Pylons WSGI app
     app = PylonsApp()
 
+    # Routing/Session/Cache Middleware
+    app = RoutesMiddleware(app, config['routes.map'])
+    app = SessionMiddleware(app, config)
+    app = CacheMiddleware(app, config)
+
     # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
 
-    import pylons
-    if pylons.__version__ >= "0.9.7":
-        # Routing/Session/Cache Middleware
-        from beaker.middleware import CacheMiddleware, SessionMiddleware
-        from routes.middleware import RoutesMiddleware
-        app = RoutesMiddleware(app, config['routes.map'])
-        app = SessionMiddleware(app, config)
-        app = CacheMiddleware(app, config)
-
-    from repoze.who.config import make_middleware_with_config
-    app = make_middleware_with_config(app, global_conf,
-            app_conf['who.config_file'], app_conf['who.log_file'],
-            app_conf['who.log_level'])
-
     if asbool(full_stack):
         # Handle Python exceptions
-        app = ErrorHandler(app, global_conf,**config['pylons.errorware'])
+        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
 
         # Display error documents for 401, 403, 404 status codes (and
         # 500 when debug is disabled)
         if asbool(config['debug']):
             app = StatusCodeRedirect(app)
         else:
-            app = StatusCodeRedirect(app, [401, 403, 404, 500])
+            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
+    
+    from repoze.who.config import make_middleware_with_config
+    app = make_middleware_with_config(app, global_conf,
+        app_conf['who.config_file'], app_conf['who.log_file'],
+        app_conf['who.log_level'])
+
 
     # Establish the Registry for this application
     app = RegistryManager(app)
 
-    # Static files
-    static_app = StaticURLParser(config['pylons.paths']['static_files'])
-    app = Cascade([static_app, app])
+    if asbool(static_files):
+        # Serve static files
+        static_app = StaticURLParser(config['pylons.paths']['static_files'])
+        app = Cascade([static_app, app])
+
     return app

ckan/config/routing.py

     """Create, configure and return the routes Mapper"""
     map = Mapper(directory=config['pylons.paths']['controllers'],
                  always_scan=config['debug'])
+    map.minimization = False
 
     # The ErrorController route (handles 404/500 error pages); it should
     # likely stay at the top, ensuring it can always be resolved
-    map.connect('/error/:action/:id', controller='error')
+    map.connect('/error/{action}', controller='error')
+    map.connect('/error/{action}/{id}', controller='error')
 
     # CUSTOM ROUTES HERE
     map.connect('home', '/', controller='home', action='index')
     map.connect('/user/logout', controller='user', action='logout')
     map.connect('/user/apikey', controller='user', action='apikey')
     map.connect('/user/:id', controller='user', action='read')
-    map.connect('/:controller/:action/:id')
-    map.connect('/:controller/', action='index')
-    map.connect('/:controller/:action/', id=None)
+    map.connect('/{controller}', action='index')
+    map.connect('/:controller/{action}')
+    map.connect('/{controller}/{action}/{id}')
+    map.redirect('/*(url)/', '/{url}',
+                 _redirect_code='301 Moved Permanently')
     map.connect('/*url', controller='template', action='view')
 
     return map

ckan/controllers/error.py

 import cgi
-import os.path
 
-import paste.fileapp
-from pylons.middleware import error_document_template, media_path
+from paste.urlparser import PkgResourcesParser
+from pylons import request
+from pylons.controllers.util import forward
+from pylons.middleware import error_document_template
+from webhelpers.html.builder import literal
 
-from ckan.lib.base import *
+from ckan.lib.base import BaseController
+from ckan.lib.base import render
 
 class ErrorController(BaseController):
+
     """Generates error documents as and when they are required.
 
     The ErrorDocuments middleware forwards to ErrorController when error
 
     This behaviour can be altered by changing the parameters to the
     ErrorDocuments middleware in your config/middleware.py file.
+
     """
 
     def document(self):
         """Render the error document"""
-        ckan_template = render("error_document_template")
-        ckan_template = ckan_template.decode('utf8')
-        response = request.environ.get('pylons.original_response')
+        ckan_template = render('error_document_template.html')
+        # ckan_template = ckan_template.decode('utf8')
+        resp = request.environ.get('pylons.original_response')
+        content = literal(resp.body) or cgi.escape(request.GET.get('message', ''))
+        # page = error_document_template % \
         page = ckan_template % \
             dict(prefix=request.environ.get('SCRIPT_NAME', ''),
-                 code=cgi.escape(request.GET.get('code', str(response.status_int))),
-                 message=h.literal(response.body) or cgi.escape(request.GET.get('message', '')))
+                 code=cgi.escape(request.GET.get('code', str(resp.status_int))),
+                 message=content)
         return page
 
     def img(self, id):
         """Serve Pylons' stock images"""
-        return self._serve_file(os.path.join(media_path, 'img', id))
+        return self._serve_file('/'.join(['media/img', id]))
 
     def style(self, id):
         """Serve Pylons' stock stylesheets"""
-        return self._serve_file(os.path.join(media_path, 'style', id))
+        return self._serve_file('/'.join(['media/style', id]))
 
     def _serve_file(self, path):
         """Call Paste's FileApp (a WSGI application) to serve the file
         at the specified path
         """
-        fapp = paste.fileapp.FileApp(path)
-        return fapp(request.environ, self.start_response)
+        request.environ['PATH_INFO'] = '/%s' % path
+        return forward(PkgResourcesParser('pylons', 'pylons'))

ckan/controllers/group.py

             page=request.params.get('page', 1),
             items_per_page=20
         )
-        return render('group/index')
+        return render('group/index.html')
 
     def read(self, id):
         c.group = model.Group.by_name(id)
             page=request.params.get('page', 1),
             items_per_page=50
         )
-        return render('group/read')
+        return render('group/read.html')
 
     def new(self):
         record = model.Group
             except ValidationException, error:
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs)
-                return render('group/edit')
+                return render('group/edit.html')
             # do not use groupname from id as may have changed
             c.groupname = c.fs.name.value
             group = model.Group.by_name(c.groupname)
             data = ckan.forms.edit_group_dict(ckan.forms.get_group_dict(), request.params)
             fs = fs.bind(data=data, session=model.Session)
         c.form = self._render_edit_form(fs)
-        return render('group/new')
+        return render('group/new.html')
 
     def edit(self, id=None): # allow id=None to allow posting
         c.error = ''
             
             fs = ckan.forms.get_group_fieldset('group_fs').bind(c.group)
             c.form = self._render_edit_form(fs)
-            return render('group/edit')
+            return render('group/edit.html')
         else:
             # id is the name (pre-edited state)
             c.groupname = id
             except ValidationException, error:
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs)
-                return render('group/edit')
+                return render('group/edit.html')
             pkgs = [model.Package.by_name(name) for name in request.params.getall('Group-packages-current')]
             group.packages = pkgs
             pkgids = request.params.getall('PackageGroup--package_id')
             except ValidationException, error:
                 # TODO: sort this out 
                 # fs = error.args[0]
-                # return render('group/authz')
+                # return render('group/authz.html')
                 raise
             # now do new roles
             newrole_user_id = request.params.get('GroupRole--user_id')
         fs = ckan.forms.get_authz_fieldset('group_authz_fs').bind(group.roles)
         c.form = fs.render()
         c.new_roles_form = ckan.forms.get_authz_fieldset('new_group_roles_fs').render()
-        return render('group/authz')
+        return render('group/authz.html')
 
     def _render_edit_form(self, fs):
         # errors arrive in c.error and fs.errors
         c.fieldset = fs
         c.fieldset2 = ckan.forms.get_group_fieldset('new_package_group_fs')
-        return render('group/edit_form')
+        return render('group/edit_form.html')
 
     def _update(self, fs, group_name, group_id):
         '''

ckan/controllers/home.py

         # 3600=hourly, 86400=daily
         c.tag_counts = mycache.get_value(key='tag_counts_home_page',
                 createfunc=tag_counts, expiretime=86400)
-        return render('home/index')
+        return render('home/index.html')
 
     def license(self):
-        return render('home/license')
+        return render('home/license.html')
 
     def about(self):
-        return render('home/about')
+        return render('home/about.html')
 
     def stats(self):
         def stats_html():
             c.top_package_owners = stats.top_package_owners()
             c.new_packages_by_week = rev_stats.get_by_week('new_packages')
             c.package_revisions_by_week = rev_stats.get_by_week('package_revisions')
-            return render('home/stats')
+            return render('home/stats.html')
         if not c.user:
             mycache = cache.get_cache('stats', type='dbm')
             # 3600=hourly, 86400=daily

ckan/controllers/importer.py

     authorizer = ckan.authz.Authorizer()
 
     def index(self):
-        return render('importer/importer')
+        return render('importer/importer.html')
 
     def preview(self):
         if not c.user:
         params = dict(request.params)
         if not params.has_key('file'):
             c.error = _('Need to specify a filename.')
-            return render('importer/importer')                
+            return render('importer/importer.html')                
         if not hasattr(params['file'], 'value'):
             c.error = _('Did not receive file successfully.')
-            return render('importer/importer')
+            return render('importer/importer.html')
         file_buf = params['file'].value
         # save as temp file for when you do import
         self._save_tempfile(file_buf)
         if not file_buf:
             c.error = _('File \'%s\' not found.') % params['file'].filename
-            return render('importer/importer')
+            return render('importer/importer.html')
         try:
             importer = importer.PackageImporter(buf=file_buf)
         except importer.ImportException, e:
             c.error = _('Error importing file \'%s\' as Excel or CSV format: %s') % (params['file'].filename, e)
-            return render('importer/importer')
+            return render('importer/importer.html')
         c.import_filename = params['file'].filename.lstrip(os.sep)
         if params.has_key('log_message'):
             c.log_message = params['log_message']
             c.fs_list.append(fs)
         c.errors = len(all_errors)
         c.num_pkgs = len(c.fs_list)
-        return render('importer/preview')
+        return render('importer/preview.html')
 
     def do_import(self):
         import ckan.lib.importer as importer
             importer = importer.PackageImporter(buf=file_buf)
         except importer.ImportException, e:
             c.error = _('Error importing file \'%s\' as Excel or CSV format: %s') % (params['file'].filename, e)
-            return render('importer/importer')
+            return render('importer/importer.html')
         if 'log_message' in request.params:
             log_message = request.params.getone('log_message')
         else:
 
         model.Session.commit()
         c.message = ungettext('Imported %i package.', 'Imported %i packages.', count) % count
-        return render('importer/result')
+        return render('importer/result.html')
 
     def _get_fs(self, importer):
         for index, pkg_dict in enumerate(importer.pkg_dict()):
     def package_render(self, fs, errors, warnings):
         try:
             PackageSaver().render_preview(fs, None, None) # create a new package for now
-            preview = h.literal(render('package/read_core'))
+            preview = h.literal(render('package/read_core.html'))
         except ValidationException, error:
             c.error, fs = error.args
             preview = h.literal('<li>Errors: %s</li>\n') % c.error

ckan/controllers/package.py

     def index(self):
         query = ckan.authz.Authorizer().authorized_query(c.user, model.Package)
         c.package_count = query.count()
-        return render('package/index')
+        return render('package/index.html')
 
     def list(self):
         query = ckan.authz.Authorizer().authorized_query(c.user, model.Package)
             page=request.params.get('page', 1),
             items_per_page=50
         )
-        return render('package/list')
+        return render('package/list.html')
 
     def search(self):        
         c.q = request.params.get('q') # unicode format (decoded from utf8)
             c.tags = results['results']
             c.tags_count = results['count']
 
-        return render('package/search')
+        return render('package/search.html')
 
     def read(self, id):
         pkg = model.Package.by_name(id)
         c.auth_for_change_state = self.authorizer.am_authorized(c, model.Action.CHANGE_STATE, pkg)
 
         PackageSaver().render_package(pkg)
-        return render('package/read') 
+        return render('package/read.html') 
 
     def history(self, id):
         if 'diff' in request.params or 'selected1' in request.params:
             feed.content_type = 'application/atom+xml'
             return feed.writeString('utf-8')
         c.pkg_revisions = c.pkg.all_related_revisions
-        return render('package/history')
+        return render('package/history.html')
 
     def new(self):
         c.error = ''
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs, request.params,
                         clear_session=True)
-                return render('package/new')
+                return render('package/new.html')
             except KeyError, error:
                 abort(400, ('Missing parameter: %s' % error.args).encode('utf8'))
 
                 PackageSaver().render_preview(fs, id, record.id,
                                               log_message=log_message,
                                               author=c.author)
-                c.preview = h.literal(render('package/read_core'))
+                c.preview = h.literal(render('package/read_core.html'))
             except ValidationException, error:
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs, request.params,
                         clear_session=True)
-                return render('package/new')
-        return render('package/new')
+                return render('package/new.html')
+        return render('package/new.html')
 
     def edit(self, id=None): # allow id=None to allow posting
         # TODO: refactor to avoid duplication between here and new
                 self._adjust_license_id_options(pkg, fs)
             fs = fs.bind(pkg)
             c.form = self._render_edit_form(fs, request.params)
-            return render('package/edit')
+            return render('package/edit.html')
         elif request.params.has_key('commit'):
             # id is the name (pre-edited state)
             pkgname = id
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs, request.params,
                         clear_session=True)
-                return render('package/edit')
+                return render('package/edit.html')
             except KeyError, error:
                 abort(400, 'Missing parameter: %s' % error.args)
         else: # Must be preview
                 PackageSaver().render_preview(fs, id, pkg.id,
                                               log_message=log_message,
                                               author=c.author)
-                read_core_html = render('package/read_core') #utf8 format
+                read_core_html = render('package/read_core.html') #utf8 format
                 c.preview = h.literal(read_core_html)
                 c.form = self._render_edit_form(fs, request.params)
             except ValidationException, error:
                 fs = error.args[0]
                 c.form = self._render_edit_form(fs, request.params,
                         clear_session=True)
-                return render('package/edit')
-            return render('package/edit') # uses c.form and c.preview
+                return render('package/edit.html')
+            return render('package/edit.html') # uses c.form and c.preview
 
     def _adjust_license_id_options(self, pkg, fs):
         options = fs.license_id.render_opts['options']
             except ValidationException, error:
                 # TODO: sort this out 
                 # fs = error.args
-                # return render('package/authz')
+                # return render('package/authz.html')
                 raise
             # now do new roles
             newrole_user_id = request.params.get('PackageRole--user_id')
         fs = ckan.forms.get_authz_fieldset('package_authz_fs').bind(c.pkg.roles)
         c.form = fs.render()
         c.new_roles_form = ckan.forms.get_authz_fieldset('new_package_roles_fs').render()
-        return render('package/authz')
+        return render('package/authz.html')
 
     def rate(self, id):
         package_name = id
             model.Session.clear()
         edit_form_html = fs.render()
         c.form = h.literal(edit_form_html)
-        return h.literal(render('package/edit_form'))
+        return h.literal(render('package/edit_form.html'))
 
     def _update_authz(self, fs):
         validation = fs.validate()

ckan/controllers/rest.py

 class BaseRestController(BaseController):
 
     def index(self):
-        return render('rest/index')
+        return render('rest/index.html')
 
     def _list_package_refs(self, packages):
         raise Exception, "Method not implemented."

ckan/controllers/rest2.py

File contents unchanged.

ckan/controllers/revision.py

                 items_per_page=50
             )
             
-            return render('revision/list')
+            return render('revision/list.html')
 
     def read(self, id=None):
         if id is None:
         c.packages = [ pkg.continuity for pkg in pkgs ]
         pkgtags = model.Session.query(model.PackageTagRevision).filter_by(revision=c.revision)
         c.pkgtags = [ pkgtag.continuity for pkgtag in pkgtags ]
-        return render('revision/read')
+        return render('revision/read.html')
 
     def diff(self, id=None):
         if 'diff' not in request.params or 'oldid' not in request.params:
         c.diff = diff.items()
         c.diff.sort()
         c.pkg = pkg
-        return render('revision/diff')
+        return render('revision/diff.html')
 
     def _has_purge_permissions(self):
         authorizer = ckan.authz.Authorizer()
     def purge(self, id=None):
         if id is None:
             c.error = _('No revision id specified')
-            return render('revision/purge')
+            return render('revision/purge.html')
         if not self._has_purge_permissions():
             c.error = _('You are not authorized to perform this action')
-            return render('revision/purge')
+            return render('revision/purge.html')
         else:
             revision = model.Session.query(model.Revision).get(id)
             try:
                 # is this a security risk?
                 # probably not because only admins get to here
                 c.error = _('Purge of revision failed: %s') % inst
-            return render('revision/purge')
+            return render('revision/purge.html')
 

ckan/controllers/tag.py

             items_per_page=100
         )
            
-        return render('tag/index')
+        return render('tag/index.html')
 
     def read(self, id):
         c.tag = model.Tag.by_name(id)
         if c.tag is None:
             abort(404)
-        return render('tag/read')
+        return render('tag/read.html')
 
     def autocomplete(self):
         incomplete = request.params.get('incomplete', '')

ckan/controllers/user.py

 from ckan.lib.base import *
 
 def login_form():
-    return render('user/login_form').replace('FORM_ACTION', '%s')
+    return render('user/login_form.html').replace('FORM_ACTION', '%s')
 
 class UserController(BaseController):
 
         c.num_edits = revisions_q.count()
         c.num_pkg_admin = model.Session.query(model.PackageRole).filter_by(user=user, role=model.Role.ADMIN).count()
         c.activity = revisions_q.limit(20).all()
-        return render('user/read')
+        return render('user/read.html')
 
     def login(self):
         if c.user:
                 model.Session.commit()
             h.redirect_to(controller='user', action=None, id=None)
         else:
-            form = render('user/openid_form')
+            form = render('user/openid_form.html')
             # /login_openid page need not exist -- request gets intercepted by openid plugin
             form = form.replace('FORM_ACTION', '/login_openid')
             return form
 
     def logout(self):
         c.user = None
-        return render('user/logout')
+        return render('user/logout.html')
 
     def apikey(self):
         # logged in
         else:
             user = model.User.by_name(c.user)
             c.api_key = user.apikey
-        return render('user/apikey')
+        return render('user/apikey.html')
 
     def edit(self):
         # logged in
                 model.Session.commit()
             h.redirect_to(controller='user', action='read', id=user.id)
             
-        return render('user/edit')
+        return render('user/edit.html')
         
     def _format_about(self, about):
         about_formatted = ckan.misc.MarkdownFormat().to_html(about)

ckan/forms/builder.py

 import formalchemy
-from pylons.templating import render
+from pylons.templating import render_genshi as render
 from pylons import c
 
 from ckan import model
         self.added_fields = []
         self.options = self.fs._fields # {field_name:fs.field}
         self.includes = None
-        self.set_form_template('package/form')
+        self.set_form_template('package/form.html')
 
     def add_field(self, field):
         if isinstance(field, common.ConfiguredField):

ckan/forms/common.py

 from formalchemy import helpers as fa_h
 import formalchemy
 import genshi
-from pylons.templating import render
+from pylons.templating import render_genshi as render
 from pylons import c
 from pylons.i18n import _, ungettext, N_, gettext
 
             c.resources = c.resources[:]
             c.resources.extend([None])
             c.id = self.name
-            return render('package/form_resources')            
+            return render('package/form_resources.html')            
 
         def stringify_value(self, v):
             # actually returns dict here for _value
                 field_values.append({
                     'name':'%s-newfield%s' % (self.name, i)})
             c.fields = field_values
-            html = render('package/form_extra_fields')
+            html = render('package/form_extra_fields.html')
             return h.literal(html)
 
         def render_readonly(self, **kwargs):

ckan/lib/app_globals.py

 """The application's Globals object"""
-from pylons import config
 
 class Globals(object):
+
     """Globals acts as a container for objects available throughout the
     life of the application
+
     """
 
     def __init__(self):
         """One instance of Globals is created during application
-        initialization and is available during requests via the 'g'
-        variable
+        initialization and is available during requests via the
+        'app_globals' variable
+
         """
-        pass
 """The base Controller API
 
-Provides the BaseController class for subclassing, and other objects
-utilized by Controllers.
+Provides the BaseController class for subclassing.
 """
 import logging
 
 from pylons.controllers.util import abort, etag_cache, redirect_to, redirect
 from pylons.decorators import jsonify, validate
 from pylons.i18n import _, ungettext, N_, gettext
-from pylons.templating import render
+from pylons.templating import render_genshi as render
 
 import ckan
 import ckan.lib.helpers as h

ckan/templates/group/authz.html

     <form action="" method="post">
       <h3>Update Existing Roles</h3>
       <table>
-      ${HTML(c.form)}
+      ${h.literal(c.form)}
       </table>
 
       <h3>Create New User Roles</h3>
-      ${HTML(c.new_roles_form)}
+      ${h.literal(c.new_roles_form)}
         
       <br/>
 

ckan/templates/package/authz.html

     <form action="" method="post">
       <h3>Update Existing Roles</h3>
       <table>
-      ${HTML(c.form)}
+      ${h.literal(c.form)}
       </table>
 
       <h3>Create New User Roles</h3>
-      ${HTML(c.new_roles_form)}
+      ${h.literal(c.new_roles_form)}
         
       <br/>
 

ckan/templates/revision/common.html

       <tr py:def="revision_row(item)">
         <td>
           ${
-            XML(
             h.link_to(item.id,
               h.url_for(
                 controller='revision',
                 action='read',
                 id=item.id)
               )
-            )
           }
           <py:if test="c.show_purge_links">
           ${
-            XML(
             h.link_to('Purge',
               h.url_for(
                 controller='revision',
                 id=item.id),
               confirm='Are you sure?'
               )
-            )
           }
           </py:if>
         </td>

ckan/templates/revision/read.html

     <ul>
       <py:for each="pkg in c.packages">
       <li>
-      ${XML(h.link_to(pkg.name, h.url_for(controller='package', action='read', id=pkg.name)))}
+      ${h.link_to(pkg.name, h.url_for(controller='package', action='read', id=pkg.name))}
       </li>
       </py:for>
     </ul>
     <ul>
       <py:for each="pkgtag in c.pkgtags">
       <li>
-      Package - ${XML(h.link_to(pkgtag.package.name, h.url_for(controller='package', action='read', id=pkgtag.package.name)))},
-      Tag - ${XML(h.link_to(pkgtag.tag.name, h.url_for(controller='tag', action='read', id=pkgtag.tag.name)))}
+      Package - ${h.link_to(pkgtag.package.name, h.url_for(controller='package', action='read', id=pkgtag.package.name))},
+      Tag - ${h.link_to(pkgtag.tag.name, h.url_for(controller='tag', action='read', id=pkgtag.tag.name))}
       </li>
       </py:for>
     </ul>

ckan/tests/forms/test_package.py

         anna = model.Package.by_name(u'annakarenina')
         fs = fs.bind(anna)
         out = fs.notes.render()
-        print out
 
     def test_2_name(self):
         fs = ckan.forms.get_standard_fieldset()
         anna = model.Package.by_name(u'annakarenina')
         fs = fs.bind(anna)
         out = fs.resources.render()
-        # out is str, but it contains unicode characters
-        out = unicode(out, 'utf8') # now it's unicode type
         out_printable = out.encode('utf8') # encoded utf8
         for res in anna.resources:
             assert escape(res.url) in out, out_printable

ckan/tests/functional/test_rest.py

         if not package2_name:
             offset = '/api/rest/package/%s/%s' % (str(package1_name), type)
         else:
-            offset = '/api/rest/package/%s/%s/%s/' % (
+            offset = '/api/rest/package/%s/%s/%s' % (
                 str(package1_name), type, str(package2_name))
         allowable_statuses = [200]
         if type:

ckan/tests/functional/test_rest2.py

File contents unchanged.

ckan/tests/functional/test_tag.py

 
     def test_read_moved(self):
         name = 'tolstoy'
-        offset = '/tag/read/%s/' % name
+        offset = '/tag/read/%s' % name
         res = self.app.get(offset, status=HTTP_MOVED_PERMANENTLY)
         res = res.follow()
         assert 'Tags - %s' % name in res
 """Setup the ckan application"""
 import logging
 
-from paste.deploy import appconfig
-from pylons import config
-
 from ckan.config.environment import load_environment
 
 log = logging.getLogger(__name__)
 
-def setup_config(command, filename, section, vars):
+def setup_app(command, conf, vars):
     """Place any commands to setup ckan here"""
-    conf = appconfig('config:' + filename)
     load_environment(conf.global_conf, conf.local_conf)
     
     from ckan import model
 [easy_install]
 find_links = http://www.pylonshq.com/download/
 
-[pudge]
-theme = pythonpaste.org
-
-# Add extra doc files here with spaces between them
-docs = docs/index.txt
-
-# Doc Settings
-doc_base = docs/
-dest = docs/html
-
-# Add extra modules here separated with commas
-modules = ckan
-title = Ckan
-organization = Pylons
-
-# Highlight code-block sections with Pygments
-highlighter = pygments
-
-# Optionally add extra links
-#organization_url = http://pylonshq.com/
-#trac_url = http://pylonshq.com/project
-settings = no_about=true
-
-# Optionally add extra settings
-#           link1=/community/ Community
-#           link2=/download/ Download
-
-[publish]
-doc-dir=docs/html
-make-dirs=1
+[nosetests]
+with-pylons = test.ini
 
 # Babel configuration
 [compile_catalog]