==================
Features
--------
- Small microspeed enhancement which anticipates that a
``pyramid.response.Response`` object is likely to be returned from a view.
Some code is shortcut if the class of the object returned by a view is this
class. A similar microoptimization was done to
``pyramid.request.Request.is_response``.
- Make it possible to use variable arguments on ``p*`` commands (``pserve``,
``pshell``, ``pviews``, etc) in the form ``a=1 b=2`` so you can fill in
values in parameterized ``.ini`` file, e.g. ``pshell etc/development.ini
http_port=8080``. See https://github.com/Pylons/pyramid/pull/714
- A somewhat advanced and obscure feature of Pyramid event handlers is their
ability to handle "multi-interface" notifications. These notifications have
traditionally presented multiple objects to the subscriber callable. For
instance, if an event was sent by code like this::
registry.notify(event, context)
In the past, in order to catch such an event, you were obligated to write and
register an event subscriber that mentioned both the event and the context in
its argument list::
subscriber([SomeEvent, SomeContextType])
def asubscriber(event, context):
pass
In many subscriber callables registered this way, it was common for the logic
in the subscriber callable to completely ignore the second and following
arguments (e.g. ``context`` in the above example might be ignored), because
they usually existed as attributes of the event anyway. You could usually
get the same value by doing ``event.context`` or similar.
The fact that you needed to put an extra argument which you usually ignored
in the subscriber callable body was only a minor annoyance until we added
"subscriber predicates", used to narrow the set of circumstances under which
a subscriber will be executed, in a prior 1.4 alpha release. Once those were
added, the annoyance was escalated, because subscriber predicates needed to
accept the same argument list and arity as the subscriber callables that they
were configured against. So, for example, if you had these two subscriber
registrations in your code::
subscriber([SomeEvent, SomeContextType])
def asubscriber(event, context):
pass
subscriber(SomeOtherEvent)
def asubscriber(event):
pass
And you wanted to use a subscriber predicate::
subscriber([SomeEvent, SomeContextType], mypredicate=True)
def asubscriber1(event, context):
pass
subscriber(SomeOtherEvent, mypredicate=True)
def asubscriber2(event):
pass
If an existing ``mypredicate`` subscriber predicate had been written in such
a way that it accepted only one argument in its ``__call__``, you could not
use it against a subscription which named more than one interface in its
subscriber interface list. Similarly, if you had written a subscriber
predicate that accepted two arguments, you couldn't use it against a
registration that named only a single interface type.
For example, if you created this predicate::
class MyPredicate(object):
portions elided...
def __call__(self, event):
return self.val == event.context.foo
It would not work against a multi-interface-registered subscription, so in
the above example, when you attempted to use it against ``asubscriber1``, it
would fail at runtime with a TypeError, claiming something was attempting to
call it with too many arguments.
To hack around this limitation, you were obligated to design the
``mypredicate`` predicate to expect to receive in its ``__call__`` either a
single ``event`` argument (a SomeOtherEvent object) *or* a pair of arguments
(a SomeEvent object and a SomeContextType object), presumably by doing
something like this::
class MyPredicate(object):
portions elided...
def __call__(self, event, context=None):
return self.val == event.context.foo
This was confusing and bad.
In order to allow people to ignore unused arguments to subscriber callables
and to normalize the relationship between event subscribers and subscriber
predicates, we now allow both subscribers and subscriber predicates to accept
only a single ``event`` argument even if they've been subscribed for
notifications that involve multiple interfaces. Subscribers and subscriber
predicates that accept only one argument will receive the first object passed
to ``notify``; this is typically (but not always) the event object. The
other objects involved in the subscription lookup will be discarded. You can
now write an event subscriber that accepts only ``event`` even if it
subscribes to multiple interfaces::
subscriber([SomeEvent, SomeContextType])
def asubscriber(event):
this will work!
This prevents you from needing to match the subscriber callable parameters to
the subscription type unnecessarily, especially when you don't make use of
any argument in your subscribers except for the event object itself.
Note, however, that if the event object is not the first
object in the call to ``notify``, you'll run into trouble. For example, if
notify is called with the context argument first::
registry.notify(context, event)
You won't be able to take advantage of the event-only feature. It will
"work", but the object received by your event handler won't be the event
object, it will be the context object, which won't be very useful::
subscriber([SomeContextType, SomeEvent])
def asubscriber(event):
bzzt! you'll be getting the context here as ``event``, and it'll
be useless
Existing multiple-argument subscribers continue to work without issue, so you
should continue use those if your system notifies using multiple interfaces
and the first interface is not the event interface. For example::
subscriber([SomeContextType, SomeEvent])
def asubscriber(context, event):
this will still work!
The event-only feature makes it possible to use a subscriber predicate that
accepts only a request argument within both multiple-interface subscriber
registrations and single-interface subscriber registrations. You needn't
make slightly different variations of predicates depending on the
subscription type arguments. Instead, just write all your subscriber
predicates so they only accept ``event`` in their ``__call__`` and they'll be
useful across all registrations for subscriptions that use an event as their
first argument, even ones which accept more than just ``event``.
However, the same caveat applies to predicates as to subscriber callables: if
you're subscribing to a multi-interface event, and the first interface is not
the event interface, the predicate won't work properly. In such a case,
you'll need to match the predicate ``__call__`` argument ordering and
composition to the ordering of the interfaces. For example, if the
registration for the subscription uses ``[SomeContext, SomeEvent]``, you'll
need to reflect that in the ordering of the parameters of the predicate's
``__call__`` method::
def __call__(self, context, event):
return event.request.path.startswith(self.val)
tl;dr: 1) When using multi-interface subscriptions, always use the event type
as the first subscription registration argument and 2) When 1 is true, use
only ``event`` in your subscriber and subscriber predicate parameter lists,
no matter how many interfaces the subscriber is notified with. This
combination will result in the maximum amount of reusability of subscriber
predicates and the least amount of thought on your part. Drink responsibly.
Bug Fixes
---------
- A failure when trying to locate the attribute ``__text__`` on route and view
predicates existed when the ``debug_routematch`` setting was true or when the
``pviews`` command was used. See https://github.com/Pylons/pyramid/pull/727
Documentation
-------------
- Sync up tutorial source files with the files that are rendered by the
scaffold that each uses.