ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 02.01.2026

Просмотров: 2774

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

CHAPTER

SEVEN

REQUEST PROCESSING

Once a Pyramid application is up and running, it is ready to accept requests and return responses. What happens from the time a WSGI request enters a Pyramid application through to the point that Pyramid hands off a response back to WSGI for upstream processing?

1.A user initiates a request from his browser to the hostname and port number of the WSGI server used by the Pyramid application.

2.The WSGI server used by the Pyramid application passes the WSGI environment to the __call__ method of the Pyramid router object.

3.A request object is created based on the WSGI environment.

4.The application registry and the request object created in the last step are pushed on to the thread local stack that Pyramid uses to allow the functions named get_current_request() and get_current_registry() to work.

5.A NewRequest event is sent to any subscribers.

6.If any route has been defined within application configuration, the Pyramid router calls a URL dispatch “route mapper.” The job of the mapper is to examine the request to determine whether any user-defined route matches the current WSGI environment. The router passes the request as an argument to the mapper.

7.If any route matches, the route mapper adds attributes to the request: matchdict and matched_route attributes are added to the request object. The former contains a dictionary representing the matched dynamic elements of the request’s PATH_INFO value, the latter contains the IRoute object representing the route which matched. The root object associated with the route found is also generated: if the route configuration which matched has an associated a factory argument, this factory is used to generate the root object, otherwise a default root factory is used.

65

7.REQUEST PROCESSING

8.If a route match was not found, and a root_factory argument was passed to the Configurator constructor, that callable is used to generate the root object. If the root_factory argument passed to the Configurator constructor was None, a default root factory is used to generate a root object.

9.The Pyramid router calls a “traverser” function with the root object and the request. The traverser function attempts to traverse the root object (using any existing __getitem__ on the root object and subobjects) to find a context. If the root object has no __getitem__ method, the root itself is assumed to be the context. The exact traversal algorithm is described in Traversal. The traverser function returns a dictionary, which contains a context and a view name as well as other ancillary information.

10.The request is decorated with various names returned from the traverser (such as context, view_name, and so forth), so they can be accessed via e.g. request.context within view code.

11.A ContextFound event is sent to any subscribers.

12.Pyramid looks up a view callable using the context, the request, and the view name. If a view callable doesn’t exist for this combination of objects (based on the type of the context, the type of the request, and the value of the view name, and any predicate attributes applied to the view configuration), Pyramid raises a HTTPNotFound exception, which is meant to be caught by a surrounding exception view.

13.If a view callable was found, Pyramid attempts to call it. If an authorization policy is in use, and the view configuration is protected by a permission, Pyramid determines whether the view callable being asked for can be executed by the requesting user based on credential information in the request and security information attached to the context. If the view execution is allowed, Pyramid calls the view callable to obtain a response. If view execution is forbidden, Pyramid raises a HTTPForbidden exception.

14.If any exception is raised within a root factory, by traversal, by a view callable or by Pyramid itself (such as when it raises HTTPNotFound or HTTPForbidden), the router catches the exception, and attaches it to the request as the exception attribute. It then attempts to find a exception view for the exception that was caught. If it finds an exception view callable, that callable is called, and is presumed to generate a response. If an exception view that matches the exception cannot be found, the exception is reraised.

15.The following steps occur only when a response could be successfully generated by a normal view callable or an exception view callable. Pyramid will attempt to execute any response callback functions attached via add_response_callback(). A NewResponse event is then sent to any subscribers. The response object’s __call__ method is then used to generate a WSGI response. The response is sent back to the upstream WSGI server.

66


16.Pyramid will attempt to execute any finished callback functions attached via add_finished_callback().

17.The thread local stack is popped.

67

7. REQUEST PROCESSING

68

This is a very high-level overview that leaves out various details. For more detail about subsystems invoked by the Pyramid router such as traversal, URL dispatch, views, and event processing, see URL Dispatch, Views, and Using Events.

69

7. REQUEST PROCESSING

70


CHAPTER

EIGHT

URL DISPATCH

URL dispatch provides a simple way to map URLs to view code using a simple pattern matching language. An ordered set of patterns is checked one-by-one. If one of the patterns matches the path information associated with a request, a particular view callable is invoked. A view callable is a specific bit of code, defined in your application, that receives the request and returns a response object.

