Hello community, here is the log from the commit of package python-pecan for openSUSE:Factory checked in at 2013-08-15 12:28:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pecan (Old) and /work/SRC/openSUSE:Factory/.python-pecan.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pecan" Changes: -------- --- /work/SRC/openSUSE:Factory/python-pecan/python-pecan.changes 2013-06-29 14:33:23.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python-pecan.new/python-pecan.changes 2013-08-15 12:28:53.000000000 +0200 @@ -1,0 +2,9 @@ +Tue Aug 13 10:10:55 UTC 2013 - dmuel...@suse.com + +- update to 0.3.2: + * Made some changes to simplify how ``pecan.conf.app`` is passed to new apps. + * Fixed a routing bug for certain ``_lookup`` controller configurations. + * Improved documentation for handling file uploads. + * Deprecated the ``pecan.conf.requestviewer`` configuration option. + +------------------------------------------------------------------- Old: ---- pecan-0.3.0.tar.gz New: ---- pecan-0.3.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pecan.spec ++++++ --- /var/tmp/diff_new_pack.MGUceP/_old 2013-08-15 12:28:53.000000000 +0200 +++ /var/tmp/diff_new_pack.MGUceP/_new 2013-08-15 12:28:53.000000000 +0200 @@ -17,7 +17,7 @@ Name: python-pecan -Version: 0.3.0 +Version: 0.3.2 Release: 0 Summary: A WSGI object-dispatching web framework, designed to be lean and fast License: BSD-3-Clause @@ -25,7 +25,7 @@ Url: http://github.com/dreamhost/pecan Source: http://pypi.python.org/packages/source/p/pecan/pecan-%{version}.tar.gz BuildRequires: python-devel -BuildRequires: python-distribute +BuildRequires: python-setuptools # Test requirements: #BuildRequires: python-Genshi #BuildRequires: python-Jinja2 ++++++ pecan-0.3.0.tar.gz -> pecan-0.3.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/PKG-INFO new/pecan-0.3.2/PKG-INFO --- old/pecan-0.3.0/PKG-INFO 2013-05-08 20:33:53.000000000 +0200 +++ new/pecan-0.3.2/PKG-INFO 2013-08-12 23:42:59.000000000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: pecan -Version: 0.3.0 +Version: 0.3.2 Summary: A WSGI object-dispatching web framework, designed to be lean and fast, with few dependancies. Home-page: http://github.com/dreamhost/pecan Author: Jonathan LaCour diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/README.rst new/pecan-0.3.2/README.rst --- old/pecan-0.3.0/README.rst 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/README.rst 2013-08-12 22:49:47.000000000 +0200 @@ -7,6 +7,10 @@ .. _travis: http://travis-ci.org/dreamhost/pecan .. |travis| image:: https://secure.travis-ci.org/dreamhost/pecan.png +.. image:: https://pypip.in/v/pecan/badge.png + :target: https://crate.io/packages/pecan/ + :alt: Latest PyPI version + |travis|_ Installing @@ -46,5 +50,6 @@ Additional Help/Support ----------------------- -Most Pecan interaction is done via the #pecanpy channel on `FreeNode -<http://freenode.net/>`_ IRC. +Most Pecan interaction is done via the `pecan-dev Mailing List +<https://groups.google.com/forum/#!forum/pecan-dev>`_ and the #pecanpy channel +on `FreeNode <http://freenode.net/>`_ IRC. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/__init__.py new/pecan-0.3.2/pecan/__init__.py --- old/pecan-0.3.0/pecan/__init__.py 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/__init__.py 2013-08-12 22:49:47.000000000 +0200 @@ -17,6 +17,8 @@ except ImportError: from logutils.dictconfig import dictConfig as load_logging_config # noqa +import warnings + __all__ = [ 'make_app', 'load_app', 'Pecan', 'request', 'response', @@ -25,8 +27,7 @@ ] -def make_app(root, static_root=None, logging={}, debug=False, - wrap_app=None, **kw): +def make_app(root, **kw): ''' Utility for creating the Pecan application object. This function should generally be called from the ``setup_app`` function in your project's @@ -37,8 +38,6 @@ :param static_root: The relative path to a directory containing static files. Serving static files is only enabled when debug mode is set. - :param logging: A dictionary used to configure logging. This uses - ``logging.config.dictConfig``. :param debug: A flag to enable debug mode. This enables the debug middleware and serving static files. :param wrap_app: A function or middleware class to wrap the Pecan app. @@ -49,19 +48,31 @@ This should be used if you want to use middleware to perform authentication or intercept all requests before they are routed to the root controller. + :param logging: A dictionary used to configure logging. This uses + ``logging.config.dictConfig``. All other keyword arguments are passed in to the Pecan app constructor. :returns: a ``Pecan`` object. ''' - # A shortcut for the RequestViewerHook middleware. - if hasattr(conf, 'requestviewer'): - existing_hooks = kw.get('hooks', []) - existing_hooks.append(RequestViewerHook(conf.requestviewer)) - kw['hooks'] = existing_hooks - # Pass logging configuration (if it exists) on to the Python logging module + logging = kw.get('logging', {}) + debug = kw.get('debug', False) if logging: + if debug: + try: + # + # By default, Python 2.7+ silences DeprecationWarnings. + # However, if conf.app.debug is True, we should probably ensure + # that users see these types of warnings. + # + from logging import captureWarnings + captureWarnings(True) + warnings.simplefilter("default", DeprecationWarning) + except ImportError: + # No captureWarnings on Python 2.6, DeprecationWarnings are on + pass + if isinstance(logging, Config): logging = logging.to_dict() if 'version' not in logging: @@ -72,28 +83,40 @@ app = Pecan(root, **kw) # Optionally wrap the app in another WSGI app + wrap_app = kw.get('wrap_app', None) if wrap_app: app = wrap_app(app) # Configuration for serving custom error messages - if hasattr(conf.app, 'errors'): - app = ErrorDocumentMiddleware(app, conf.app.errors) + errors = kw.get('errors', getattr(conf.app, 'errors', {})) + if errors: + app = ErrorDocumentMiddleware(app, errors) # Included for internal redirect support app = RecursiveMiddleware(app) # When in debug mode, load our exception dumping middleware + static_root = kw.get('static_root', None) if debug: app = DebugMiddleware(app) # Support for serving static files (for development convenience) if static_root: app = StaticFileMiddleware(app, static_root) + elif static_root: - from warnings import warn - warn( + warnings.warn( "`static_root` is only used when `debug` is True, ignoring", RuntimeWarning ) + if hasattr(conf, 'requestviewer'): + warnings.warn(''.join([ + "`pecan.conf.requestviewer` is deprecated. To apply the ", + "`RequestViewerHook` to your application, add it to ", + "`pecan.conf.app.hooks` or manually in your project's `app.py` ", + "file."]), + DeprecationWarning + ) + return app diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/core.py new/pecan-0.3.2/pecan/core.py --- old/pecan-0.3.0/pecan/core.py 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/core.py 2013-08-12 22:49:47.000000000 +0200 @@ -173,11 +173,12 @@ :param root: A string representing a root controller object (e.g., "myapp.controller.root.RootController") - :param default_renderer: The default rendering engine to use. Defaults - to mako. - :param template_path: The default relative path to use for templates. - Defaults to 'templates'. - :param hooks: A list of Pecan hook objects to use for this application. + :param default_renderer: The default template rendering engine to use. + Defaults to mako. + :param template_path: A relative file system path (from the project root) + where template files live. Defaults to 'templates'. + :param hooks: A callable which returns a list of + :class:`pecan.hooks.PecanHook`s :param custom_renderers: Custom renderer objects, as a dictionary keyed by engine name. :param extra_template_vars: Any variables to inject into the template @@ -195,9 +196,9 @@ ) def __init__(self, root, default_renderer='mako', - template_path='templates', hooks=[], custom_renderers={}, - extra_template_vars={}, force_canonical=True, - guess_content_type_from_ext=True): + template_path='templates', hooks=lambda: [], + custom_renderers={}, extra_template_vars={}, + force_canonical=True, guess_content_type_from_ext=True, **kw): if isinstance(root, six.string_types): root = self.__translate_root__(root) @@ -205,7 +206,11 @@ self.root = root self.renderers = RendererFactory(custom_renderers, extra_template_vars) self.default_renderer = default_renderer + # pre-sort these so we don't have to do it per-request + if six.callable(hooks): + hooks = hooks() + self.hooks = list(sorted( hooks, key=operator.attrgetter('priority') @@ -299,7 +304,11 @@ hooks = reversed(state.hooks) for hook in hooks: - getattr(hook, hook_type)(*args) + result = getattr(hook, hook_type)(*args) + # on_error hooks can choose to return a Response, which will + # be used instead of the standard error pages. + if hook_type == 'on_error' and isinstance(result, Response): + return result def get_args(self, req, all_params, remainder, argspec, im_self): ''' @@ -564,11 +573,16 @@ environ['pecan.original_exception'] = e # if this is not an internal redirect, run error hooks + on_error_result = None if not isinstance(e, ForwardRequestException): - self.handle_hooks('on_error', state, e) + on_error_result = self.handle_hooks('on_error', state, e) - if not isinstance(e, exc.HTTPException): - raise + # if the on_error handler returned a Response, use it. + if isinstance(on_error_result, Response): + state.response = on_error_result + else: + if not isinstance(e, exc.HTTPException): + raise finally: # handle "after" hooks self.handle_hooks('after', state) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/routing.py new/pecan-0.3.2/pecan/routing.py --- old/pecan-0.3.0/pecan/routing.py 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/routing.py 2013-08-12 22:49:47.000000000 +0200 @@ -46,6 +46,13 @@ # traversal result = handle_lookup_traversal(obj, remainder) if result: + # If no arguments are passed to the _lookup, yet the + # argspec requires at least one, raise a 404 + if ( + remainder == [''] + and len(obj._pecan['argspec'].args) > 1 + ): + raise return lookup_controller(*result) else: raise exc.HTTPNotFound diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/scaffolds/base/+package+/app.py_tmpl new/pecan-0.3.2/pecan/scaffolds/base/+package+/app.py_tmpl --- old/pecan-0.3.0/pecan/scaffolds/base/+package+/app.py_tmpl 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/scaffolds/base/+package+/app.py_tmpl 2013-08-12 22:49:47.000000000 +0200 @@ -5,16 +5,10 @@ def setup_app(config): model.init_model() + app_conf = dict(config.app) return make_app( - config.app.root, - static_root=config.app.static_root, - template_path=config.app.template_path, + app_conf.pop('root'), logging=getattr(config, 'logging', {}), - debug=getattr(config.app, 'debug', False), - force_canonical=getattr(config.app, 'force_canonical', True), - guess_content_type_from_ext=getattr( - config.app, - 'guess_content_type_from_ext', - True), + **app_conf ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/scaffolds/base/config.py_tmpl new/pecan-0.3.2/pecan/scaffolds/base/config.py_tmpl --- old/pecan-0.3.0/pecan/scaffolds/base/config.py_tmpl 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/scaffolds/base/config.py_tmpl 2013-08-12 22:49:47.000000000 +0200 @@ -20,7 +20,9 @@ logging = { 'loggers': { 'root': {'level': 'INFO', 'handlers': ['console']}, - '${package}': {'level': 'DEBUG', 'handlers': ['console']} + '${package}': {'level': 'DEBUG', 'handlers': ['console']}, + 'py.warnings': {'handlers': ['console']}, + '__force_dict__': True }, 'handlers': { 'console': { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/tests/test_base.py new/pecan-0.3.2/pecan/tests/test_base.py --- old/pecan-0.3.0/pecan/tests/test_base.py 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/tests/test_base.py 2013-08-12 22:49:47.000000000 +0200 @@ -182,6 +182,35 @@ assert r.status_int == 404 +class TestCanonicalLookups(PecanTestCase): + + @property + def app_(self): + class LookupController(object): + def __init__(self, someID): + self.someID = someID + + @expose() + def index(self): + return self.someID + + class UserController(object): + @expose() + def _lookup(self, someID, *remainder): + return LookupController(someID), remainder + + class RootController(object): + users = UserController() + + return TestApp(Pecan(RootController())) + + def test_canonical_lookup(self): + assert self.app_.get('/users', expect_errors=404).status_int == 404 + assert self.app_.get('/users/', expect_errors=404).status_int == 404 + assert self.app_.get('/users/100').status_int == 302 + assert self.app_.get('/users/100/').body == b_('100') + + class TestControllerArguments(PecanTestCase): @property diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan/tests/test_hooks.py new/pecan-0.3.2/pecan/tests/test_hooks.py --- old/pecan-0.3.0/pecan/tests/test_hooks.py 2013-05-07 20:13:05.000000000 +0200 +++ new/pecan-0.3.2/pecan/tests/test_hooks.py 2013-08-12 22:49:47.000000000 +0200 @@ -1,7 +1,10 @@ from webtest import TestApp from six import b as b_ +from six import u as u_ from six.moves import cStringIO as StringIO +from webob import Response + from pecan import make_app, expose, redirect, abort from pecan.hooks import ( PecanHook, TransactionHook, HookController, RequestViewerHook @@ -133,6 +136,33 @@ assert run_hook[0] == 'on_route' assert run_hook[1] == 'error' + def test_on_error_response_hook(self): + run_hook = [] + + class RootController(object): + @expose() + def causeerror(self): + return [][1] + + class ErrorHook(PecanHook): + def on_error(self, state, e): + run_hook.append('error') + + r = Response() + r.text = u_('on_error') + + return r + + app = TestApp(make_app(RootController(), hooks=[ + ErrorHook() + ])) + + response = app.get('/causeerror') + + assert len(run_hook) == 1 + assert run_hook[0] == 'error' + assert response.text == 'on_error' + def test_prioritized_hooks(self): run_hook = [] @@ -1017,21 +1047,6 @@ class TestRequestViewerHook(PecanTestCase): - def test_hook_from_config(self): - from pecan.configuration import _runtime_conf as conf - conf['requestviewer'] = { - 'blacklist': ['/favicon.ico'] - } - - class RootController(object): - pass - - app = make_app(RootController()) - while hasattr(app, 'application'): - app = app.application - del conf.__values__['requestviewer'] - assert app.hooks - def test_basic_single_default_hook(self): _stdout = StringIO() @@ -1043,7 +1058,9 @@ app = TestApp( make_app( - RootController(), hooks=[RequestViewerHook(writer=_stdout)] + RootController(), hooks=lambda: [ + RequestViewerHook(writer=_stdout) + ] ) ) response = app.get('/') @@ -1074,7 +1091,9 @@ app = TestApp( make_app( - RootController(), hooks=[RequestViewerHook(writer=_stdout)] + RootController(), hooks=lambda: [ + RequestViewerHook(writer=_stdout) + ] ) ) response = app.get('/404', expect_errors=True) @@ -1104,7 +1123,7 @@ app = TestApp( make_app( RootController(), - hooks=[ + hooks=lambda: [ RequestViewerHook( config={'items': ['path']}, writer=_stdout ) @@ -1139,7 +1158,7 @@ app = TestApp( make_app( RootController(), - hooks=[ + hooks=lambda: [ RequestViewerHook( config={'blacklist': ['/']}, writer=_stdout ) @@ -1166,7 +1185,7 @@ app = TestApp( make_app( RootController(), - hooks=[ + hooks=lambda: [ RequestViewerHook( config={'items': ['date']}, writer=_stdout ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/pecan.egg-info/PKG-INFO new/pecan-0.3.2/pecan.egg-info/PKG-INFO --- old/pecan-0.3.0/pecan.egg-info/PKG-INFO 2013-05-08 20:33:52.000000000 +0200 +++ new/pecan-0.3.2/pecan.egg-info/PKG-INFO 2013-08-12 23:42:58.000000000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: pecan -Version: 0.3.0 +Version: 0.3.2 Summary: A WSGI object-dispatching web framework, designed to be lean and fast, with few dependancies. Home-page: http://github.com/dreamhost/pecan Author: Jonathan LaCour diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pecan-0.3.0/setup.py new/pecan-0.3.2/setup.py --- old/pecan-0.3.0/setup.py 2013-05-08 20:05:13.000000000 +0200 +++ new/pecan-0.3.2/setup.py 2013-08-12 22:49:47.000000000 +0200 @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -version = '0.3.0' +version = '0.3.2' # # determine requirements @@ -43,7 +43,6 @@ tests_require = requirements + [ 'virtualenv', - 'Jinja2', 'gunicorn', 'mock' ] @@ -58,6 +57,9 @@ # Genshi added Python3 support in 0.7 tests_require += ['Genshi>=0.7'] +if sys.version_info < (3, 0) or sys.version_info >= (3, 3): + tests_require += ['Jinja2'] + # # call setup # -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org