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.
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.
Bug Fix Releases¶
Pyramid 2.0 was released on 2021-02-28.
The following bug fix releases were made since then. Bug fix releases also include documentation improvements and other minor feature changes.
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.authentication.AuthTktCookieHelper(available in Pyramid 1.x)
pyramid.authorization.DENY_ALLsuch that all of the ACL-related constants are now importable from the
pyramid.authorizationnamespace. See https://github.com/Pylons/pyramid/pull/3563
Changed the default
pyramid.session.PickleSerializer. Read Upgrading Session Serialization for more information about why this change was made. See https://github.com/Pylons/pyramid/pull/3413
It is now possible to control whether a route pattern contains a trailing slash when it is composed with a route prefix using
with config.route_prefix_context(...). This can be done by specifying an empty pattern and setting the new argument
inherit_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 the
'/', then the final pattern would always be
/users/. This new setting is only available if the pattern supplied to
add_routeis the empty string (
''). See https://github.com/Pylons/pyramid/pull/3420
A new parameter,
allow_no_origin, was added to
pyramid.config.Configurator.set_default_csrf_options()as well as
pyramid.csrf.check_csrf_origin(). This option controls whether a request is rejected if it has no
Refererheader - often the result of a user configuring their browser not to send a
Refererheader 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 special
Origin: nullheader by adding it to the
pyramid.csrf_trusted_originslist in the settings. See https://github.com/Pylons/pyramid/pull/3512 and https://github.com/Pylons/pyramid/pull/3518
A new parameter,
check_origin, was added to
pyramid.config.Configurator.set_default_csrf_options()which disables origin checking entirely. See https://github.com/Pylons/pyramid/pull/3518
pyramid.interfaces.IPredicateInfowhich defines the object passed to predicate factories as their second argument. See https://github.com/Pylons/pyramid/pull/3514
Added support for serving pre-compressed static assets by using the
pyramid.static.static_view(). See https://github.com/Pylons/pyramid/pull/3537
DeprecationWarningemitted by using the
impmodule. See https://github.com/Pylons/pyramid/pull/3553
Properties created via
request.set_propertyused to be readonly. They can now be overridden via
request.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/3559
Finished callbacks are now executed as part of the
closerthat is invoked as part of
pyramid.paster.bootstrap(). See https://github.com/Pylons/pyramid/pull/3561
pyramid.request.RequestLocalCachewhich 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 via
pyramid.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/3561
No longer define
pyramid.request.Request.json_bodywhich is already provided by WebOb. This allows the attribute to now be settable. See https://github.com/Pylons/pyramid/pull/3447
Improve debugging info from
pyramid.view.view_configdecorator. See https://github.com/Pylons/pyramid/pull/3483
pservenow 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
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:
effective_principalsview and route predicates.
pyramid.security.principals_allowed_by_permission`(). This method continues to work with the deprecated
pyramid.interfaces.IAuthorizationPolicyinterface but will not work with the new
pyramid.interfaces.ISecurityPolicy. See https://github.com/Pylons/pyramid/pull/3465
Deprecated several ACL-related aspects of
pyramid.security. Equivalent objects should now be imported from the
pyramid.authorizationmodule. This includes:
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)