8.1 High-Level Operational Overview

If route configuration is present in an application, the Pyramid Router checks every incoming request against an ordered set of URL matching patterns present in a route map.

If any route pattern matches the information in the request, Pyramid will invoke view lookup to find a matching view.

If no route pattern in the route map matches the information in the request provided in your application, Pyramid will fail over to using traversal to perform resource location and view lookup.

8.2 Route Configuration

Route configuration is the act of adding a new route to an application. A route has a name, which acts as an identifier to be used for URL generation. The name also allows developers to associate a view configuration with the route. A route also has a pattern, meant to match against the PATH_INFO portion of a URL (the portion following the scheme and port, e.g. /foo/bar in the URL http://localhost:8080/foo/bar). It also optionally has a factory and a set of route predicate attributes.

71

8. URL DISPATCH

8.2.1 Configuring a Route to Match a View

The pyramid.config.Configurator.add_route() method adds a single route configuration to the application registry. Here’s an example:

#"config" below is presumed to be an instance of the

#pyramid.config.Configurator class; "myview" is assumed

#to be a "view callable" function

from views import myview config.add_route(’myroute’, ’/prefix/{one}/{two}’) config.add_view(myview, route_name=’myroute’)

When a view callable added to the configuration by way of add_view() becomes associated with a route via its route_name predicate, that view callable will always be found and invoked when the associated route pattern matches during a request.

More commonly, you will not use any add_view statements in your project’s “setup” code, instead only using add_route statements using a scan for to associate view callables with routes. For example, if this is a portion of your project’s __init__.py:

# in your project’s __init__.py (mypackage.__init__)

config.add_route(’myroute’, ’/prefix/{one}/{two}’) config.scan(’mypackage’)

Note that we don’t call add_view() in this setup code. However, the above scan execution config.scan(’mypackage’) will pick up all configuration decoration, including any objects decorated with the pyramid.view.view_config decorator in the mypackage Python pakage. For example, if you have a views.py in your package, a scan will pick up any of its configuration decorators, so we can add one there that that references myroute as a route_name parameter:

# in your project’s views.py module (mypackage.views)

from pyramid.view import view_config from pyramid.response import Response

@view_config(route_name=’myroute’) def myview(request):

return Response(’OK’)

The above combination of add_route and scan is completely equivalent to using the previous combination of add_route and add_view.

72


8.2. ROUTE CONFIGURATION

8.2.2 Route Pattern Syntax

The syntax of the pattern matching language used by Pyramid URL dispatch in the pattern argument is straightforward; it is close to that of the Routes system used by Pylons.

The pattern used in route configuration may start with a slash character. If the pattern does not start with a slash character, an implicit slash will be prepended to it at matching time. For example, the following patterns are equivalent:

{foo}/bar/baz

and:

/{foo}/bar/baz

A pattern segment (an individual item between / characters in the pattern) may either be a literal string (e.g. foo) or it may be a replacement marker (e.g. {foo}) or a certain combination of both. A replacement marker does not need to be preceded by a / character.

A replacement marker is in the format {name}, where this means “accept any characters up to the next slash character and use this as the name matchdict value.”

A replacement marker in a pattern must begin with an uppercase or lowercase ASCII letter or an underscore, and can be composed only of uppercase or lowercase ASCII letters, underscores, and numbers. For example: a, a_b, _b, and b9 are all valid replacement marker names, but 0a is not.

latex-note.png

A replacement marker could not start with an underscore until Pyramid 1.2. Previous versions required that the replacement marker start with an uppercase or lowercase letter.

A matchdict is the dictionary representing the dynamic parts extracted from a URL based on the routing pattern. It is available as request.matchdict. For example, the following pattern defines one literal segment (foo) and two replacement markers (baz, and bar):

73

8. URL DISPATCH

foo/{baz}/{bar}

The above pattern will match these URLs, generating the following matchdicts:

foo/1/2

->

{’baz’:u’1’, ’bar’:u’2’}

foo/abc/def

->

{’baz’:u’abc’, ’bar’:u’def’}

 

 

 

It will not match the following patterns however:

foo/1/2/

->

No match (trailing slash)

bar/abc/def

->

First segment literal mismatch

 

 

 

The match for a segment replacement marker in a segment will be done only up to the first nonalphanumeric character in the segment in the pattern. So, for instance, if this route pattern was used:

foo/{name}.html

The literal path /foo/biz.html will match the above route pattern, and the match result will be {’name’:u’biz’}. However, the literal path /foo/biz will not match, because it does not contain a literal .html at the end of the segment represented by {name}.html (it only contains biz, not biz.html).

To capture both segments, two replacement markers can be used:

foo/{name}.{ext}

The literal path /foo/biz.html will match the above route pattern, and the match result will be {’name’: ’biz’, ’ext’: ’html’}. This occurs because there is a literal part of . (period) between the two replacement markers {name} and {ext}.

Replacement markers can optionally specify a regular expression which will be used to decide whether a path segment should match the marker. To specify that a replacement marker should match only a specific set of characters as defined by a regular expression, you must use a slightly extended form of replacement marker syntax. Within braces, the replacement marker name must be followed by a colon, then directly thereafter, the regular expression. The default regular expression associated with a replacement marker [^/]+ matches one or more characters which are not a slash. For example, under the hood, the replacement marker {foo} can more verbosely be spelled as {foo:[^/]+}. You can change this to be an arbitrary regular expression to match an arbitrary sequence of characters, such as {foo:\d+} to match only digits.

74


8.2. ROUTE CONFIGURATION

It is possible to use two replacement markers without any literal characters between them, for instance /{foo}{bar}. However, this would be a nonsensical pattern without specifying a custom regular expression to restrict what each marker captures.

Segments must contain at least one character in order to match a segment replacement marker. For example, for the URL /abc/:

/abc/{foo} will not match.

/{foo}/ will match.

Note that values representing matched path segments will be url-unquoted and decoded from UTF-8 into Unicode within the matchdict. So for instance, the following pattern:

foo/{bar}

When matching the following URL:

http://example.com/foo/La%20Pe%C3%B1a

The matchdict will look like so (the value is URL-decoded / UTF-8 decoded):

{’bar’:u’La Pe\xf1a’}

Literal strings in the path segment should represent the decoded value of the PATH_INFO provided to Pyramid. You don’t want to use a URL-encoded value or a bytestring representing the literal’s UTF-8 in the pattern. For example, rather than this:

/Foo%20Bar/{baz}

You’ll want to use something like this:

/Foo Bar/{baz}

For patterns that contain “high-order” characters in its literals, you’ll want to use a Unicode value as the pattern as opposed to any URL-encoded or UTF-8-encoded value. For example, you might be tempted to use a bytestring pattern like this:

75

8. URL DISPATCH

/La Pe\xc3\xb1a/{x}

But this will either cause an error at startup time or it won’t match properly. You’ll want to use a Unicode value as the pattern instead rather than raw bytestring escapes. You can use a high-order Unicode value as the pattern by using Python source file encoding plus the “real” character in the Unicode pattern in the source, like so:

/La Peña/{x}

Or you can ignore source file encoding and use equivalent Unicode escape characters in the pattern.

/La Pe\xf1a/{x}

Dynamic segment names cannot contain high-order characters, so this applies only to literals in the pattern.

If the pattern has a * in it, the name which follows it is considered a “remainder match”. A remainder match must come at the end of the pattern. Unlike segment replacement markers, it does not need to be preceded by a slash. For example:

foo/{baz}/{bar}*fizzle

The above pattern will match these URLs, generating the following matchdicts:

foo/1/2/ ->

{’baz’:u’1’, ’bar’:u’2’, ’fizzle’:()}

foo/abc/def/a/b/c ->

{’baz’:u’abc’, ’bar’:u’def’, ’fizzle’:(u’a’, u’b’, u’c’)}

Note that when a *stararg remainder match is matched, the value put into the matchdict is turned into a tuple of path segments representing the remainder of the path. These path segments are url-unquoted and decoded from UTF-8 into Unicode. For example, for the following pattern:

foo/*fizzle

When matching the following path:

76