Overview

Pyramid 2.0, released on March 2, 2021, drops Python 2 support, overhauls security, and adds type annotations throughout the framework.

Main Features

Python 2 dropped and type annotations

Pyramid's source code is now Python 3 only (3.6+). Type annotations have been added to public APIs, making it easier to use with mypy and modern IDEs.

python
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.request import Request
from pyramid.response import Response

def home(request: Request) -> Response:
    name = request.params.get('name', 'World')
    return Response(f'Hello {name}!')

def api_info(request: Request) -> dict:
    """Views can return a dict (JSON rendered)."""
    return {'version': '2.0', 'framework': 'Pyramid'}

with Configurator() as config:
    config.add_route('home', '/')
    config.add_route('api', '/api/info')
    config.add_view(home, route_name='home')
    config.add_view(api_info, route_name='api', renderer='json')
    app = config.make_wsgi_app()

# server = make_server('0.0.0.0', 8080, app)
# server.serve_forever()

Security overhaul

The security system has been redesigned with a new security policy API (SecurityPolicy) that replaces the old separate authentication and authorization systems. The unified approach is simpler to configure and more secure.

python
from pyramid.authorization import ACLHelper
from pyramid.request import Request

class MySecurityPolicy:
    """Unified security policy for Pyramid 2.0."""

    def __init__(self, secret: str):
        self.secret = secret
        self.acl = ACLHelper()

    def identity(self, request: Request):
        """Return the user's identity."""
        token = request.cookies.get('auth_token')
        if token:
            return self.verify_token(token)
        return None

    def authenticated_userid(self, request: Request):
        identity = self.identity(request)
        return identity.get('id') if identity else None

    def permits(self, request, context, permission):
        return self.acl.permits(context, request.identity, permission)

    def verify_token(self, token: str) -> dict | None:
        ...  # token verification

Sources