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

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

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

Добавлен: 02.01.2026

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

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

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

21.11. LOCALE NEGOTIATORS

21.10.2 Setting the Locale

When the default locale negotiator (see The Default Locale Negotiator) is in use, you can inform Pyramid of the current locale name by doing any of these things before any translations need to be performed:

• Set the _LOCALE_ attribute of the request to a valid locale name (usually directly within view code). E.g. request._LOCALE_ = ’de’.

• Ensure that a valid locale name value is in the request.params dictionary under the key named _LOCALE_. This is usually the result of passing a _LOCALE_ value in the query string or in the body of a form post associated with a request. For example, visiting http://my.application?_LOCALE_=de.

Ensure that a valid locale name value is in the request.cookies dictionary under the key named _LOCALE_. This is usually the result of setting a _LOCALE_ cookie in a prior response, e.g. response.set_cookie(’_LOCALE_’, ’de’).

latex-note.png

If this locale negotiation scheme is inappropriate for a particular application, you can configure a custom locale negotiator function into that application as required. See Using a Custom Locale Negotiator.

21.11 Locale Negotiators

A locale negotiator informs the operation of a localizer by telling it what locale name is related to a particular request. A locale negotiator is a bit of code which accepts a request and which returns a locale name. It is consulted when pyramid.i18n.Localizer.translate() or pyramid.i18n.Localizer.pluralize() is invoked. It is also consulted when get_locale_name() or negotiate_locale_name() is invoked.

245

21. INTERNATIONALIZATION AND LOCALIZATION

21.11.1 The Default Locale Negotiator

Most applications can make use of the default locale negotiator, which requires no additional coding or configuration.

The default locale negotiator implementation named default_locale_negotiator uses the following set of steps to dermine the locale name.

First, the negotiator looks for the _LOCALE_ attribute of the request object (possibly set directly by view code or by a listener for an event).

Then it looks for the request.params[’_LOCALE_’] value.

Then it looks for the request.cookies[’_LOCALE_’] value.

If no locale can be found via the request, it falls back to using the default locale name (see

Localization-Related Deployment Settings).

Finally, if the default locale name is not explicitly set, it uses the locale name en.

21.11.2 Using a Custom Locale Negotiator

Locale negotiation is sometimes policy-laden and complex. If the (simple) default locale negotiation scheme described in Activating Translation is inappropriate for your application, you may create and a special locale negotiator. Subsequently you may override the default locale negotiator by adding your newly created locale negotiator to your application’s configuration.

A locale negotiator is simply a callable which accepts a request and returns a single locale name or None if no locale can be determined.

Here’s an implementation of a simple locale negotiator:

1

2

3

def my_locale_negotiator(request):

locale_name = request.params.get(’my_locale’) return locale_name

If a locale negotiator returns None, it signifies to Pyramid that the default application locale name should be used.

You may add your newly created locale negotiator to your application’s configuration by passing an object which can act as the negotiator (or a dotted Python name referring to the object) as the locale_negotiator argument of the Configurator instance during application startup. For example:

246


21.11. LOCALE NEGOTIATORS

1

2

from pyramid.config import Configurator

config = Configurator(locale_negotiator=my_locale_negotiator)

Alternately, use the pyramid.config.Configurator.set_locale_negotiator() method.

For example:

1 from pyramid.config import Configurator

2 config = Configurator()

3 config.set_locale_negotiator(my_locale_negotiator)

247

21. INTERNATIONALIZATION AND LOCALIZATION

248


CHAPTER

TWENTYTWO

VIRTUAL HOSTING

“Virtual hosting” is, loosely, the act of serving a Pyramid application or a portion of a Pyramid application under a URL space that it does not “naturally” inhabit.

Pyramid provides facilities for serving an application under a URL “prefix”, as well as serving a portion of a traversal based application under a root URL.

22.1 Hosting an Application Under a URL Prefix

