diff --git a/MANIFEST.in b/MANIFEST.in index a0348e0..c822c84 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ +include newpylonsapp/config/deployment.ini_tmpl recursive-include ddportfolioservice/public * recursive-include ddportfolioservice/templates * diff --git a/ddportfolioservice/config/__init__.py b/ddportfolioservice/config/__init__.py index 5d13c6e..cdcce52 100644 --- a/ddportfolioservice/config/__init__.py +++ b/ddportfolioservice/config/__init__.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service config package -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # diff --git a/ddportfolioservice/config/deployment.ini_tmpl b/ddportfolioservice/config/deployment.ini_tmpl new file mode 100644 index 0000000..29f9ab9 --- /dev/null +++ b/ddportfolioservice/config/deployment.ini_tmpl @@ -0,0 +1,60 @@ +# +# ddportfolioservice - Pylons configuration +# +# The %(here)s variable will be replaced with the parent directory of this file +# +[DEFAULT] +debug = true +email_to = you@yourdomain.com +smtp_server = localhost +error_email_from = paste@localhost + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 5000 + +[app:main] +use = egg:ddportfolioservice +full_stack = true +static_files = true + +cache_dir = %(here)s/data +beaker.session.key = ddportfolioservice +beaker.session.secret = ${app_instance_secret} +app_instance_uuid = ${app_instance_uuid} + +# If you'd like to fine-tune the individual locations of the cache data dirs +# for the Cache data, or the Session saves, un-comment the desired settings +# here: +#beaker.cache.data_dir = %(here)s/data/cache +#beaker.session.data_dir = %(here)s/data/sessions + +# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* +# Debug mode will enable the interactive debugging tool, allowing ANYONE to +# execute malicious code after an exception is raised. +set debug = false + + +# Logging configuration +[loggers] +keys = root + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s diff --git a/ddportfolioservice/config/environment.py b/ddportfolioservice/config/environment.py index 4f4b8dc..a1fe3ba 100644 --- a/ddportfolioservice/config/environment.py +++ b/ddportfolioservice/config/environment.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service environment configuration -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -23,7 +23,9 @@ """Pylons environment configuration""" import os -from pylons import config +from mako.lookup import TemplateLookup +from pylons.configuration import PylonsConfig +from pylons.error import handle_mako_error import ddportfolioservice.lib.app_globals as app_globals import ddportfolioservice.lib.helpers @@ -33,6 +35,8 @@ def load_environment(global_conf, app_conf): """Configure the Pylons environment via the ``pylons.config`` object """ + config = PylonsConfig() + # Pylons paths root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) paths = dict(root=root, @@ -41,15 +45,26 @@ def load_environment(global_conf, app_conf): templates=[os.path.join(root, 'templates')]) # Initialize config with the basic options - config.init_app(global_conf, app_conf, package='ddportfolioservice', - template_engine='mako', paths=paths) + config.init_app(global_conf, app_conf, package='ddportfolioservice', paths=paths) - config['routes.map'] = make_map() - config['pylons.g'] = app_globals.Globals() + config['routes.map'] = make_map(config) + config['pylons.app_globals'] = app_globals.Globals(config) config['pylons.h'] = ddportfolioservice.lib.helpers - # Customize templating options via this variable - tmpl_options = config['buffet.template_options'] + # Setup cache object as early as possible + import pylons + pylons.cache._push_object(config['pylons.app_globals'].cache) + + + # Create the Mako TemplateLookup, with the default auto-escaping + config['pylons.app_globals'].mako_lookup = TemplateLookup( + directories=paths['templates'], + error_handler=handle_mako_error, + module_directory=os.path.join(app_conf['cache_dir'], 'templates'), + input_encoding='utf-8', default_filters=['escape'], + imports=['from webhelpers.html import escape']) # CONFIGURATION OPTIONS HERE (note: all config options will override # any Pylons config options) + + return config diff --git a/ddportfolioservice/config/middleware.py b/ddportfolioservice/config/middleware.py index 4cc9378..6e87b2d 100644 --- a/ddportfolioservice/config/middleware.py +++ b/ddportfolioservice/config/middleware.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service middleware configuration -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -21,20 +21,18 @@ # . # """Pylons middleware initialization""" +from beaker.middleware import 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 error_mapper, ErrorDocuments, ErrorHandler, \ - StaticJavascripts +from pylons.middleware import ErrorHandler, StatusCodeRedirect from pylons.wsgiapp import PylonsApp +from routes.middleware import RoutesMiddleware from ddportfolioservice.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`` @@ -42,38 +40,50 @@ def make_app(global_conf, full_stack=True, **app_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:] section of the Paste ini file (where + The application's local configuration. Normally specified in + the [app:] section of the Paste ini file (where defaults to main). + """ # Configure the Pylons environment - load_environment(global_conf, app_conf) + config = load_environment(global_conf, app_conf) # The Pylons WSGI app - app = PylonsApp() + app = PylonsApp(config=config) + + # Routing/Session/Cache Middleware + app = RoutesMiddleware(app, config['routes.map']) + app = SessionMiddleware(app, config) # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares) if asbool(full_stack): # Handle Python exceptions - app = ErrorHandler(app, global_conf, error_template=error_template, - **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) - app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf) + if asbool(config['debug']): + app = StatusCodeRedirect(app) + else: + app = StatusCodeRedirect(app, [400, 401, 403, 404, 500]) # Establish the Registry for this application app = RegistryManager(app) - # Static files - javascripts_app = StaticJavascripts() - static_app = StaticURLParser(config['pylons.paths']['static_files']) - app = Cascade([static_app, javascripts_app, app]) + if asbool(static_files): + # Serve static files + static_app = StaticURLParser(config['pylons.paths']['static_files']) + app = Cascade([static_app, app]) + app.config = config return app diff --git a/ddportfolioservice/config/routing.py b/ddportfolioservice/config/routing.py index 3d116d4..d197181 100644 --- a/ddportfolioservice/config/routing.py +++ b/ddportfolioservice/config/routing.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service routing configuration -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -26,24 +26,26 @@ The more specific and detailed routes should be defined first so they may take precedent over the more generic routes. For more information refer to the routes manual at http://routes.groovie.org/docs/ """ -from pylons import config from routes import Mapper -def make_map(): +def make_map(config): """Create, configure and return the routes Mapper""" map = Mapper(directory=config['pylons.paths']['controllers'], - always_scan=config['debug']) + always_scan=config['debug'], explicit=True) + 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('', controller='ddportfolio', action='index') - map.connect('result', controller='ddportfolio', action='urllist') - map.connect('htmlformhelper.js', controller='showformscripts', + map.connect('/', controller='ddportfolio', action='index') + map.connect('/result', controller='ddportfolio', action='urllist') + map.connect('/htmlformhelper.js', controller='showformscripts', action='index') - map.connect(':controller/:action/:id') - map.connect('*url', controller='template', action='view') + + map.connect('/{controller}/{action}') + map.connect('/{controller}/{action}/{id}') return map diff --git a/ddportfolioservice/lib/__init__.py b/ddportfolioservice/lib/__init__.py index 9017306..ac207b6 100644 --- a/ddportfolioservice/lib/__init__.py +++ b/ddportfolioservice/lib/__init__.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service lib package -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # diff --git a/ddportfolioservice/lib/app_globals.py b/ddportfolioservice/lib/app_globals.py index 7969caa..e66df3d 100644 --- a/ddportfolioservice/lib/app_globals.py +++ b/ddportfolioservice/lib/app_globals.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service application Globals -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -21,16 +21,21 @@ # . # """The application's Globals object""" -from pylons import config + +from beaker.cache import CacheManager +from beaker.util import parse_cache_config_options class Globals(object): + """Globals acts as a container for objects available throughout the life of the application + """ - def __init__(self): + def __init__(self, config): """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 + self.cache = CacheManager(**parse_cache_config_options(config)) diff --git a/ddportfolioservice/lib/base.py b/ddportfolioservice/lib/base.py index 9dc819c..24d0cc4 100644 --- a/ddportfolioservice/lib/base.py +++ b/ddportfolioservice/lib/base.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service base controller -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -22,18 +22,12 @@ # """The base Controller API -Provides the BaseController class for subclassing, and other objects -utilized by Controllers. +Provides the BaseController class for subclassing. """ -from pylons import c, cache, config, g, request, response, session +from pylons import tmpl_context as c, request from pylons.controllers import WSGIController -from pylons.controllers.util import abort, etag_cache, redirect_to -from pylons.decorators import jsonify, validate -from pylons.i18n import _, ungettext, N_, add_fallback -from pylons.templating import render - -import ddportfolioservice.lib.helpers as h -import ddportfolioservice.model as model +from pylons.i18n import add_fallback +from pylons.templating import render_mako as render class BaseController(WSGIController): @@ -50,7 +44,3 @@ class BaseController(WSGIController): pass c.messages = { 'errors': [], 'messages': [] } return WSGIController.__call__(self, environ, start_response) - -# Include the '_' function in the public names -__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \ - or __name == '_'] diff --git a/ddportfolioservice/lib/helpers.py b/ddportfolioservice/lib/helpers.py index bf113c2..24170e9 100644 --- a/ddportfolioservice/lib/helpers.py +++ b/ddportfolioservice/lib/helpers.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service webhelpers -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -23,11 +23,6 @@ """Helper functions Consists of functions to typically be used within templates, but also -available to Controllers. This module is available to both as 'h'. +available to Controllers. This module is available to templates as 'h'. """ -from webhelpers import * -from webhelpers.html.tags import * from webhelpers.html.builder import escape -from webhelpers.text import * -from webhelpers.textile import * -from routes.util import * diff --git a/development.ini b/development.ini index 0a2cd4e..ffa4c63 100644 --- a/development.ini +++ b/development.ini @@ -12,12 +12,14 @@ error_email_from = paste@localhost [server:main] use = egg:Paste#http -host = 0.0.0.0 +host = 127.0.0.1 port = 5000 [app:main] use = egg:ddportfolioservice full_stack = true +static_files = true + cache_dir = %(here)s/data beaker.session.key = ddportfolioservice beaker.session.secret = somesecret @@ -36,7 +38,7 @@ beaker.session.secret = somesecret # Logging configuration [loggers] -keys = root, ddportfolioservice +keys = root, routes, ddportfolioservice [handlers] keys = console @@ -48,6 +50,12 @@ keys = generic level = INFO handlers = console +[logger_routes] +level = INFO +handlers = +qualname = routes.middleware +# "level = DEBUG" logs the route matched and routing variables. + [logger_ddportfolioservice] level = DEBUG handlers = @@ -60,5 +68,5 @@ level = NOTSET formatter = generic [formatter_generic] -format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s +format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s datefmt = %H:%M:%S diff --git a/setup.cfg b/setup.cfg index 5c5ebdd..390771c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,6 +12,9 @@ source-dir = docs doc-dir=docs/html make-dirs=1 +[nosetests] +with-pylons = test.ini + # Babel configuration [compile_catalog] domain = ddportfolioservice diff --git a/setup.py b/setup.py index 58aeb28..0c26b1f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # DDPortfolio service setup -# Copyright (c) 2009 Jan Dittberner +# Copyright © 2009, 2010 Jan Dittberner # # This file is part of DDPortfolio service. # @@ -29,7 +29,7 @@ except ImportError: setup( name='ddportfolioservice', - version='0.1', + version='0.2', description='service to create DDPortfolio URLs', long_description="""This is a service implementation that returns a set of personalized URLs as outlined in @@ -48,7 +48,7 @@ array of URLs.""", author_email='jan@dittberner.info', url='http://debian-stuff.dittberner.info/ddportfolioservice', license='AGPL-3.0+', - install_requires=["Pylons>=0.9.6.2"], + install_requires=["Pylons>=0.10rc1"], packages=find_packages(exclude=['ez_setup']), include_package_data=True, test_suite='nose.collector', @@ -57,6 +57,7 @@ array of URLs.""", ('**.py', 'python', None), ('templates/**.mako', 'mako', None), ('public/**', 'ignore', None)]}, + zip_safe=False, entry_points=""" [paste.app_factory] main = ddportfolioservice.config.middleware:make_app diff --git a/test.ini b/test.ini index 6f3a54e..940a578 100644 --- a/test.ini +++ b/test.ini @@ -12,7 +12,7 @@ error_email_from = paste@localhost [server:main] use = egg:Paste#http -host = 0.0.0.0 +host = 127.0.0.1 port = 5000 [app:main]