What's New in Pyramid 2.0¶
This article explains the new features in Pyramid version 2.0 as compared to its predecessor, Pyramid 1.10. It also documents backwards incompatibilities between the two versions and deprecations added to Pyramid 2.0, as well as software dependency changes and notable documentation additions.
Note
This is the first release of Pyramid that does not support Python 2, which is now End-of-Life and no longer receiving critical security updates by the PSF.
Feature Additions¶
The feature additions in Pyramid 2.0 are as follows:
The authentication and authorization policies of Pyramid 1.x have been merged into a single security policy in Pyramid 2.0. For details on how to migrate to the new security policy, see Upgrading Authentication/Authorization. Authentication and authorization policies can still be used and will continue to function normally for the time being.
New security APIs have been added to support an overhaul of the authentication and authorization system. Read Upgrading Authentication/Authorization for information about using this new system.
pyramid.config.Configurator.set_security_policy()
pyramid.authentication.AuthTktCookieHelper
(available in Pyramid 1.x)
Exposed
pyramid.authorization.ALL_PERMISSIONS
andpyramid.authorization.DENY_ALL
such that all of the ACL-related constants are now importable from thepyramid.authorization
namespace. See https://github.com/Pylons/pyramid/pull/3563Changed the default
serializer
onpyramid.session.SignedCookieSessionFactory
to usepyramid.session.JSONSerializer
instead ofpyramid.session.PickleSerializer
. Read Upgrading Session Serialization for more information about why this change was made. See https://github.com/Pylons/pyramid/pull/3413It is now possible to control whether a route pattern contains a trailing slash when it is composed with a route prefix using
config.include(..., route_prefix=...)
orwith config.route_prefix_context(...)
. This can be done by specifying an empty pattern and setting the new argumentinherit_slash=True
. For example:with config.route_prefix_context('/users'): config.add_route('users', '', inherit_slash=True)
In the example, the resulting pattern will be
/users
. Similarly, if the route prefix were/users/
then the final pattern would be/users/
. If thepattern
was'/'
, then the final pattern would always be/users/
. This new setting is only available if the pattern supplied toadd_route
is the empty string (''
). See https://github.com/Pylons/pyramid/pull/3420A new parameter,
allow_no_origin
, was added topyramid.config.Configurator.set_default_csrf_options()
as well aspyramid.csrf.check_csrf_origin()
. This option controls whether a request is rejected if it has noOrigin
orReferer
header - often the result of a user configuring their browser not to send aReferer
header for privacy reasons even on same-domain requests. The default is to reject requests without a known origin. It is also possible to allow the specialOrigin: null
header by adding it to thepyramid.csrf_trusted_origins
list in the settings. See https://github.com/Pylons/pyramid/pull/3512 and https://github.com/Pylons/pyramid/pull/3518A new parameter,
check_origin
, was added topyramid.config.Configurator.set_default_csrf_options()
which disables origin checking entirely. See https://github.com/Pylons/pyramid/pull/3518Added
pyramid.interfaces.IPredicateInfo
which defines the object passed to predicate factories as their second argument. See https://github.com/Pylons/pyramid/pull/3514Added support for serving pre-compressed static assets by using the
content_encodings
argument ofpyramid.config.Configurator.add_static_view()
andpyramid.static.static_view()
. See https://github.com/Pylons/pyramid/pull/3537Fix
DeprecationWarning
emitted by using theimp
module. See https://github.com/Pylons/pyramid/pull/3553Properties created via
config.add_request_method(..., property=True)
orrequest.set_property
used to be readonly. They can now be overridden viarequest.foo = ...
and until the value is deleted it will return the overridden value. This is most useful when mocking request properties in testing. See https://github.com/Pylons/pyramid/pull/3559Finished callbacks are now executed as part of the
closer
that is invoked as part ofpyramid.scripting.prepare()
andpyramid.paster.bootstrap()
. See https://github.com/Pylons/pyramid/pull/3561Added
pyramid.request.RequestLocalCache
which can be used to create simple objects that are shared across requests and can be used to store per-request data. This is useful when the source of data is external to the request itself. Often a reified property is used on a request viapyramid.config.Configurator.add_request_method()
, orpyramid.decorator.reify
. These work great when the data is generated on-demand when accessing the request property. However, often the case is that the data is generated when accessing some other system and then we want to cache the data for the duration of the request. See https://github.com/Pylons/pyramid/pull/3561No longer define
pyramid.request.Request.json_body
which is already provided by WebOb. This allows the attribute to now be settable. See https://github.com/Pylons/pyramid/pull/3447Improve debugging info from
pyramid.view.view_config
decorator. See https://github.com/Pylons/pyramid/pull/3483pserve
now outputs verbose messaging to stderr instead of stdout to circumvent buffering issues that exist by default on stdout. See https://github.com/Pylons/pyramid/pull/3593
Deprecations¶
Deprecated the authentication and authorization interfaces and principal-based support. See Upgrading Authentication/Authorization for information on equivalent APIs and notes on upgrading. The following APIs are deprecated as a result of this change:
pyramid.config.Configurator.set_authentication_policy()
pyramid.config.Configurator.set_authorization_policy()
The
effective_principals
view and route predicates.
Deprecated
pyramid.security.principals_allowed_by_permission`()
. This method continues to work with the deprecatedpyramid.interfaces.IAuthorizationPolicy
interface but will not work with the newpyramid.interfaces.ISecurityPolicy
. See https://github.com/Pylons/pyramid/pull/3465Deprecated several ACL-related aspects of
pyramid.security
. Equivalent objects should now be imported from thepyramid.authorization
module. This includes:Deprecated
pyramid.session.PickleSerializer
. See Upgrading Session Serialization for more information, as well as https://github.com/pylons/pyramid/issues/2709, https://github.com/pylons/pyramid/pull/3353, and https://github.com/pylons/pyramid/pull/3413
Upgrading Session Serialization¶
In Pyramid 2.0 the pyramid.interfaces.ISession
interface was changed to require that session implementations only need to support JSON-serializable data types.
This is a stricter contract than the previous requirement that all objects be pickleable and it is being done for security purposes.
This is a backward-incompatible change.
Previously, if a client-side session implementation was compromised, it left the application vulnerable to remote code execution attacks using specially-crafted sessions that execute code when deserialized.
Please reference the following tickets if detailed information on these changes is needed:
2.0 feature request: Require that sessions are JSON serializable #2709.
change to use JSONSerializer for SignedCookieSessionFactory #3413.
For users with compatibility concerns, it's possible to craft a serializer that can handle both formats until you are satisfied that clients have had time to reasonably upgrade. Remember that sessions should be short-lived and thus the number of clients affected should be small (no longer than an auth token, at a maximum). An example serializer:
1import pickle
2from pyramid.session import JSONSerializer
3from pyramid.session import SignedCookieSessionFactory
4
5
6class JSONSerializerWithPickleFallback(object):
7 def __init__(self):
8 self.json = JSONSerializer()
9
10 def dumps(self, appstruct):
11 """
12 Accept a Python object and return bytes.
13
14 During a migration, you may want to catch serialization errors here,
15 and keep using pickle while finding spots in your app that are not
16 storing JSON-serializable objects. You may also want to integrate
17 a fall-back to pickle serialization here as well.
18 """
19 return self.json.dumps(appstruct)
20
21 def loads(self, bstruct):
22 """Accept bytes and return a Python object."""
23 try:
24 return self.json.loads(bstruct)
25 except ValueError:
26 try:
27 return pickle.loads(bstruct)
28 except Exception:
29 # this block should catch at least:
30 # ValueError, AttributeError, ImportError; but more to be safe
31 raise ValueError
32
33# somewhere in your configuration code
34serializer = JSONSerializerWithPickleFallback()
35session_factory = SignedCookieSessionFactory(..., serializer=serializer)
36config.set_session_factory(session_factory)