Pyramid supports a common form of virtual hosting whereby you can host a Pyramid application as a “subset” of some other site (e.g. under http://example.com/mypyramidapplication/ as opposed to under http://example.com/).

If you use a “pure Python” environment, this functionality can be provided by Paste’s urlmap “composite” WSGI application. Alternately, you can use mod_wsgi to serve your application, which handles this virtual hosting translation for you “under the hood”.

If you use the urlmap composite application “in front” of a Pyramid application or if you use mod_wsgi to serve up a Pyramid application, nothing special needs to be done within the application for URLs to be generated that contain a prefix. paste.urlmap and mod_wsgi manipulate the WSGI environment in such a way that the PATH_INFO and SCRIPT_NAME variables are correct for some given prefix.

Here’s an example of a PasteDeploy configuration snippet that includes a urlmap composite.

249

22. VIRTUAL HOSTING

1

2

3

4

5

6

[app:mypyramidapp]

use = egg:mypyramidapp

[composite:main]

use = egg:Paste#urlmap /pyramidapp = mypyramidapp

This “roots” the Pyramid application at the prefix /pyramidapp and serves up the composite as the “main” application in the file.

latex-note.png

If you’re using an Apache server to proxy to a Paste urlmap composite, you may have to use the ProxyPreserveHost directive to pass the original HTTP_HOST header along to the application, so URLs get generated properly. As of this writing the urlmap composite does not seem to respect the HTTP_X_FORWARDED_HOST parameter, which will contain the original host header even if HTTP_HOST is incorrect.

If you use mod_wsgi, you do not need to use a composite application in your .ini file. The WSGIScriptAlias configuration setting in a mod_wsgi configuration does the work for you:

1 WSGIScriptAlias /pyramidapp /Users/chrism/projects/modwsgi/env/pyramid.wsgi

In the above configuration, we root a Pyramid application at /pyramidapp within the Apache configuration.

22.2 Virtual Root Support

Pyramid also supports “virtual roots”, which can be used in traversal -based (but not URL dispatch -based) applications.

Virtual root support is useful when you’d like to host some resource in a Pyramid resource tree as an application under a URL pathname that does not include the resource path itself. For example, you might want to serve the object at the traversal path /cms as an application reachable via http://example.com/

(as opposed to http://example.com/cms).

250

22.3. FURTHER DOCUMENTATION AND EXAMPLES

To specify a virtual root, cause an environment variable to be inserted into the WSGI environ named HTTP_X_VHM_ROOT with a value that is the absolute pathname to the resource object in the resource tree that should behave as the “root” resource. As a result, the traversal machinery will respect this value during traversal (prepending it to the PATH_INFO before traversal starts), and the pyramid.request.Request.resource_url() API will generate the “correct” virtually-rooted URLs.

An example of an Apache mod_proxy configuration that will host the /cms subobject as http://www.example.com/ using this facility is below:

1NameVirtualHost *:80

2

3<VirtualHost *:80>

4 ServerName www.example.com

5RewriteEngine On

6 RewriteRule ^/(.*) http://127.0.0.1:6543/$1 [L,P]

7ProxyPreserveHost on

8 RequestHeader add X-Vhm-Root /cms

9</VirtualHost>

latex-note.png

Use of the RequestHeader directive requires that the Apache mod_headers module be available in the Apache environment you’re using.

For a Pyramid application running under mod_wsgi, the same can be achieved using SetEnv:

1

2

3

<Location />

SetEnv HTTP_X_VHM_ROOT /cms

</Location>

Setting a virtual root has no effect when using an application based on URL dispatch.

22.3 Further Documentation and Examples

The API documentation in pyramid.traversal documents a pyramid.traversal.virtual_root()

API. When called, it returns the virtual root object (or the physical root object if no virtual root has been specified).

251


22. VIRTUAL HOSTING

Running a Pyramid Application under mod_wsgi has detailed information about using mod_wsgi to serve Pyramid applications.

252

CHAPTER

TWENTYTHREE

UNIT, INTEGRATION, AND

FUNCTIONAL TESTING

Unit testing is, not surprisingly, the act of testing a “unit” in your application. In this context, a “unit” is often a function or a method of a class instance. The unit is also referred to as a “unit under test”.

The goal of a single unit test is to test only some permutation of the “unit under test”. If you write a unit test that aims to verify the result of a particular codepath through a Python function, you need only be concerned about testing the code that lives in the function body itself. If the function accepts a parameter that represents a complex application “domain object” (such as a resource, a database connection, or an SMTP server), the argument provided to this function during a unit test need not be and likely should not be a “real” implementation object. For example, although a particular function implementation may accept an argument that represents an SMTP server object, and the function may call a method of this object when the system is operating normally that would result in an email being sent, a unit test of this codepath of the function does not need to test that an email is actually sent. It just needs to make sure that the function calls the method of the object provided as an argument that would send an email if the argument happened to be the “real” implementation of an SMTP server object.

An integration test, on the other hand, is a different form of testing in which the interaction between two or more “units” is explicitly tested. Integration tests verify that the components of your application work together. You might make sure that an email was actually sent in an integration test.

A functional test is a form of integration test in which the application is run “literally”. You would have to make sure that an email was actually sent in a functional test, because it tests your code end to end.

It is often considered best practice to write each type of tests for any given codebase. Unit testing often provides the opportunity to obtain better “coverage”: it’s usually possible to supply a unit under test with arguments and/or an environment which causes all of its potential codepaths to be executed. This is

253


23. UNIT, INTEGRATION, AND FUNCTIONAL TESTING

usually not as easy to do with a set of integration or functional tests, but integration and functional testing provides a measure of assurance that your “units” work together, as they will be expected to when your application is run in production.

The suggested mechanism for unit and integration testing of a Pyramid application is the Python unittest module. Although this module is named unittest, it is actually capable of driving both unit and integration tests. A good unittest tutorial is available within Dive Into Python by Mark Pilgrim.

Pyramid provides a number of facilities that make unit, integration, and functional tests easier to write. The facilities become particularly useful when your code calls into Pyramid -related framework functions.

23.1 Test Set Up and Tear Down

Pyramid

uses

a “global”

(actually

thread local) data

structure to

hold

on to

two

items:

the

current request

and the

current application

registry.

These data

 

struc-

tures are available via the pyramid.threadlocal.get_current_request()

and

pyramid.threadlocal.get_current_registry() functions, respectively.

See

Thread

Locals for information about these functions and the data structures they return.

 

 

 

 

If your code uses these get_current_* functions or calls Pyramid code which uses get_current_* functions, you will need to call pyramid.testing.setUp() in your test setup and you will need to call pyramid.testing.tearDown() in your test teardown. setUp() pushes a registry onto the thread local stack, which makes the get_current_* functions work. It returns a Configurator object which can be used to perform extra configuration required by the code under test. tearDown() pops the thread local stack.

Normally when a Configurator is used directly with the main block of a Pyramid application, it defers performing any “real work” until its .commit method is called (often implicitly by the pyramid.config.Configurator.make_wsgi_app() method). The Configurator returned by setUp() is an autocommitting Configurator, however, which performs all actions implied by methods called on it immediately. This is more convenient for unit-testing purposes than needing to call pyramid.config.Configurator.commit() in each test after adding extra configuration statements.

The use of the setUp() and tearDown() functions allows you to supply each unit test method in a test case with an environment that has an isolated registry and an isolated request for the duration of a single test. Here’s an example of using this feature:

254