diff options
| -rw-r--r-- | CHANGES.txt | 10 | ||||
| -rw-r--r-- | TODO.txt | 10 | ||||
| -rw-r--r-- | docs/api/request.rst | 7 | ||||
| -rw-r--r-- | docs/designdefense.rst | 9 | ||||
| -rw-r--r-- | docs/whatsnew-1.1.rst | 10 | ||||
| -rw-r--r-- | pyramid/config.py | 22 | ||||
| -rw-r--r-- | pyramid/request.py | 7 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 5 | ||||
| -rw-r--r-- | pyramid/tests/test_request.py | 20 | ||||
| -rw-r--r-- | pyramid/tests/venusianapp/__init__.py | 14 |
10 files changed, 107 insertions, 7 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 67163d3e7..041ff0bb7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,16 @@ Next release Features -------- +- The ``config.scan`` method has grown a ``**kw`` argument. ``kw`` argument + represents a set of keyword arguments to pass to the Venusian ``Scanner`` + object created by Pyramid. (See the Venusian documentation for more + information about ``Scanner``). + +- New request attribute: ``json``. If the request's ``content_type`` is + ``application/json``, this attribute will contain the JSON-decoded + variant of the request body. If the request's ``content_type`` is not + ``application/json``, this attribute will be ``None``. + - A new value ``http_cache`` can be used as a view configuration parameter. @@ -6,6 +6,16 @@ Must-Have - Github issues fixes. +- add_route discriminator wrong + +- tutorial models.initialize_sql doesn't match scaffold + (DBSession.rollback()/transaction.abort() in scaffold vs. "pass" in + tutorial) + +- Allow views to override http_cache headers. + +- request.JSON dictionary? + Should-Have ----------- diff --git a/docs/api/request.rst b/docs/api/request.rst index 27ce395ac..5dfb2ae9a 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -180,6 +180,13 @@ object (exposed to view code as ``request.response``) to influence rendered response behavior. + .. attribute:: json + + If the request's ``content_type`` is ``application/json``, this + attribute will contain the JSON-decoded variant of the request body. + If the request's ``content_type`` is not ``application/json``, this + attribute will be ``None``. + .. note:: For information about the API of a :term:`multidict` structure (such as diff --git a/docs/designdefense.rst b/docs/designdefense.rst index ce3c507c5..b285524c6 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1125,10 +1125,11 @@ Self-described "microframeworks" exist: `Bottle <http://bottle.paws.de>`_ and <http://bobo.digicool.com/>`_ doesn't describe itself as a microframework, but its intended userbase is much the same. Many others exist. We've actually even (only as a teaching tool, not as any sort of official project) -`created one using BFG <http://bfg.repoze.org/videos#groundhog1>`_ (the -precursor to Pyramid). Microframeworks are small frameworks with one common -feature: each allows its users to create a fully functional application that -lives in a single Python file. +`created one using Pyramid <http://bfg.repoze.org/videos#groundhog1>`_ (the +videos use BFG, a precursor to Pyramid, but the resulting code is `available +for Pyramid too <http://github.com/Pylons/groundhog>`_). Microframeworks are +small frameworks with one common feature: each allows its users to create a +fully functional application that lives in a single Python file. Some developers and microframework authors point out that Pyramid's "hello world" single-file program is longer (by about five lines) than the diff --git a/docs/whatsnew-1.1.rst b/docs/whatsnew-1.1.rst index 783f2caaa..a6bb8e99d 100644 --- a/docs/whatsnew-1.1.rst +++ b/docs/whatsnew-1.1.rst @@ -94,6 +94,16 @@ Default HTTP Exception View Minor Feature Additions ----------------------- +- The :meth:`pyramid.config.Configurator.scan` method has grown a ``**kw`` + argument. ``kw`` argument represents a set of keyword arguments to pass to + the Venusian ``Scanner`` object created by Pyramid. (See the + :term:`Venusian` documentation for more information about ``Scanner``). + +- New request attribute: ``json``. If the request's ``content_type`` is + ``application/json``, this attribute will contain the JSON-decoded + variant of the request body. If the request's ``content_type`` is not + ``application/json``, this attribute will be ``None``. + - A new value ``http_cache`` can be used as a :term:`view configuration` parameter. diff --git a/pyramid/config.py b/pyramid/config.py index 41af9e832..c4f75c39d 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -1085,7 +1085,7 @@ class Configurator(object): The ``renderer`` attribute is optional. If it is not defined, the "null" renderer is assumed (no rendering is performed and the value is passed back to the upstream - :app:`Pyramid` machinery unmolested). + :app:`Pyramid` machinery unmodified). http_cache @@ -1950,7 +1950,7 @@ class Configurator(object): return mapper # this is *not* an action method (uses caller_package) - def scan(self, package=None, categories=None): + def scan(self, package=None, categories=None, **kw): """Scan a Python package and any of its subpackages for objects marked with :term:`configuration decoration` such as :class:`pyramid.view.view_config`. Any decorated object found will @@ -1970,12 +1970,28 @@ class Configurator(object): :class:`pyramid.view.view_config`. See the :term:`Venusian` documentation for more information about limiting a scan by using an explicit set of categories. + + To perform a ``scan``, Pyramid creates a Venusian ``Scanner`` object. + The ``kw`` argument represents a set of keyword arguments to pass to + the Venusian ``Scanner`` object's constructor. See the + :term:`venusian` documentation (its ``Scanner`` class) for more + information about the constructor. By default, the only keyword + arguments passed to the Scanner constructor are ``{'config':self}`` + where ``self`` is this configurator object. This services the + requirement of all built-in Pyramid decorators, but extension systems + may require additional arguments. Providing this argument is not + often necessary; it's an advanced usage. + + .. note:: the ``**kw`` argument is new in Pyramid 1.1 """ package = self.maybe_dotted(package) if package is None: # pragma: no cover package = caller_package() - scanner = self.venusian.Scanner(config=self) + scankw = {'config':self} + scankw.update(kw) + + scanner = self.venusian.Scanner(**scankw) scanner.scan(package, categories=categories) @action_method diff --git a/pyramid/request.py b/pyramid/request.py index cc5137869..a3848461f 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -10,6 +10,7 @@ from pyramid.interfaces import IResponse from pyramid.interfaces import ISessionFactory from pyramid.interfaces import IResponseFactory +from pyramid.compat import json from pyramid.exceptions import ConfigurationError from pyramid.decorator import reify from pyramid.response import Response @@ -489,6 +490,12 @@ class Request(BaseRequest, DeprecatedRequestMethods): return False return adapted is ob + @property + def json(self): + if self.content_type == 'application/json': + return json.loads(self.body, encoding=self.charset) + + def route_request_iface(name, bases=()): iface = InterfaceClass('%s_IRequest' % name, bases=bases) # for exception view lookups diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index 4827cdd70..ad5e5a89a 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -2850,6 +2850,11 @@ class ConfiguratorTests(unittest.TestCase): result = render_view_to_response(ctx, req, '') self.assertEqual(result, 'grokked') + def test_scan_integration_with_extra_kw(self): + config = self._makeOne(autocommit=True) + config.scan('pyramid.tests.venusianapp', a=1) + self.assertEqual(config.a, 1) + def test_testing_securitypolicy(self): from pyramid.testing import DummySecurityPolicy config = self._makeOne(autocommit=True) diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index 76426b8a8..e65d484ed 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -233,6 +233,26 @@ class TestRequest(unittest.TestCase): request.registry.registerAdapter(adapter, (Foo,), IResponse) self.assertEqual(request.is_response(foo), True) + def test_json_incorrect_mimetype(self): + request = self._makeOne({}) + self.assertEqual(request.json, None) + + def test_json_correct_mimetype(self): + request = self._makeOne({'REQUEST_METHOD':'POST'}) + request.content_type = 'application/json' + request.body = '{"a":1}' + self.assertEqual(request.json, {'a':1}) + + def test_json_alternate_charset(self): + from pyramid.compat import json + request = self._makeOne({'REQUEST_METHOD':'POST'}) + request.content_type = 'application/json' + request.charset = 'latin-1' + la = unicode('La Pe\xc3\xb1a', 'utf-8') + body = json.dumps({'a':la}, encoding='latin-1') + request.body = body + self.assertEqual(request.json, {'a':la}) + class TestRequestDeprecatedMethods(unittest.TestCase): def setUp(self): self.config = testing.setUp() diff --git a/pyramid/tests/venusianapp/__init__.py b/pyramid/tests/venusianapp/__init__.py new file mode 100644 index 000000000..ce5e07238 --- /dev/null +++ b/pyramid/tests/venusianapp/__init__.py @@ -0,0 +1,14 @@ +import venusian + +def foo(wrapped): + def bar(scanner, name, wrapped): + scanner.config.a = scanner.a + venusian.attach(wrapped, bar) + return wrapped + +@foo +def hello(): + pass + +hello() # appease coverage + |
