diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-12-09 00:34:50 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-12-09 00:34:50 +0000 |
| commit | 8b1f6e5ed3f9fc32b5eb03257d24eaf754a797a9 (patch) | |
| tree | b0525c11e88c5adf6c233c09d7e9318429d54265 | |
| parent | f46de3bb0a9d2c9823aa3221fd28d80aed65b719 (diff) | |
| download | pyramid-8b1f6e5ed3f9fc32b5eb03257d24eaf754a797a9.tar.gz pyramid-8b1f6e5ed3f9fc32b5eb03257d24eaf754a797a9.tar.bz2 pyramid-8b1f6e5ed3f9fc32b5eb03257d24eaf754a797a9.zip | |
- General documentation freshening which takes imperative
configuration into account in more places and uses glossary
references more liberally.
| -rw-r--r-- | CHANGES.txt | 10 | ||||
| -rw-r--r-- | docs/glossary.rst | 188 | ||||
| -rw-r--r-- | docs/narr/configuration.rst | 39 | ||||
| -rw-r--r-- | docs/narr/templates.rst | 19 | ||||
| -rw-r--r-- | docs/tutorials/gae/index.rst | 2 | ||||
| -rw-r--r-- | repoze/bfg/authentication.py | 10 | ||||
| -rw-r--r-- | repoze/bfg/authorization.py | 28 | ||||
| -rw-r--r-- | repoze/bfg/configuration.py | 284 | ||||
| -rw-r--r-- | repoze/bfg/events.py | 44 | ||||
| -rw-r--r-- | repoze/bfg/interfaces.py | 36 | ||||
| -rw-r--r-- | repoze/bfg/location.py | 28 | ||||
| -rw-r--r-- | repoze/bfg/path.py | 1 | ||||
| -rw-r--r-- | repoze/bfg/request.py | 6 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 10 | ||||
| -rw-r--r-- | repoze/bfg/scripting.py | 5 | ||||
| -rw-r--r-- | repoze/bfg/security.py | 51 | ||||
| -rw-r--r-- | repoze/bfg/testing.py | 132 | ||||
| -rw-r--r-- | repoze/bfg/traversal.py | 155 | ||||
| -rw-r--r-- | repoze/bfg/url.py | 54 | ||||
| -rw-r--r-- | repoze/bfg/view.py | 196 | ||||
| -rw-r--r-- | repoze/bfg/wsgi.py | 20 |
21 files changed, 693 insertions, 625 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 885c5e8b1..0ae688938 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +Next release +============ + +Documentation +------------- + +- General documentation freshening which takes imperative + configuration into account in more places and uses glossary + references more liberally. + 1.2a4 (2009-12-07) ================== diff --git a/docs/glossary.rst b/docs/glossary.rst index 79b780092..aa7847879 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -10,11 +10,12 @@ Glossary A ``WebOb`` request object. See :ref:`webob_chapter` for information about request objects. Response - An object that has three attributes: app_iter (representing an - iterable body), headerlist (representing the http headers sent - upstream), and status (representing the http status string). This - is the interface defined for ``WebOb`` response objects. See - :ref:`webob_chapter` for information about response objects. + An object that has three attributes: ``app_iter`` (representing an + iterable body), ``headerlist`` (representing the http headers sent + to the user agent), and ``status`` (representing the http status + string sent to the user agent). This is the interface defined for + ``WebOb`` response objects. See :ref:`webob_chapter` for + information about response objects. Repoze "Repoze" is essentially a "brand" of software developed by `Agendaless Consulting <http://agendaless.com>`_ and a set of @@ -37,11 +38,12 @@ Glossary Any file contained within a Python :term:`package` which is *not* a Python source code file. Resource Specification - A colon-delimited identifier for a resource. The colon separates - a Python :term:`package` name from a package subpath. For - example, the resource specification ``my.package:static/baz.css`` - identifies the file named ``baz.css`` in the ``static`` - subdirectory of the ``my.package`` Python package. + A colon-delimited identifier for a :term:`resource`. The colon + separates a Python :term:`package` name from a package subpath. + For example, the resource specification + ``my.package:static/baz.css`` identifies the file named + ``baz.css`` in the ``static`` subdirectory of the ``my.package`` + Python :term:`package`. Package A directory on disk which contains an ``__init__.py`` file, making it recognizable to Python as a location which can be ``import`` -ed. @@ -85,10 +87,10 @@ Glossary configuration information. This configuration information helps map the view callable to URLs and can influence the response of a view callable. :mod:`repoze.bfg` views can be configured via - :term:`ZCML` or by a special ``@bfg_view`` decorator (see - :ref:`mapping_views_to_urls_using_a_decorator_section`.). See + :term:`imperative configuration`, :term:`ZCML` or by a special + ``@bfg_view`` decorator coupled with a :term:`scan`. See :ref:`views_chapter` for more information about view - configuration. + configuration. View name The "URL name" of a view, e.g ``index.html``. If a view is configured without a name, its name is considered to be the empty @@ -108,9 +110,10 @@ Glossary used, a model is a node in the object graph traversed by the system. When traversal is used, a model instance becomes the :term:`context` of a :term:`view`. If :mod:`url dispatch` is - used, a single :term:`context` (which isn't really a model, - because it contains no data except security elements) is generated - for each request and is used as the context of a view. + used, a single :term:`context` is generated for each request and + is used as the context of a view: this object is also technically + a "model" in :mod:`repoze.bfg` terms, although this terminology + can be a bit confusing: see :ref:`model_traversal_confusion`. Traversal The act of descending "down" a graph of model objects from a root model in order to find a :term:`context`. The :mod:`repoze.bfg` @@ -129,15 +132,15 @@ Glossary URL dispatch An alternative to graph traversal as a mechanism for locating a :term:`context` for a :term:`view`. When you use a :term:`route` - in your :mod:`repoze.bfg` application via a ``<route>`` - :term:`ZCML declaration` in ZCML, you are using URL dispatch. See the + in your :mod:`repoze.bfg` application via a :term:`route + configuration`, you are using URL dispatch. See the :ref:`urldispatch_chapter` for more information. Context An object in the system that is found during :term:`traversal` or :term:`URL dispatch` based on URL data; if it's found via traversal, it's usually a :term:`model` object that is part of an object graph; if it's found via :term:`URL dispatch`, it's a - object manufacture on behalf of the route's "factory". A context + object manufactured on behalf of the route's "factory". A context becomes the subject of a :term:`view`, and typically has security information attached to it. See the :ref:`traversal_chapter` chapter and the :ref:`urldispatch_chapter` chapter for more @@ -187,9 +190,7 @@ Glossary given the :term:`authentication` information in the request. Authentication The act of determining that the credentials a user presents during - a particular request are "good". :mod:`repoze.bfg` does not - perfom authentication: it leaves it up to an upstream component - such as :term:`repoze.who`. :mod:`repoze.bfg` uses the + a particular request are "good". :mod:`repoze.bfg` uses the :term:`authentication` data supplied by the upstream component as one input during :term:`authorization`. Authentication in :mod:`repoze.bfg` is performed via an :term:`authentication @@ -203,13 +204,12 @@ Glossary its :term:`authorization policy`. Principal A *principal* is a string or unicode object representing a user or - a user's membership in a group. It is provided by the - :term:`authentication` machinery "upstream", typically (such as - :term:`repoze.who`). For example, if a user had the user id - "bob", and Bob was part of two groups named "group foo" and "group - bar", the request might have information attached to it that would - indictate that Bob was represented by three principals: "bob", - "group foo" and "group bar". + a user's membership in a group. It is provided by an + :term:`authentication policy`. For example, if a user had the + user id "bob", and Bob was part of two groups named "group foo" + and "group bar", the request might have information attached to it + that would indictate that Bob was represented by three principals: + "bob", "group foo" and "group bar". Authorization Policy An authorization policy in :mod:`repoze.bfg` terms is a bit of code which has an API which determines whether or not the @@ -274,15 +274,7 @@ Glossary the ability to use bracketed (Genshi-style) ``${name}`` syntax, even within ZPT. It is also much faster than the reference implementations of both ZPT and Genshi. :mod:`repoze.bfg` offers - Chameleon templating out of the box in ZPT flavor and offers the - Genshi flavor as an add on within the - :mod:`repoze.bfg.chameleon_genshi` package. - chameleon.zpt - ``chameleon.zpt`` is the package which provides :term:`ZPT` - templating support under the :term:`Chameleon` templating engine. - z3c.pt - This was the previous name for :term:`Chameleon`, and is now a - Zope 3 compatibility package for Chameleon. + Chameleon templating out of the box in ZPT and text flavors. ZPT The `Zope Page Template <http://wiki.zope.org/ZPT/FrontPage>`_ templating language. @@ -307,11 +299,12 @@ Glossary which generally resolves to a :term:`root factory` (and then ultimately a :term:`view`). See also :term:`url dispatch`. Route Configuration - Route configuration is the act of using a :term:`ZCML` ``<route>`` - statement to associate request parameters with a particular - :term:`route` using pattern matching and :term:`route predicate` - statements. See :ref:`urldispatch_chapter` for more information - about route configuration. + Route configuration is the act of using :term:`imperative + configuration` or a :term:`ZCML` ``<route>`` statement to + associate request parameters with a particular :term:`route` using + pattern matching and :term:`route predicate` statements. See + :ref:`urldispatch_chapter` for more information about route + configuration. ZCML `Zope Configuration Markup Language <http://www.muthukadan.net/docs/zca.html#zcml>`_, an XML dialect @@ -320,8 +313,8 @@ Glossary declaration`, but its primary purpose in :mod:`repoze.bfg` is to perform :term:`view configuration` and :term:`route configuration` within the ``configure.zcml`` file in a :mod:`repoze.bfg` - application. ZCML in a :mod:`repoze.bfg` application represents - the application's :term:`application registry`. + application. You can use ZCML as an alternative to + :term:`imperative configuration`. ZCML Directive A ZCML "tag" such as ``<view>`` or ``<route>``. ZCML Declaration @@ -351,51 +344,42 @@ Glossary subpath. See :ref:`star_subpath` for more information. Interface A `Zope interface <http://pypi.python.org/pypi/zope.interface>`_ - object. In :mod:`repoze.bfg`, an interface may be attached to an - model object or a request object in order to identify that the - object is "of a type". Interfaces are used internally by - :mod:`repoze.bfg` to perform view lookups and other policy - lookups. Interfaces are exposed to application programmers by the - ``view`` ZCML directive or the corresponding ``bfg_view`` - decorator in the form of both the ``for`` attribute and the - ``request_type`` attribute. They may be exposed to application - developers when using the :term:`event` system as - well. Fundamentally, :mod:`repoze.bfg` programmers can think of an - interface as something that they can attach to an object that - stamps it with a "type" unrelated to its underlying Python type. - Interfaces can also be used to describe the behavior of an object - (its methods and attributes), but unless they choose to, - :mod:`repoze.bfg` programmers do not need to understand or use + object. In :mod:`repoze.bfg`, an interface may be attached to a + :term:`model` object or a :term:`request` object in order to + identify that the object is "of a type". Interfaces are used + internally by :mod:`repoze.bfg` to perform view lookups and other + policy lookups. The ability to make use of an interface is + exposed to an application programmers during :term:`view + configuration` via the ``for`` argument, the ``request_type`` + argument and the ``containment`` argument. Interfaces are also + exposed to application developers when they make use of the + :term:`event` system. Fundamentally, :mod:`repoze.bfg` programmers + can think of an interface as something that they can attach to an + object that stamps it with a "type" unrelated to its underlying + Python type. Interfaces can also be used to describe the behavior + of an object (its methods and attributes), but unless they choose + to, :mod:`repoze.bfg` programmers do not need to understand or use this feature of interfaces. Event An object broadcast to zero or more :term:`subscriber` callables - during normal system operations. :mod:`repoze.bfg` emits events - during its lifetime routine. Application code can subscribe to + during normal :mod:`repoze.bfg` system operations during the + lifetime of an application. Application code can subscribe to these events by using the subscriber functionality described in - :ref:`events_chapter`. Application code can also generate its own - events using the ``zope.component.event.dispatch`` function. - Application-code generated events may be subscribed to in the same - way as system-generated events. + :ref:`events_chapter`. Subscriber A callable which receives an :term:`event`. A callable becomes a - subscriber through an application registry registration. See - :ref:`events_chapter` for more information. + subscriber via :term:`imperative configuration` or the + ``<subscriber>`` ZCML directive. See :ref:`events_chapter` for + more information. Request type An attribute of a :term:`request` that allows for specialization - of view code based on arbitrary categorization. The every + of view invocation based on arbitrary categorization. The every :term:`request` object that bfg generates and manipulates has one or more :term:`interface` objects attached to it. The default interface attached to a request object is - ``repoze.bfg.interfaces.IRequest``. When a user writes view code, - and registers a view without specifying a particular request type, - the view is assumed to be registered for requests that have - ``repoze.bfg.interfaces.IRequest`` attached to them. However if - the view is registered with a different interface as its request - type, the view will be invoked only when the request possesses - that particular interface. Application code can cause requests to - possess a different interface by adding the interface to the - request object within a :term:`subscriber` to the - ``repoze.bfg.interfaces.INewRequest`` event type. + ``repoze.bfg.interfaces.IRequest``. See + :ref:`using_an_event_to_vary_the_request_type` for more + information. repoze.lemonade Zope2 CMF-like `data structures and helper facilities <http://docs.repoze.org/lemonade>`_ for CA-and-ZODB-based @@ -419,22 +403,22 @@ Glossary application root factory) unless :ref:`vhosting_chapter` is in use. Lineage - An ordered sequence of objects based on a ":term:`location` -aware" - context. The lineage of any given :term:`context` is composed of - itself, its parent, its parent's parent, and so on. The order of - the sequence is context-first, then the parent of the context, - then its parent's parent, and so on. + An ordered sequence of objects based on a ":term:`location` + -aware" context. The lineage of any given :term:`context` is + composed of itself, its parent, its parent's parent, and so on. + The order of the sequence is context-first, then the parent of the + context, then its parent's parent, and so on. The parent of an + object in a lineage is available as its ``__parent__`` attribute. Root Factory The "root factory" of an :mod:`repoze.bfg` application is called on every request sent to the application. The root factory returns the traversal root of an application. It is - conventionally named ``get_root``. An application must supply a - root factory to :mod:`repoze.bfg` within a call to - ``repoze.bfg.router.make_app``; however, an application's root - factory may be passed to ``make_app`` as ``None``, in which case - the application uses a default root object (this pattern is often - used in application which use :term:`URL dispatch` for all - URL-to-view code mappings). + conventionally named ``get_root``. An application may supply a + root factory to :mod:`repoze.bfg` during the construction of a + :term:`Configurator`. If a root factory is not supplied, the + application uses a default root object. Use of the default root + object is useful in application which use :term:`URL dispatch` for + all URL-to-view code mappings. SQLAlchemy `SQLAlchemy' <http://www.sqlalchemy.org/>`_ is an object relational mapper used in tutorials within this documentation. @@ -454,22 +438,22 @@ Glossary applications (such as applications developed using :mod:`repoze.bfg`) to be served using the Apache web server. View Predicate - An attribute of a ZCML ``view`` directive or an argument to a - ``bfg_view`` decorator which implies a value which evaluates to - true or false for a given :term:`request`. All predicates + An argument to a :term:`view configuration` which evaluates to + ``True`` or ``False`` for a given :term:`request`. All predicates attached to a view configuration must evaluate to true for the associated view to be considered as a possible callable for a given request. Route Predicate - An attribute of a ZCML ``route`` directive which implies a value - that evaluates to true or false for a given :term:`request`. All - predicates attached to a route configuration must evaluate to true - for the associated route to "match" the current request. If a - route does not match the current request, the next route (in - definition order) is attempted. + An argument to a :term:`route configuration` which implies a value + that evaluates to ``True`` or ``False`` for a given + :term:`request`. All predicates attached to a :term:`route + configuration` must evaluate to ``True`` for the associated route + to "match" the current request. If a route does not match the + current request, the next route (in definition order) is + attempted. Predicate - A test which returns true or false. Two different types of - predicates exist in :mod:`repoze.bfg`: a :term:`view predicate` + A test which returns ``True`` or ``False``. Two different types + of predicates exist in :mod:`repoze.bfg`: a :term:`view predicate` and a :term:`route predicate`. View predicates are attached to :term:`view configuration` and route predicates are attached to :term:`route configuration`. diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst index 705e5aef5..7720bf5fc 100644 --- a/docs/narr/configuration.rst +++ b/docs/narr/configuration.rst @@ -21,18 +21,17 @@ used to create all kinds of web applications. libraries to create an application is often initially easier than using a framework to create an application, because the developer can choose to cede control to library code he has not authored - selectively, making the resulting application easier to understand. - When using a framework, the developer is typically required to cede - a greater portion of control to code he has not authored: code that - resides in the framework itself. You needn't use a framework at - all to create a web application using Python. A rich set of - libraries exists for the platform which you can snap together to - effectively create your own framework. In practice, however, using - an existing framework to create an application is often more - practical than rolling your own via a set of libraries if the - framework provides a set of facilities and assumptions that fit - your application requirements. :mod:`repoze.bfg` is a framework - that fits a large set of assumptions in the domain of web + selectively. When using a framework, the developer is typically + required to cede a greater portion of control to code he has not + authored: code that resides in the framework itself. You needn't + use a framework at all to create a web application using Python. A + rich set of libraries exists for the platform which you can snap + together to effectively create your own framework. In practice, + however, using an existing framework to create an application is + often more practical than rolling your own via a set of libraries + if the framework provides a set of facilities and assumptions that + fit your application requirements. :mod:`repoze.bfg` is a + framework that fits a large set of assumptions in the domain of web application construction. As a framework, the primary job of :mod:`repoze.bfg` is to make it @@ -51,11 +50,10 @@ instance, it's easy to think of the values implied by a ``.ini`` file which is parsed at application startup time as "configuration". :mod:`repoze.bfg` extends this pattern all the way out to application development, using the term "configuration" to express standardized -methods the framework makes available to developers which can be used -to plug code into a deployment of the framework itself. When you plug -code into the :mod:`repoze.bfg` framework, you are indeed -"configuring" :mod:`repoze.bfg` for the purpose of creating a -particular application deployment. +methods which can be used to plug code into a deployment of the +framework itself. When you plug code into the :mod:`repoze.bfg` +framework, you are indeed "configuring" :mod:`repoze.bfg` for the +purpose of creating a particular application deployment. There are a number of different mechanisms you may use to configure :mod:`repoze.bfg` to create an application: *imperative* configuration @@ -75,9 +73,10 @@ Hello World, Configured Imperatively ------------------------------------ Experienced Python programmers may find the "imperative" configuration -mechanism fits the way they already do things. This is the configuration -mode in which developers cede the least amount of control to the framework. -Because of this, it is also the easiest configuration mode to understand. +mechanism fits the way they already do things. This is the +configuration mode in which developers cede the least amount of +control to the framework. It is often the easiest configuration mode +to understand. Here's one of the simplest :mod:`repoze.bfg` applications, configured imperatively: diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst index a94c493a6..4417ffcd5 100644 --- a/docs/narr/templates.rst +++ b/docs/narr/templates.rst @@ -16,10 +16,9 @@ Like :term:`Zope`, :mod:`repoze.bfg` uses Zope Page Templates (:term:`ZPT`) as its default and best-supported templating language. However, :mod:`repoze.bfg` uses a different implementation of the :term:`ZPT` specification than Zope does: the :term:`Chameleon` -:term:`chameleon.zpt` templating engine. This templating engine -complies largely with the `Zope Page Template -<http://wiki.zope.org/ZPT/FrontPage>`_ template specification, however -it is significantly faster. +templating engine. This templating engine complies largely with the +`Zope Page Template <http://wiki.zope.org/ZPT/FrontPage>`_ template +specification, however it is significantly faster. .. note:: The language definition documentation for Chameleon ZPT-style templates is available from `the Chameleon website @@ -27,7 +26,7 @@ it is significantly faster. <http://chameleon.repoze.org/docs/latest/>`_ for the Chameleon ZPT language specification. -Given that there is a :term:`chameleon.zpt` template named ``foo.pt`` +Given that there is a :term:`Chameleon` ZPT template named ``foo.pt`` in a directory in your application named ``templates``, you can render the template from a view like so: @@ -90,7 +89,7 @@ changing the content-type and status: A Sample Template ~~~~~~~~~~~~~~~~~ -Here's what a simple :term:`chameleon.zpt` template used under +Here's what a simple :term:`Chameleon` ZPT template used under :mod:`repoze.bfg` might look like: .. code-block:: xml @@ -113,7 +112,7 @@ Here's what a simple :term:`chameleon.zpt` template used under </html> Note the use of :term:`Genshi` -style ``${replacements}`` above. This -is one of the ways that :term:`chameleon.zpt` differs from standard +is one of the ways that :term:`Chameleon` ZPT differs from standard ZPT. The above template expects to find a ``project`` key in the set of keywords passed in to it via ``render_template`` or ``render_template_to_response``. Typical ZPT attribute-based syntax @@ -124,9 +123,9 @@ Using ZPT Macros in :mod:`repoze.bfg` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unlike Zope "browser views", :mod:`repoze.bfg` doesn't make any names -(such as ``context`` or ``view``) available to :term:`chameleon.zpt` -templates by default. Instead, it expects you to pass all the names -you need into the template. +(such as ``context`` or ``view``) available to :term:`Chameleon` ZPT +templates by default unless a :term:`renderer` is used. Instead, it +expects you to pass all the names you need into the template. One of the common needs in ZPT-based template is to one template's "macros" from within a different template. In Zope, this is typically diff --git a/docs/tutorials/gae/index.rst b/docs/tutorials/gae/index.rst index c48350dff..2cdb3bf81 100644 --- a/docs/tutorials/gae/index.rst +++ b/docs/tutorials/gae/index.rst @@ -12,7 +12,7 @@ This tutorial is written in terms of using the command line on a UNIX system; it should be possible to perform similar actions on a Windows system. -.. note:: :term:`chameleon.zpt` cannot easily be used on Google App +.. note:: :term:`Chameleon` cannot easily be used on Google App Engine due to GAE environment limitations, so the tutorial is presented in terms of using :term:`Jinja2` as the templating language in the generated BFG application. It is possible to *use* diff --git a/repoze/bfg/authentication.py b/repoze/bfg/authentication.py index 6989cb23f..d532a3a09 100644 --- a/repoze/bfg/authentication.py +++ b/repoze/bfg/authentication.py @@ -170,11 +170,11 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): ``callback`` - Default: ``None``. A callback passed the userid and the request, - expected to return None if the userid doesn't exist or a sequence - of group identifiers (possibly empty) if the user does exist. If - ``callback`` is None, the userid will be assumed to exist with no - groups. Optional. + Default: ``None``. A callback passed the userid and the + request, expected to return ``None`` if the userid doesn't + exist or a sequence of group identifiers (possibly empty) if + the user does exist. If ``callback`` is ``None``, the userid + will be assumed to exist with no groups. Optional. ``cookie_name`` diff --git a/repoze/bfg/authorization.py b/repoze/bfg/authorization.py index 7113ddd23..bc8b92b5e 100644 --- a/repoze/bfg/authorization.py +++ b/repoze/bfg/authorization.py @@ -12,10 +12,10 @@ from repoze.bfg.security import Everyone class ACLAuthorizationPolicy(object): """ An :term:`authorization policy` which consults an :term:`ACL` object attached to a :term:`context` to determine authorization - information about a a :term:`principal` or multiple principals. If - the context is part of a :term:`lineage`, the context's parents are - consulted for ACL information too. The following is true about this - security policy. + information about a a :term:`principal` or multiple principals. + If the context is part of a :term:`lineage`, the context's parents + are consulted for ACL information too. The following is true + about this security policy. - When checking whether the 'current' user is permitted (via the ``permits`` method), the security policy consults the @@ -27,14 +27,15 @@ class ACLAuthorizationPolicy(object): During this processing, if any ``Deny`` ACE is found matching any principal in ``principals``, stop processing by returning an - ``ACLDenied`` (equals False) immediately. If any ``Allow`` ACE - is found matching any principal, stop processing by returning an - ``ACLAllowed`` (equals True) immediately. If we exhaust the - context's lineage, and no ACE has explicitly permitted or denied - access, return an ``ACLDenied``. This differs from the - non-inheriting security policy (the ``ACLSecurityPolicy``) by - virtue of the fact that it does not stop looking for ACLs in the - object lineage after it finds the first one. + ``ACLDenied`` (equals ``False``) immediately. If any ``Allow`` + ACE is found matching any principal, stop processing by + returning an ``ACLAllowed`` (equals ``True``) immediately. If + we exhaust the context's lineage, and no ACE has explicitly + permitted or denied access, return an ``ACLDenied``. This + differs from the non-inheriting security policy (the + ``ACLSecurityPolicy``) by virtue of the fact that it does not + stop looking for ACLs in the object lineage after it finds the + first one. - When computing principals allowed by a permission via the ``principals_allowed_by_permission`` method, we compute the set @@ -92,7 +93,8 @@ class ACLAuthorizationPolicy(object): def principals_allowed_by_permission(self, context, permission): """ Return the set of principals explicitly granted the permission named ``permission`` according to the ACL directly - attached to the context context as well as inherited ACLs. """ + attached to the ``context`` as well as inherited ACLs based on + :term:`lineage`.""" allowed = set() for location in reversed(list(lineage(context))): diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index a0409bd06..b858f405a 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -75,11 +75,11 @@ class Configurator(object): If the ``registry`` argument is passed as a non-``None`` value, it must be an instance of the :mod:`repoze.bfg.registry.Registry` class representing the registry to configure. If ``registry`` is - ``None``, the configurator will create a Registry instance itself; - it will also perform some default configuration that would not - otherwise be done. After construction, the configurator may be - used to add configuration to the registry. The overall state of a - registry is called the 'configuration state'. + ``None``, the configurator will create a ``Registry`` instance + itself; it will also perform some default configuration that would + not otherwise be done. After construction, the configurator may + be used to add configuration to the registry. The overall state + of a registry is called the 'configuration state'. .. warning:: If a ``registry`` is passed to the Configurator constructor, all other constructor arguments except ``package`` @@ -109,9 +109,9 @@ class Configurator(object): If ``authorization_policy`` is passed, it should be an instance of an :term:`authorization policy`. - .. note:: A ``ConfigurationError`` will be raised if an - authorization policy is supplied without authentication policy - also being supplied (authorization requires authentication). + .. note:: A ``ConfigurationError`` will be raised when an + authorization policy is supplied without also supplying an + authentication policy (authorization requires authentication). If ``renderers`` is passed, it should be a list of tuples representing a set of :term:`renderer` factories which should be @@ -120,7 +120,9 @@ class Configurator(object): If ``debug_logger`` is not passed, a default debug logger that logs to stderr will be used. If it is passed, it should be an - instance of a ``logging.Logger`` (PEP 282) class. + instance of the ``logging.Logger`` (PEP 282) standard library + class. The debug logger is used by :mod:`repoze.bfg` itself to + log warnings and authorization debugging information. """ def __init__(self, registry=None, package=None, settings=None, root_factory=None, authentication_policy=None, @@ -250,9 +252,9 @@ class Configurator(object): def view(context, request): return {} else: - raise ConfigurationError('"view" attribute was not ' - 'specified and no renderer ' - 'specified') + raise ConfigurationError( + '"view" argument was not specified and no renderer ' + 'specified') derived_view = self._derive_view(view, attr=attr, renderer_name=renderer, @@ -273,14 +275,15 @@ class Configurator(object): # API def add_subscriber(self, subscriber, iface=None): - """Add an event subscriber for the event stream implied by - the supplied ``iface`` interface. The ``subscriber`` argument - represents a callable object; it will be called with a single - object ``event`` whenever :mod:`repoze.bfg` emits an event - associated with the ``iface``. Using the default ``iface`` - value, ``None`` will cause the subscriber to be registered for - all event types. See :ref:`events_chapter` for more - information about events and subscribers.""" + """Add an event :term:`subscriber` for the event stream + implied by the supplied ``iface`` interface. The + ``subscriber`` argument represents a callable object; it will + be called with a single object ``event`` whenever + :mod:`repoze.bfg` emits an :term:`event` associated with the + ``iface``. Using the default ``iface`` value, ``None`` will + cause the subscriber to be registered for all event types. See + :ref:`events_chapter` for more information about events and + subscribers.""" if iface is None: iface = (Interface,) if not isinstance(iface, (tuple, list)): @@ -337,33 +340,36 @@ class Configurator(object): configuration state. Arguments to ``add_view`` are broken down below into *predicate* arguments and *non-predicate* arguments. Predicate arguments narrow the circumstances in - which a view will be invoked; non-predicate arguments are + which the view callable will be invoked when a request is + presented to :mod:`repoze.bfg`; non-predicate arguments are informational. Non-Predicate Arguments view - The Python dotted-path name to the view callable. This - argument is required unless a ``renderer`` attribute also - exists. If a ``renderer`` argument is passed, this - attribute defaults to a view that returns an empty - dictionary (see :ref:`views_which_use_a_renderer`). + A reference to a :term:`view callable`. This argument is + required unless a ``renderer`` argument also exists. If a + ``renderer`` argument is passed, and a ``view`` argument is + not provided, the view callable defaults to a callable that + returns an empty dictionary (see + :ref:`views_which_use_a_renderer`). permission - The name of a *permission* that the user must possess in - order to call the view. See :ref:`view_security_section` - for more information about view security and permissions. + The name of a :term:`permission` that the user must possess + in order to invoke the :term:`view callable`. See + :ref:`view_security_section` for more information about view + security and permissions. attr The view machinery defaults to using the ``__call__`` method - of the view callable (or the function itself, if the view - callable is a function) to obtain a response dictionary. - The ``attr`` value allows you to vary the method attribute - used to obtain the response. For example, if your view was - a class, and the class has a method named ``index`` and you + of the :term:`view callable` (or the function itself, if the + view callable is a function) to obtain a response. The + ``attr`` value allows you to vary the method attribute used + to obtain the response. For example, if your view was a + class, and the class has a method named ``index`` and you wanted to use this method instead of the class' ``__call__`` method to return the response, you'd say ``attr="index"`` in the view configuration for the view. This is @@ -373,55 +379,58 @@ class Configurator(object): This is either a single string term (e.g. ``json``) or a string implying a path or :term:`resource specification` - (e.g. ``templates/views.pt``). If the renderer value is a - single term (does not contain a dot ``.``), the specified - term will be used to look up a renderer implementation, and - that renderer implementation will be used to construct a - response from the view return value. If the renderer term - contains a dot (``.``), the specified term will be treated - as a path, and the filename extension of the last element in - the path will be used to look up the renderer - implementation, which will be passed the full path. The - renderer implementation will be used to construct a response - from the view return value. - - Note that if the view itself returns a response (see + (e.g. ``templates/views.pt``) naming a :term:`renderer` + implementation. If the ``renderer`` value does not contain + a dot ``.``, the specified string will be used to look up a + renderer implementation, and that renderer implementation + will be used to construct a response from the view return + value. If the ``renderer`` value contains a dot (``.``), + the specified term will be treated as a path, and the + filename extension of the last element in the path will be + used to look up the renderer implementation, which will be + passed the full path. The renderer implementation will be + used to construct a :term:`response` from the view return + value. + + Note that if the view itself returns a :term:`response` (see :ref:`the_response`), the specified renderer implementation is never called. When the renderer is a path, although a path is usually just a simple relative pathname (e.g. ``templates/foo.pt``, implying that a template named"foo.pt" is in the "templates" - directory relative to the directory of *package* of the - Configurator), a path can be absolute, starting with a slash - on UNIX or a drive letter prefix on Windows. The path can - alternately be a :term:`resource specification` in the form + directory relative to the directory of the current + :term:`package` of the Configurator), a path can be + absolute, starting with a slash on UNIX or a drive letter + prefix on Windows. The path can alternately be a + :term:`resource specification` in the form ``some.dotted.package_name:relative/path``, making it possible to address template resources which live in a separate package. The ``renderer`` attribute is optional. If it is not - defined, the "null" renderer is assumed (no rendering is performed - and the value is passed back to the upstream BFG machinery - unmolested). + defined, the "null" renderer is assumed (no rendering is + performed and the value is passed back to the upstream BFG + machinery unmolested). wrapper - The :term:`view name` of another view declared elsewhere in - configuration which will receive the response body of this + The :term:`view name` of a different :term:`view + configuration` which will receive the response body of this view as the ``request.wrapped_body`` attribute of its own - request, and the response returned by this view as the - ``request.wrapped_response`` attribute of its own request. - Using a wrapper makes it possible to - "chain" views together to form a composite response. The response - of the outermost wrapper view will be returned to the user. The - wrapper view will be found as any view is found: see - :ref:`view_lookup_ordering`. The "best" wrapper view will be found - based on the lookup ordering: "under the hood" this wrapper view is - looked up via ``repoze.bfg.view.render_view_to_response(context, - request, 'wrapper_viewname')``. The context and request of a wrapper - view is the same context and request of the inner view. If this - attribute is unspecified, no view wrapping is done. + :term:`request`, and the :term:`response` returned by this + view as the ``request.wrapped_response`` attribute of its + own request. Using a wrapper makes it possible to "chain" + views together to form a composite response. The response + of the outermost wrapper view will be returned to the user. + The wrapper view will be found as any view is found: see + :ref:`view_lookup_ordering`. The "best" wrapper view will + be found based on the lookup ordering: "under the hood" this + wrapper view is looked up via + ``repoze.bfg.view.render_view_to_response(context, request, + 'wrapper_viewname')``. The context and request of a wrapper + view is the same context and request of the inner view. If + this attribute is unspecified, no view wrapping is done. Predicate Arguments @@ -442,17 +451,20 @@ class Configurator(object): route_name - *This argument services an advanced feature that isn't often - used unless you want to perform traversal *after* a route - has matched.* This value must match the ``name`` of a - ``<route>`` declaration (see :ref:`urldispatch_chapter`) + This value must match the ``name`` of a :term:`route + configuration` declaration (see :ref:`urldispatch_chapter`) that must match before this view will be called. Note that the ``route`` configuration referred to by ``route_name`` usually has a ``*traverse`` token in the value of its ``path``, representing a part of the path that will be used by traversal against the result of the route's :term:`root - factory`.See :ref:`hybrid_chapter` for more information on - using this advanced feature. + factory`. + + .. warning:: Using this argument services an advanced + feature that isn't often used unless you want to perform + traversal *after* a route has matched. See + :ref:`hybrid_chapter` for more information on using this + advanced feature. request_type @@ -474,22 +486,23 @@ class Configurator(object): This value can be any string. A view declaration with this argument ensures that the view will only be called when the - request has a key in the ``request.params`` dictionary (an - HTTP ``GET`` or ``POST`` variable) that has a name which - matches the supplied value. If the value supplied to the - attribute has a ``=`` sign in it, e.g. ``request_params="foo=123"``, - then the key (``foo``) must both exist in the ``request.params`` - dictionary, and the value must match the right hand side of the - expression (``123``) for the view to "match" the current request. + :term:`request` has a key in the ``request.params`` + dictionary (an HTTP ``GET`` or ``POST`` variable) that has a + name which matches the supplied value. If the value + supplied has a ``=`` sign in it, + e.g. ``request_params="foo=123"``, then the key (``foo``) + must both exist in the ``request.params`` dictionary, *and* + the value must match the right hand side of the expression + (``123``) for the view to "match" the current request. containment - This value should be a reference to a Python class that a - graph traversal parent object of the :term:`context` must be - an instance of or :term:`interface` that a parent object - must provide in order for this view to be found and called. - Your models must be"location-aware" to use this feature. See - :ref:`location_aware` for more information about location-awareness. + This value should be a reference to a Python class or + :term:`interface` that a parent object in the + :term:`lineage` must provide in order for this view to be + found and called. Your models must be"location-aware" to + use this feature. See :ref:`location_aware` for more + information about location-awareness. xhr @@ -503,7 +516,7 @@ class Configurator(object): accept - The value of this attribute represents a match query for one + The value of this argument represents a match query for one or more mimetypes in the ``Accept`` HTTP request header. If this value is specified, it must be in one of the following forms: a mimetype match token in the form ``text/plain``, a @@ -518,27 +531,25 @@ class Configurator(object): name/value pair. If the value contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The - *value* of an attribute that represent a name/value pair - should be a regular expression. If the value does not - contain a colon, the entire value will be considered to be - the header name (e.g. ``If-Modified-Since``). If the value - evaluates to a header name only without a value, the header - specified by the name must be present in the request for - this predicate to be true. If the value evaluates to a - header name/value pair, the header specified by the name - must be present in the request *and* the regular expression - specified as the value must match the header value. Whether - or not the value represents a header name or a header - name/value pair, the case of the header name is not - significant. + value portion should be a regular expression. If the value + does not contain a colon, the entire value will be + considered to be the header name + (e.g. ``If-Modified-Since``). If the value evaluates to a + header name only without a value, the header specified by + the name must be present in the request for this predicate + to be true. If the value evaluates to a header name/value + pair, the header specified by the name must be present in + the request *and* the regular expression specified as the + value must match the header value. Whether or not the value + represents a header name or a header name/value pair, the + case of the header name is not significant. path_info This value represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment variable. If the regex matches, this predicate will be - true. - + ``True``. """ if not view: @@ -658,11 +669,9 @@ class Configurator(object): configuration` to be used to specify a :term:`view callable` that will be invoked when this route matches. The arguments to this method are divided into *predicate*, *non-predicate*, - and *view-related* types. Predicate arguments narrow the - circumstances in which a route will be match a request; - non-predicate arguments are informational. View-related types - are used to modify the - + and *view-related* types. :term:`Route predicate` arguments + narrow the circumstances in which a route will be match a + request; non-predicate arguments are informational. Non-Predicate Arguments @@ -670,15 +679,15 @@ class Configurator(object): The name of the route, e.g. ``myroute``. This attribute is required. It must be unique among all defined routes in a given - configuration. + application. factory - A reference to a Python object (often a function) that will - generate a :mod:`repoze.bfg` context object when this route - matches. e.g. ``mypackage.models.MyFactoryClass``. If this - argument is not specified, a default root factory will be - used. + A reference to a Python object (often a function or a class) + that will generate a :mod:`repoze.bfg` :term:`context` + object when this route matches. For example, + ``mypackage.models.MyFactoryClass``. If this argument is + not specified, a default root factory will be used. Predicate Arguments @@ -686,7 +695,8 @@ class Configurator(object): The path of the route e.g. ``ideas/:idea``. This argument is required. See :ref:`route_path_pattern_syntax` for - information about the syntax of route paths. + information about the syntax of route paths. If the path + doesn't match the current URL, route matching continues. xhr @@ -696,23 +706,23 @@ class Configurator(object): ``X-Requested-With``) header for this route to match. This is useful for detecting AJAX requests issued from jQuery, Prototype and other Javascript libraries. If this predicate - returns false, route matching continues. + returns ``False``, route matching continues. request_method A string representing an HTTP method name, e.g. ``GET``, ``POST``, ``HEAD``, ``DELETE``, ``PUT``. If this argument is not specified, this route will match if the request has - *any* request method. If this predicate returns false, + *any* request method. If this predicate returns ``False``, route matching continues. path_info This value represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment - variable. If the regex matches, this predicate will be - true. If this predicate returns false, route matching - continues. + variable. If the regex matches, this predicate will return + ``True``. If this predicate returns ``False``, route + matching continues. request_param @@ -726,17 +736,17 @@ class Configurator(object): (``foo``) must both exist in the ``request.params`` dictionary, and the value must match the right hand side of the expression (``123``) for the route to "match" the current request. If this predicate - returns false, route matching continues. + returns ``False``, route matching continues. header - This value represents an HTTP header name or a header - name/value pair. If the value contains a ``:`` (colon), it - will be considered a name/value pair - (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). The - *value* of such a pair should be a regular expression. If - the value does not contain a colon, the entire value will be - considered to be the header name + This argument represents an HTTP header name or a header + name/value pair. If the argument contains a ``:`` (colon), + it will be considered a name/value pair + (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If + the value contains a colon, the value portion should be a + regular expression. If the value does not contain a colon, + the entire value will be considered to be the header name (e.g. ``If-Modified-Since``). If the value evaluates to a header name only without a value, the header specified by the name must be present in the request for this predicate @@ -746,7 +756,7 @@ class Configurator(object): value must match the header value. Whether or not the value represents a header name or a header name/value pair, the case of the header name is not significant. If this - predicate returns false, route matching continues. + predicate returns ``False``, route matching continues. accept @@ -758,7 +768,7 @@ class Configurator(object): match-all wildcard mimetype match token in the form ``*/*``. If any of the forms matches the ``Accept`` header of the request, this predicate will be true. If this predicate - returns false, route matching continues. + returns ``False``, route matching continues. View-Related Arguments @@ -829,12 +839,12 @@ class Configurator(object): view_containment - This a reference to a Python object representing the class - that a graph traversal parent object of the :term:`context` - must be an instance of (or :term:`interface` that a parent - object must provide) in order for this view to be found and - called. Your models must be "location-aware" to use this feature. - See :ref:`location_aware` for more information about + This value should be a reference to a Python class or + :term:`interface` that a parent object in the + :term:`lineage` must provide in order for the view related + to this route to be found and called. Your models must be + 'location-aware' to use this feature. See + :ref:`location_aware` for more information about location-awareness. If the ``view`` argument is not provided, this argument has no @@ -902,7 +912,7 @@ class Configurator(object): def scan(self, package=None, _info=u''): """ Scan a Python package and any of its subpackages for - objects marked with configuration decorators such as + objects marked with :term:`configuration decoration` such as ``@bfg_view``. Any decorated object found will influence the current configuration state. diff --git a/repoze/bfg/events.py b/repoze/bfg/events.py index 14e47ca3f..75a5aec5a 100644 --- a/repoze/bfg/events.py +++ b/repoze/bfg/events.py @@ -6,19 +6,20 @@ from repoze.bfg.interfaces import INewResponse from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent class NewRequest(object): - """ An instance of this class is emitted as an event whenever - repoze.bfg begins to process a new request. The instance has an - attribute, ``request``, which is the request object. This class - implements the ``repoze.bfg.interfaces.INewRequest`` interface.""" + """ An instance of this class is emitted as an :term:`event` + whenever repoze.bfg begins to process a new request. The instance + has an attribute, ``request``, which is a :term:`request` object. + This class implements the ``repoze.bfg.interfaces.INewRequest`` + interface.""" implements(INewRequest) def __init__(self, request): self.request = request class NewResponse(object): - """ An instance of this class is emitted as an event whenever any - repoze.bfg view returns a response.. The instance has an - attribute, ``response``, which is the response object returned by - the view. This class implements the + """ An instance of this class is emitted as an :term:`event` + whenever any repoze.bfg view returns a :term:`response`.. The + instance has an attribute, ``response``, which is the response + object returned by the view. This class implements the ``repoze.bfg.interfaces.INewResponse`` interface.""" implements(INewResponse) def __init__(self, response): @@ -26,23 +27,24 @@ class NewResponse(object): class AfterTraversal(object): implements(IAfterTraversal) - """ An instance of this class is emitted as an event after the - repoze.bfg router performs traversal (but before any view code is - executed). The instance has an attribute, ``request``, which is - the request object returned by the view. Notably, the request - object will have an attribute named ``context``, which is the - context that will be provided to the view which will eventually be - called, as well as other attributes defined by the traverser. - This class implements the - ``repoze.bfg.interfaces.IAfterTraversal`` interface.""" + """ An instance of this class is emitted as an :term:`event` after + the repoze.bfg :term:`router` performs traversal but before any + view code is executed. The instance has an attribute, + ``request``, which is the request object generated by + :mod:`repoze.bfg`. Notably, the request object will have an + attribute named ``context``, which is the context that will be + provided to the view which will eventually be called, as well as + other attributes defined by the traverser. This class implements + the ``repoze.bfg.interfaces.IAfterTraversal`` interface.""" def __init__(self, request): self.request = request class WSGIApplicationCreatedEvent(object): - """ An instance of this class is emitted as an event whenever a - ``repoze.bfg`` application starts. The instance has an attribute, - ``app``, which is an instance of the ``repoze.bfg.router.Router`` - class that will handle WSGI requests. This class implements the + """ An instance of this class is emitted as an :term:`event` when + the ``make_wsgi_app`` method of a :term:`Configurator` is called). + The instance has an attribute, ``app``, which is an instance of + the ``repoze.bfg.router.Router`` class that will handle WSGI + requests. This class implements the ``repoze.bfg.interfaces.IWSGIApplicationCreatedEvent`` interface.""" implements(IWSGIApplicationCreatedEvent) def __init__(self, app): diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py index 479e3a751..553f6775f 100644 --- a/repoze/bfg/interfaces.py +++ b/repoze/bfg/interfaces.py @@ -28,6 +28,10 @@ class IWSGIApplicationCreatedEvent(Interface): class IRequest(Interface): """ Request type interface attached to all request objects """ +class IRouteRequest(Interface): + """ *internal only* interface used as in a utility lookup to find + route-specific interfaces. Not an API.""" + class IResponse(Interface): status = Attribute('WSGI status code of response') headerlist = Attribute('List of response headers') @@ -65,10 +69,6 @@ class IAuthorizationPolicy(Interface): """ Return a set of principal identifiers allowed by the permission """ -class IRouteRequest(Interface): - """ *internal only* interface used as in a utility lookup to find - route-specific interfaces. Not an API.""" - class IResponseFactory(Interface): """ A utility which generates a response factory """ def __call__(): @@ -102,15 +102,15 @@ class IMultiView(ISecuredView): """ Add a view to the multiview. """ class IRootFactory(Interface): - def __call__(environ): - """ Return a root object based on the WSGI environ """ + def __call__(request): + """ Return a root object based on the request """ class IDefaultRootFactory(Interface): - def __call__(environ): + def __call__(request): """ Return the *default* root object for an application """ class ITraverser(Interface): - def __call__(environ): + def __call__(request): """ Return a dictionary with (at least) the keys ``root``, ``context``, ``view_name``, ``subpath``, ``traversed``, ``virtual_root``, and ``virtual_root_path``. These values are @@ -143,7 +143,7 @@ class IRenderer(Interface): unicode object useful as a response body). Values computed by the system are passed by the system in the ``system`` parameter, which is a dictionary. Keys in the dictionary - include: ``view`` (the view object that returned the value), + include: ``view`` (the view callable that returned the value), ``renderer_name`` (the template name or simple name of the renderer), ``context`` (the context object passed to the view), and ``request`` (the request object passed to the @@ -172,7 +172,8 @@ class IRouter(Interface): class ISettings(Interface): """ Runtime settings utility for repoze.bfg; represents the - deployment settings for the application""" + deployment settings for the application. Implements a mapping + interface.""" # this interface, even if it becomes unused within BFG, is imported by # other packages (such as repoze.bfg.traversalwrapper) @@ -188,7 +189,20 @@ ILogger = IDebugLogger # b/c class IRoutesMapper(Interface): """ Interface representing a Routes ``Mapper`` object """ - + def get_routes(): + """ Return a sequence of Route objects registered in the mapper.""" + + def connect(path, name, factory=None, predicates=()): + """ Add a new route. """ + + def generate(name, kw): + """ Generate a URL using the route named ``name`` with the + keywords implied by kw""" + + def __call__(request): + """ Return a matchdict for the request; the ``route`` key will + either be a Route object or ``None`` if no route matched.""" + class IForbiddenView(Interface): """ A utility which returns an IResponse as the result of the denial of a view invocation by a security policy.""" diff --git a/repoze/bfg/location.py b/repoze/bfg/location.py index 8e8eff671..fd3bd3792 100644 --- a/repoze/bfg/location.py +++ b/repoze/bfg/location.py @@ -12,18 +12,14 @@ # ############################################################################## -"""Location support loosely based from ``zope.location``, but without -``zope.security`` support or proxy support, neither of which is used -by ``repoze.bfg`` -""" - def inside(model1, model2): """Is ``model1`` 'inside' ``model2``? Return ``True`` if so, else ``False``. - ``model1`` is 'inside' ``model2`` if ``model2`` is a `location - ancestor` of ``model1``. It is a location ancestor if its parent - (or one of its parent's parents, etc.) is an ancestor. + ``model1`` is 'inside' ``model2`` if ``model2`` is a + :term:`lineage` ancestor of ``model1``. It is a lineage ancestor + if its parent (or one of its parent's parents, etc.) is an + ancestor. """ while model1 is not None: if model1 is model2: @@ -34,14 +30,14 @@ def inside(model1, model2): def lineage(model): """ - Return a generator representing the model lineage. The generator - first returns ``model`` unconditionally. Then, if ``model`` - supplies a ``__parent__`` attribute, return the object represented - by ``model.__parent__``. If *that* object has a ``__parent__`` - attribute, return that object's parent, and so on, until the - object being inspected either has no ``__parent__`` attribute or - which has a ``__parent__`` attribute of ``None``. For example, if - the object tree is:: + Return a generator representing the :term:`lineage` of the + ``model``. The generator first returns ``model`` unconditionally. + Then, if ``model`` supplies a ``__parent__`` attribute, return the + object represented by ``model.__parent__``. If *that* object has + a ``__parent__`` attribute, return that object's parent, and so + on, until the object being inspected either has no ``__parent__`` + attribute or which has a ``__parent__`` attribute of ``None``. + For example, if the object tree is:: thing1 = Thing() thing2 = Thing() diff --git a/repoze/bfg/path.py b/repoze/bfg/path.py index 2c1c0f4e3..30c72b436 100644 --- a/repoze/bfg/path.py +++ b/repoze/bfg/path.py @@ -3,7 +3,6 @@ import pkg_resources import sys def caller_path(path, level=2): - """ Return an absolute path """ if not os.path.isabs(path): module = caller_module(level+1) prefix = package_path(module) diff --git a/repoze/bfg/request.py b/repoze/bfg/request.py index a7f4f32ba..f3443dfa2 100644 --- a/repoze/bfg/request.py +++ b/repoze/bfg/request.py @@ -7,9 +7,9 @@ from webob import Request as WebobRequest from repoze.bfg.interfaces import IRequest def make_request_ascii(event): - """ An event handler that causes the request charset to be ASCII; - used as an INewRequest subscriber so code written before 0.7.0 can - continue to work without a change""" + """ An function that is useful as a ``INewRequest`` :term:`event` + :term:`subscriber` that causes the request charset to be ASCII so + code written before 0.7.0 can continue to work without a change""" request = event.request request.charset = None diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index b3f41442e..deffa4e17 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -29,7 +29,6 @@ from repoze.bfg.view import default_notfound_view make_app # prevent pyflakes from complaining class Router(object): - """ The main repoze.bfg WSGI application. """ implements(IRouter) debug_notfound = False @@ -50,10 +49,11 @@ class Router(object): def __call__(self, environ, start_response): """ - Accept ``environ`` and ``start_response``; route requests to - ``repoze.bfg`` views based on registrations within the - application registry; call ``start_response`` and return an - iterable. + Accept ``environ`` and ``start_response``; create a + :term:`request` and route the request to a :mod:`repoze.bfg` + view based on introspection of :term:`view configuration` + within the application registry; call ``start_response`` and + return an iterable. """ registry = self.registry has_listeners = registry.has_listeners diff --git a/repoze/bfg/scripting.py b/repoze/bfg/scripting.py index bf2423a8c..3e743524a 100644 --- a/repoze/bfg/scripting.py +++ b/repoze/bfg/scripting.py @@ -7,8 +7,9 @@ def get_root(app, request=None): ``closer`` returned is a callable (accepting no arguments) that should be called when your scripting application is finished using the root. If ``request`` is not None, it is used as the request - passed to the BFG application root factory. A faux request is - constructed and passed to the root factory if ``request`` is None.""" + passed to the :mod:`repoze.bfg` application root factory. A + request is constructed and passed to the root factory if + ``request`` is None.""" registry = app.registry if request is None: request = Request.blank('/') diff --git a/repoze/bfg/security.py b/repoze/bfg/security.py index 56bcf5e52..f7ed8e050 100644 --- a/repoze/bfg/security.py +++ b/repoze/bfg/security.py @@ -60,8 +60,8 @@ def has_permission(permission, context, request): def authenticated_userid(request): """ Return the userid of the currently authenticated user or - ``None`` if there is no authentication policy in effect or there - is no currently authenticated user. """ + ``None`` if there is no :term:`authentication policy` in effect or + there is no currently authenticated user.""" try: reg = request.registry except AttributeError: @@ -73,11 +73,11 @@ def authenticated_userid(request): return policy.authenticated_userid(request) def effective_principals(request): - """ Return the list of 'effective' principal identifiers for the - request. This will include the userid of the currently - authenticated user if a user is currently authenticated. If no - authentication policy is in effect, this will return an empty - sequence.""" + """ Return the list of 'effective' :term:`principal` identifiers + for the ``request``. This will include the userid of the + currently authenticated user if a user is currently + authenticated. If no :term:`authentication policy` is in effect, + this will return an empty sequence.""" try: reg = request.registry except AttributeError: @@ -89,16 +89,17 @@ def effective_principals(request): return policy.effective_principals(request) def principals_allowed_by_permission(context, permission): - """ Provided a context (a model object), and a permission (a - string or unicode object), return a sequence of principal ids that - possess the permission in the context. If no authorization policy - is in effect, this will return a sequence with the single value + """ Provided a ``context`` (a model object), and a ``permission`` + (a string or unicode object), if a :term:`authorization policy` is + in effect, return a sequence of :term:`principal` ids that possess + the permission in the ``context``. If no authorization policy is + in effect, this will return a sequence with the single value representing ``Everyone`` (the special principal identifier representing all principals). - .. note:: even if an authorization policy *is* in effect, some - (exotic) authorization policies may not implement the required - machinery for this function; those will cause a + .. note:: even if an :term:`authorization policy` is in effect, + some (exotic) authorization policies may not implement the + required machinery for this function; those will cause a ``NotImplementedError`` exception to be raised when this function is invoked. """ @@ -110,11 +111,11 @@ def principals_allowed_by_permission(context, permission): def view_execution_permitted(context, request, name=''): """ If the view specified by ``context`` and ``name`` is protected - by a permission, check the permission associated with the view - using the effective authentication/authorization policies and the - ``request``. Return a boolean result. If no authentication - policy is in effect, or if the view is not protected by a - permission, return True.""" + by a :term:`permission`, check the permission associated with the + view using the effective authentication/authorization policies and + the ``request``. Return a boolean result. If no + :term:`authorization policy` is in effect, or if the view is not + protected by a permission, return True.""" try: reg = request.registry except AttributeError: @@ -141,10 +142,10 @@ def remember(request, principal, **kw): response.headerlist.extend(headers) return response - If no authentication policy is in use, this function will always - return an empty sequence. If used, the composition and meaning of - ``**kw`` must be agreed upon by the calling code and the effective - authentication policy.""" + If no :term:`authentication policy` is in use, this function will + always return an empty sequence. If used, the composition and + meaning of ``**kw`` must be agreed upon by the calling code and + the effective authentication policy.""" try: reg = request.registry except AttributeError: @@ -168,8 +169,8 @@ def forget(request): response.headerlist.extend(headers) return response - If no authentication policy is in use, this function will always - return an empty sequence.""" + If no :term:`authentication policy` is in use, this function will + always return an empty sequence.""" try: reg = request.registry except AttributeError: diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py index 127f54283..428f1c11f 100644 --- a/repoze/bfg/testing.py +++ b/repoze/bfg/testing.py @@ -40,17 +40,17 @@ zcml_configure # prevent pyflakes from complaining _marker = object() def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True): - """ Registers a dummy ``repoze.bfg`` security policy (actually, a - pair of policies: an authorization policy and an authentication - policy) using the userid ``userid`` and the group ids - ``groupids``. If ``permissive`` is true, a 'permissive' security - policy is registered; this policy allows all access. If - ``permissive`` is false, a nonpermissive security policy is - registered; this policy denies all access. This function is most - useful when testing code that uses the ``repoze.bfg.security`` - APIs named ``has_permission``, ``authenticated_userid``, - ``effective_principals``, ``principals_allowed_by_permission``, - and so on. + """ Registers a a pair of dummy :mod:`repoze.bfg` security + policies: an :term:`authorization policy` and an + :term:`authentication policy`) using the userid ``userid`` and the + group ids ``groupids``. If ``permissive`` is true, a 'permissive' + authorization policy is registered; this policy allows all access. + If ``permissive`` is false, a nonpermissive authorization policy + is registered; this policy denies all access. This function is + most useful when testing code that uses the + ``repoze.bfg.security`` APIs named ``has_permission``, + ``authenticated_userid``, ``effective_principals``, + ``principals_allowed_by_permission``, and so on. """ policy = DummySecurityPolicy(userid, groupids, permissive) reg = get_current_registry() @@ -58,7 +58,8 @@ def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True): reg.registerUtility(policy, IAuthenticationPolicy) def registerModels(models): - """ Registers a dictionary of models. This is most useful for + """ Registers a dictionary of models that can be resolved via + ``repoze.bfg.traversal.find_model``. This is most useful for testing code that wants to call the ``repoze.bfg.traversal.find_model`` API. The ``find_model`` API is called with a path as one of its arguments. If the dictionary @@ -83,13 +84,14 @@ def registerModels(models): return models def registerEventListener(event_iface=Interface): - """ Registers an event listener (aka 'subscriber') listening for - events of the type ``event_iface`` and returns a list which is - appended to by the subscriber. When an event is dispatched that - matches ``event_iface``, that event will be appended to the list. - You can then compare the values in the list to expected event - notifications. This method is useful when testing code that wants - to call ``zope.component.event.dispatch`` or + """ Registers an :term:`event` listener (aka :term:`subscriber`) + listening for events of the type ``event_iface`` and returns a + list which is appended to by the subscriber. When an event is + dispatched that matches ``event_iface``, that event will be + appended to the list. You can then compare the values in the list + to expected event notifications. This method is useful when + testing code that wants to call ``registry.notify``, + ``zope.component.event.dispatch`` or ``zope.component.event.objectEventNotify``.""" L = [] def subscriber(*event): @@ -98,7 +100,7 @@ def registerEventListener(event_iface=Interface): return L def registerTemplateRenderer(path, renderer=None): - """ Register a 'template renderer' at ``path`` (usually a relative + """ Register a template tenderer at ``path`` (usually a relative filename ala ``templates/foo.pt``) and return the renderer object. If the ``renderer`` argument is None, a 'dummy' renderer will be used. This function is useful when testing code that calls the @@ -114,16 +116,16 @@ registerDummyRenderer = registerTemplateRenderer def registerView(name, result='', view=None, for_=(Interface, Interface), permission=None): - """ Registers ``repoze.bfg`` view function under the name + """ Registers a :mod:`repoze.bfg` view callable under the name ``name``. The view will return a webob Response object with the ``result`` value as its body attribute. To gain more control, if you pass in a non-None ``view``, this view function will be used instead of an automatically generated view function (and - ``result`` is not used). To protect the view using a permission, - pass in a non-``None`` value as ``permission``. This permission - will be checked by any existing security policy when view - execution is attempted. This function is useful when dealing with - code that wants to call, + ``result`` is not used). To protect the view using a + :term:`permission`, pass in a non-``None`` value as + ``permission``. This permission will be checked by any existing + security policy when view execution is attempted. This function + is useful when dealing with code that wants to call, e.g. ``repoze.bfg.view.render_view_to_response``.""" if view is None: def view(context, request): @@ -144,20 +146,21 @@ def registerView(name, result='', view=None, for_=(Interface, Interface), def registerViewPermission(name, result=True, viewpermission=None, for_=(Interface, Interface)): - """ Registers a ``repoze.bfg`` 'view permission' object under - the name ``name``. The view permission return a result - denoted by the ``result`` argument. If ``result`` is True, a + """ Registers a :mod:`repoze.bfg` 'view permission' object under + the name ``name``. The view permission return a result denoted by + the ``result`` argument. If ``result`` is True, a ``repoze.bfg.security.Allowed`` object is returned; else a - ``repoze.bfg.security.Denied`` object is returned. To gain - more control, if you pass in a non-None ``viewpermission``, - this view permission object will be used instead of an - automatically generated view permission (and ``result`` is not - used). This method is useful when dealing with code that - wants to call, e.g. ``repoze.bfg.view.view_execution_permitted``. - Note that view permissions are not checked unless a security - policy is in effect (see ``registerSecurityPolicy``). - - **This function was deprecated in repoze.bfg 1.1.** + ``repoze.bfg.security.Denied`` object is returned. To gain more + control, if you pass in a non-None ``viewpermission``, this view + permission object will be used instead of an automatically + generated view permission (and ``result`` is not used). This + method is useful when dealing with code that wants to call, + e.g. ``repoze.bfg.view.view_execution_permitted``. Note that view + permissions are not checked unless a security policy is in effect + (see ``registerSecurityPolicy``). + + .. warning:: This function was deprecated in repoze.bfg 1.1; it + has no real effect in 1.2+. """ if result is True: result = Allowed('message') @@ -180,19 +183,20 @@ deprecated('registerViewPermission', '``permission`` argument.') def registerUtility(impl, iface=Interface, name=''): - """ Register a Zope component architecture utility component. + """ Register a utility component. ``impl`` is the implementation of the utility. ``iface`` is the interface type ``zope.interface.Interface`` by default. ``name`` - is the empty string by default. See `The ZCA book - <http://www.muthukadan.net/docs/zca.html>`_ for more information - about ZCA utilities.""" + is the empty string by default. + + See `The ZCA book <http://www.muthukadan.net/docs/zca.html>`_ for + more information about ZCA utilities.""" reg = get_current_registry() reg.registerUtility(impl, iface, name=name) return impl def registerAdapter(impl, for_=Interface, provides=Interface, name=''): - """ Register a Zope component architecture adapter component. + """ Register an adapter component. ``impl`` is the implementation of the component (often a class). ``for_`` is the ``for`` interface type @@ -201,9 +205,10 @@ def registerAdapter(impl, for_=Interface, provides=Interface, name=''): to underlying ZCA registerAdapter API. ``name`` is the empty string by default. ``provides`` is the ZCA provides interface, also ``zope.interface.Interface`` by default. ``name`` is the - name of the adapter, the empty string by default. See `The ZCA - book <http://www.muthukadan.net/docs/zca.html>`_ for more - information about ZCA adapters.""" + name of the adapter, the empty string by default. + + See `The ZCA book <http://www.muthukadan.net/docs/zca.html>`_ for + more information about ZCA adapters.""" reg = get_current_registry() if not isinstance(for_, (tuple, list)): for_ = (for_,) @@ -211,16 +216,17 @@ def registerAdapter(impl, for_=Interface, provides=Interface, name=''): return impl def registerSubscriber(subscriber, iface=Interface): - """ Register a Zope component architecture subscriber component. + """ Register a subscriber component. ``subscriber`` is the implementation of the component (often a function). ``iface`` is the interface type the subscriber will be registered for (``zope.interface.Interface`` by default). If ``iface`` is not a tuple or list, it will be converted to a - one-tuple before being passed to underlying zca registerHandler - query. See `The ZCA book - <http://www.muthukadan.net/docs/zca.html>`_ for more information - about ZCA subscribers.""" + one-tuple before being passed to underlying ZCA registerHandler + query. + + See `The ZCA book <http://www.muthukadan.net/docs/zca.html>`_ for + more information about ZCA subscribers.""" reg = get_current_registry() if not isinstance(iface, (tuple, list)): iface = (iface,) @@ -231,9 +237,10 @@ def registerTraverser(traverser, for_=Interface): return registerAdapter(traverser, for_, ITraverser) def registerRoute(path, name, factory=None): - """ Register a new route using a path (e.g. ``:pagename``), a name - (e.g. 'home'), and an optional root factory. This is useful for - testing code that calls e.g. ``route_url``. + """ Register a new :term:`route` using a path + (e.g. ``:pagename``), a name (e.g. 'home'), and an optional root + factory. This is useful for testing code that calls + e.g. ``route_url``. .. note:: This API was added in :mod:`repoze.bfg` version 1.1. """ @@ -338,10 +345,10 @@ class DummySecurityPolicy: class DummyTemplateRenderer: """ An instance of this class is returned from - ``registerTemplateRenderer``. It has a helper function (``assert_``) - that makes it possible to make an assertion which compares data - passed to the renderer by the view function against expected - key/value pairs. + ``registerTemplateRenderer``. It has a helper function + (``assert_``) that makes it possible to make an assertion which + compares data passed to the renderer by the view function against + expected key/value pairs. """ def __init__(self, string_response=''): @@ -467,10 +474,11 @@ class DummyModel: return inst class DummyRequest: - """ A dummy request object (imitates a :term:`WebOb` ``Request`` object). + """ A dummy request object (imitates a :term:`request` object). - The ``params``, ``environ``, ``headers``, ``path``, and ``cookies`` - arguments correspond to their WebOb equivalents. + The ``params``, ``environ``, ``headers``, ``path``, and + ``cookies`` arguments correspond to their :term`WebOb` + equivalents. The ``post`` argument, if passed, populates the request's ``POST`` attribute, but *not* ``params``, in order to allow testing diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index 43680be0d..051a4c34c 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -81,8 +81,8 @@ def find_interface(model, class_or_interface): Return the first object found in the parent chain of ``model`` which, a) if ``class_or_interface`` is a Python class object, is an instance of the class or any subclass of that class or b) if - ``class_or_interface`` is a Zope interface, provides the specified - interface. Return ``None`` if no object providing + ``class_or_interface`` is a :term:`interface`, provides the + specified interface. Return ``None`` if no object providing ``interface_or_class`` can be found in the parent chain. The ``model`` passed in *must* be :term:`location`-aware. """ @@ -149,67 +149,70 @@ def traverse(model, path): A definition of each value in the returned dictionary: - - ``context``: The context (a 'model' object) found via traversal - or url dispatch. If the ``path`` passed in is the empty string, - the value of the ``model`` argument passed to this function is - returned. + - ``context``: The :term:`context` (a :term:`model` object) found + via traversal or url dispatch. If the ``path`` passed in is the + empty string, the value of the ``model`` argument passed to this + function is returned. - - ``root``: The model object at which traversal begins. If the - ``model`` passed in was found via url dispatch or if the + - ``root``: The model object at which :term:`traversal` begins. + If the ``model`` passed in was found via url dispatch or if the ``path`` passed in was relative (non-absolute), the value of the ``model`` argument passed to this function is returned. - - ``view_name``: The 'view name' found during traversal or url - dispatch; if the ``model`` was found via traversal, this is - usually a representation of the path segment which directly - follows the path to the ``context`` in the ``path``. The - ``view_name`` will be a Unicode object or the empty string. The - ``view_name`` will be the empty string if there is no element - which follows the ``context`` path. An example: if the path - passed is ``/foo/bar``, and a context object is found at - ``/foo`` (but not at ``/foo/bar``), the 'view name' will be - ``u'bar'``. If the ``model`` was found via urldispatch, the - view_name will be the name the route found was registered with. - - - ``subpath``: For a ``model`` found via traversal, this is a - sequence of path segments found in the ``path`` that follow the - ``view_name`` (if any). Each of these items is a Unicode + - ``view_name``: The :term:`view name` found during + :term:`traversal` or :term:`url dispatch`; if the ``model`` was + found via traversal, this is usually a representation of the + path segment which directly follows the path to the ``context`` + in the ``path``. The ``view_name`` will be a Unicode object or + the empty string. The ``view_name`` will be the empty string if + there is no element which follows the ``context`` path. An + example: if the path passed is ``/foo/bar``, and a context + object is found at ``/foo`` (but not at ``/foo/bar``), the 'view + name' will be ``u'bar'``. If the ``model`` was found via + urldispatch, the view_name will be the name the route found was + registered with. + + - ``subpath``: For a ``model`` found via :term:`traversal`, this + is a sequence of path segments found in the ``path`` that follow + the ``view_name`` (if any). Each of these items is a Unicode object. If no path segments follow the ``view_name``, the - subpath will be the empty list. An example: if the path passed - is ``/foo/bar/baz/buz``, and a context object is found at + subpath will be the empty sequence. An example: if the path + passed is ``/foo/bar/baz/buz``, and a context object is found at ``/foo`` (but not ``/foo/bar``), the 'view name' will be - ``u'bar'`` and the subpath will be ``[u'baz', u'buz']``. For a - ``model`` found via url dispatch, the subpath will be a sequence - of values discerned from ``*subpath`` in the route pattern - matched or the empty sequence. + ``u'bar'`` and the :term:`subpath` will be ``[u'baz', u'buz']``. + For a ``model`` found via url dispatch, the subpath will be a + sequence of values discerned from ``*subpath`` in the route + pattern matched or the empty sequence. - ``traversed``: The sequence of path elements traversed from the - root to find the ``context`` object. Each of these items is a - Unicode object. If no path segments were traversed to find the - ``context`` object (e.g. if the ``path`` provided is the empty - string), the ``traversed`` value will be the empty list. If the - ``model`` is a model found via urldispatch, traversed will be - None. + root to find the ``context`` object during :term:`traversal`. + Each of these items is a Unicode object. If no path segments + were traversed to find the ``context`` object (e.g. if the + ``path`` provided is the empty string), the ``traversed`` value + will be the empty sequence. If the ``model`` is a model found + via :term:`url dispatch`, traversed will be None. - ``virtual_root``: A model object representing the 'virtual' root - of the object graph being traversed. See - :ref:`vhosting_chapter` for a definition of the virtual root + of the object graph being traversed during :term:`traversal`. + See :ref:`vhosting_chapter` for a definition of the virtual root object. If no virtual hosting is in effect, and the ``path`` passed in was absolute, the ``virtual_root`` will be the - *physical* root object (the object at which traversal begins). - If the ``model`` passed in was found via URL dispatch or if the - ``path`` passed in was relative, the ``virtual_root`` will - always equal the ``root`` object (the model passed in). - - - ``virtual_root_path`` -- If traversal was used to find the - ``model``, this will be the sequence of path elements traversed - to find the ``virtual_root`` object. Each of these items is a - Unicode object. If no path segments were traversed to find the - ``virtual_root`` object (e.g. if virtual hosting is not in - effect), the ``traversed`` value will be the empty list. If url - dispatch was used to find the ``model``, this will be None. + *physical* root object (the object at which :term:`traversal` + begins). If the ``model`` passed in was found via :term:`URL + dispatch` or if the ``path`` passed in was relative, the + ``virtual_root`` will always equal the ``root`` object (the + model passed in). + + - ``virtual_root_path`` -- If :term:`traversal` was used to find + the ``model``, this will be the sequence of path elements + traversed to find the ``virtual_root`` object. Each of these + items is a Unicode object. If no path segments were traversed + to find the ``virtual_root`` object (e.g. if virtual hosting is + not in effect), the ``traversed`` value will be the empty list. + If url dispatch was used to find the ``model``, this will be + None. - If the path cannot be resolved, a KeyError will be raised. + If the path cannot be resolved, a ``KeyError`` will be raised. Rules for passing a *string* as the ``path`` argument: if the first character in the path string is the with the ``/`` @@ -244,14 +247,14 @@ def traverse(model, path): Explanation of the conversion of ``path`` segment values to Unicode during traversal: Each segment is URL-unquoted, and decoded into Unicode. Each segment is assumed to be encoded using - the UTF-8 encoding (or a subset, such as ASCII); a TypeError is - raised if a segment cannot be decoded. If a segment name is empty - or if it is ``.``, it is ignored. If a segment name is ``..``, - the previous segment is deleted, and the ``..`` is ignored. As a - result of this process, the return values ``view_name``, each - element in the ``subpath``, each element in ``traversed``, and - each element in the ``virtual_root_path`` will be Unicode as - opposed to a string, and will be URL-decoded. + the UTF-8 encoding (or a subset, such as ASCII); a ``TypeError`` + is raised if a segment cannot be decoded. If a segment name is + empty or if it is ``.``, it is ignored. If a segment name is + ``..``, the previous segment is deleted, and the ``..`` is + ignored. As a result of this process, the return values + ``view_name``, each element in the ``subpath``, each element in + ``traversed``, and each element in the ``virtual_root_path`` will + be Unicode as opposed to a string, and will be URL-decoded. """ if hasattr(path, '__iter__'): @@ -279,8 +282,8 @@ def traverse(model, path): def model_path_tuple(model, *elements): """ Return a tuple representing the absolute physical path of the - model object based on its position in the model graph, e.g ``('', - 'foo', 'bar')``. Any positional arguments passed in as + ``model`` object based on its position in an object graph, e.g + ``('', 'foo', 'bar')``. Any positional arguments passed in as ``elements`` will be appended as elements in the tuple representing the the model path. For instance, if the model's path is ``('', 'foo', 'bar')`` and elements equals ``('a', 'b')``, @@ -324,11 +327,12 @@ def _model_path_list(model, *elements): def virtual_root(model, request): """ - Provided any model and a request object, return the model object - representing the 'virtual root' of the current request. Using a - virtual root in a traversal-based :mod:`repoze.bfg` application - permits rooting, for example, the object at the traversal path - ``/cms`` at ``http://example.com/`` instead of rooting it at + Provided any :term:`model` and a :term:`request` object, return + the model object representing the :term:`virtual root` of the + current :term:`request`. Using a virtual root in a + :term:`traversal` -based :mod:`repoze.bfg` application permits + rooting, for example, the object at the traversal path ``/cms`` at + ``http://example.com/`` instead of rooting it at ``http://example.com/cms/``. If the ``model`` passed in is a context obtained via @@ -336,9 +340,9 @@ def virtual_root(model, request): WSGI environment, the value of this key will be treated as a 'virtual root path': the :func:`repoze.bfg.traversal.find_model` API will be used to find the virtual root object using this path; - if the object is found, it will found will be returned. If the - ``%s`` key is is not present in the WSGI environment, the physical - :term:`root` of the graph will be returned instead. + if the object is found, it will be returned. If the + ``HTTP_X_VHM_ROOT`` key is is not present in the WSGI environment, + the physical :term:`root` of the graph will be returned instead. Virtual roots are not useful at all in applications that use :term:`URL dispatch`. Contexts obtained via URL dispatch don't @@ -595,13 +599,14 @@ class TraversalContextURL(object): return find_root(self.context) def __call__(self): - """ Generate a URL based on the lineage of a model obtained - via traversal. If any model in the context lineage has a - unicode name, it will be converted to a UTF-8 string before - being attached to the URL. If a ``HTTP_X_VHM_ROOT`` key is - present in the WSGI environment, its value will be treated as - a 'virtual root path': the path of the URL generated by this - will be left-stripped of this virtual root path value. + """ Generate a URL based on the :term:`lineage` of a + :term:`model` object obtained via :term:`traversal`. If any + model in the context lineage has a Unicode name, it will be + converted to a UTF-8 string before being attached to the URL. + If a ``HTTP_X_VHM_ROOT`` key is present in the WSGI + environment, its value will be treated as a 'virtual root + path': the path of the URL generated by this will be + left-stripped of this virtual root path value. """ path = model_path(self.context) if path != '/': diff --git a/repoze/bfg/url.py b/repoze/bfg/url.py index 2079b41cd..741fab9ce 100644 --- a/repoze/bfg/url.py +++ b/repoze/bfg/url.py @@ -15,7 +15,8 @@ from repoze.bfg.traversal import TraversalContextURL from repoze.bfg.traversal import quote_path_segment def route_url(route_name, request, *elements, **kw): - """Generates a fully qualified URL for a named BFG route. + """Generates a fully qualified URL for a named :mod:`repoze.bfg` + :term:`route configuration`. Use the route's ``name`` as the first positional argument. Use a request object as the second positional argument. Additional @@ -23,7 +24,7 @@ def route_url(route_name, request, *elements, **kw): after it is generated. Use keyword arguments to supply values which match any dynamic - path elements in the route definition. Raises a KeyError + path elements in the route definition. Raises a ``KeyError`` exception if the URL cannot be generated for any reason (not enough arguments, for example). @@ -118,22 +119,11 @@ def route_url(route_name, request, *elements, **kw): def model_url(model, request, *elements, **kw): """ - Generate a string representing the absolute URL of the model (or - context) object based on the ``wsgi.url_scheme``, ``HTTP_HOST`` or - ``SERVER_NAME`` in the request, plus any ``SCRIPT_NAME``. If a - 'virtual root path' is present in the request environment (the - value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the - ``model`` was obtained via traversal, the URL path will not - include the virtual root prefix (it will be stripped out of the - generated URL). If a ``query`` keyword argument is provided, a - query string based on its value will be composed and appended to - the generated URL string (see details below). The overall result - of this function is always a UTF-8 encoded string (never unicode). - - .. note:: If the ``model`` used is the result of a traversal, it - must be :term:`location`-aware. The 'model' can also be the - context of a URL dispatch; contexts found this way do not need - to be location-aware. + Generate a string representing the absolute URL of the ``model`` + object based on the ``wsgi.url_scheme``, ``HTTP_HOST`` or + ``SERVER_NAME`` in the ``request``, plus any ``SCRIPT_NAME``. The + overall result of this function is always a UTF-8 encoded string + (never unicode). Examples:: @@ -151,7 +141,7 @@ def model_url(model, request, *elements, **kw): model_url(context, request, 'a.html', anchor='abc') => - http://example.com/#abc + http://example.com/a.html#abc Any positional arguments passed in as ``elements`` must be strings or unicode objects. These will be joined by slashes and appended @@ -197,6 +187,19 @@ def model_url(model, request, *elements, **kw): If both ``anchor`` and ``query`` are specified, the anchor element will always follow the query element, e.g. ``http://example.com?foo=1#bar``. + + .. note:: If the ``model`` used is the result of a + :term:`traversal`, it must be :term:`location`-aware. + The ``model`` can also be the context of a :term:`URL + dispatch`; contexts found this way do not need to be + location-aware. + + .. note:: If a 'virtual root path' is present in the request + environment (the value of the WSGI environ key + ``HTTP_X_VHM_ROOT``), and the ``model`` was obtained via + :term:`traversal`, the URL path will not include the + virtual root prefix (it will be stripped off the + left hand side of the generated URL). """ try: reg = request.registry @@ -229,9 +232,10 @@ def model_url(model, request, *elements, **kw): def static_url(path, request, **kw): """ - Generates a fully qualified URL for a static resource. The - resource must live within a location defined via the ``<static>`` - ZCML directive (see :ref:`static_resources_section`). + Generates a fully qualified URL for a static :term:`resource`. + The resource must live within a location defined via the + ``add_static_view`` :term:`configuration declaration` or the + ``<static>`` ZCML directive (see :ref:`static_resources_section`). Example:: @@ -247,7 +251,7 @@ def static_url(path, request, **kw): may not be an absolute filesystem path (a ValueError will be raised if this function is supplied with an absolute path). - The ``request`` argument should be a WebOb request. + The ``request`` argument should be a :term:`request` object. The purpose of the ``**kw`` argument is the same as the purpose of the ``route_url`` ``**kw`` argument. See the documentation for @@ -255,8 +259,8 @@ def static_url(path, request, **kw): it. However, typically, you don't need to pass anything as ``*kw`` when generating a static resource URL. - This function raises a ValueError if a ``<static>`` ZCML - definition cannot be found which matches the path specification. + This function raises a ValueError if a static view definition + cannot be found which matches the path specification. .. note:: This feature is new in :mod:`repoze.bfg` 1.1. """ diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py index d682d762b..e5b271262 100644 --- a/repoze/bfg/view.py +++ b/repoze/bfg/view.py @@ -50,14 +50,15 @@ deprecated('NotFound', _marker = object() def render_view_to_response(context, request, name='', secure=True): - """ Render the view named ``name`` against the specified - ``context`` and ``request`` to an object implementing - ``repoze.bfg.interfaces.IResponse`` or ``None`` if no such view - exists. This function will return ``None`` if a corresponding - view cannot be found. If ``secure`` is ``True``, and the view is - protected by a permission, the permission will be checked before - calling the view function. If the permission check disallows view - execution (based on the current security policy), a + """ Render the view with the :term:`view name` ``name`` against + the specified ``context`` and ``request`` and return a + :term:`response` object or ``None`` if no such view exists. + + This function will return ``None`` if a corresponding view cannot + be found. If ``secure`` is ``True``, and the view is protected by + a permission, the permission will be checked before calling the + view function. If the permission check disallows view execution + (based on the current security policy), a ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its ``args`` attribute explains why the view access was disallowed. If ``secure`` is ``False``, no permission checking is done.""" @@ -83,18 +84,20 @@ def render_view_to_response(context, request, name='', secure=True): def render_view_to_iterable(context, request, name='', secure=True): """ Render the view named ``name`` against the specified ``context`` and ``request``, and return an iterable representing - the view response's ``app_iter`` (see the interface named - ``repoze.bfg.interfaces.IResponse``). This function will return - ``None`` if a corresponding view cannot be found. Additionally, - this function will raise a ``ValueError`` if a view function is - found and called but the view does not return an object which - implements ``repoze.bfg.interfaces.IResponse``. You can usually + the view response's ``app_iter`` (see :ref:`the_response`). + + This function will return ``None`` if a corresponding view cannot + be found. Additionally, this function will raise a ``ValueError`` + if a view function is found and called but the view function's + result does not have an ``app_iter`` attribute. You can usually get the string representation of the return value of this function by calling ``''.join(iterable)``, or just use ``render_view`` - instead. If ``secure`` is ``True``, and the view is protected by - a permission, the permission will be checked before calling the - view function. If the permission check disallows view execution - (based on the current security policy), a + instead. + + If ``secure`` is ``True``, and the view is protected by a + permission, the permission will be checked before the view + function is invoked. If the permission check disallows view + execution (based on the current :term:`authentication policy`), a ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its ``args`` attribute explains why the view access was disallowed. If ``secure`` is ``False``, no permission checking is done.""" @@ -106,16 +109,16 @@ def render_view_to_iterable(context, request, name='', secure=True): def render_view(context, request, name='', secure=True): """ Render the view named ``name`` against the specified ``context`` and ``request``, and unwind the the view response's - ``app_iter`` (see the interface named - ``repoze.bfg.interfaces.IResponse``) into a single string. This + ``app_iter`` (see :ref:`the_response`) into a single string. This function will return ``None`` if a corresponding view cannot be found. Additionally, this function will raise a ``ValueError`` if a view function is found and called but the view does not return an object which implements ``repoze.bfg.interfaces.IResponse``. + If ``secure`` is ``True``, and the view is protected by a - permission, the permission will be checked before calling the view - function. If the permission check disallows view execution (based - on the current security policy), a + permission, the permission will be checked before the view is + invoked. If the permission check disallows view execution (based + on the current :term:`authorization policy`), a ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its ``args`` attribute explains why the view access was disallowed. If ``secure`` is ``False``, no permission checking is done.""" @@ -125,11 +128,12 @@ def render_view(context, request, name='', secure=True): return ''.join(iterable) def is_response(ob): - """ Return True if ``ob`` implements the - ``repoze.bfg.interfaces.IResponse`` interface, False if not. Note - that this isn't actually a true Zope interface check, it's a - duck-typing check, as response objects are not obligated to - actually implement a Zope interface.""" + """ Return ``True`` if ``ob`` implements the interface implied by + :ref:`the_response`. ``False`` if not. + + .. note:: this isn't a true interface check (in Zope terms), it's a + duck-typing check, as response objects are not obligated to + actually implement a Zope interface.""" # response objects aren't obligated to implement a Zope interface, # so we do it the hard way if ( hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and @@ -141,39 +145,40 @@ def is_response(ob): return False class static(object): - """ An instance of this class is a callable which can act as a BFG - view; this view will serve static files from a directory on disk - based on the ``root_dir`` you provide to its constructor. + """ An instance of this class is a callable which can act as a + :mod:`repoze.bfg` :term:`view callable`; this view will serve + static files from a directory on disk based on the ``root_dir`` + you provide to its constructor. The directory may contain subdirectories (recursively); the static view implementation will descend into these directories as necessary based on the components of the URL in order to resolve a path into a response. - You may pass an absolute or relative filesystem path to the - directory containing static files directory to the constructor as - the ``root_dir`` argument. - - If the path is relative, and the ``package`` argument is ``None``, - it will be considered relative to the directory in which the - Python file which calls ``static`` resides. If the ``package`` - name argument is provided, and a relative ``root_dir`` is - provided, the ``root_dir`` will be considered relative to the - Python package specified by ``package_name`` (a dotted path to a - Python package). - - ``cache_max_age`` influences the Expires and Max-Age response - headers returned by the view (default is 3600 seconds or five - minutes). ``level`` influences how relative directories are - resolved (the number of hops in the call stack), not used very - often. - - .. note:: If the ``root_dir`` is relative to a package, the BFG - ``resource`` ZCML directive can be used to override resources - within the named ``root_dir`` package-relative directory. - However, if the ``root_dir`` is absolute, the ``resource`` - directive will not be able to override the resources it - contains. + You may pass an absolute or relative filesystem path or a + :term:`resource specification` representing the directory + containing static files as the ``root_dir`` argument to this + class' constructor. + + If the ``root_dir`` path is relative, and the ``package_name`` + argument is ``None``, ``root_dir`` will be considered relative to + the directory in which the Python file which *calls* ``static`` + resides. If the ``package_name`` name argument is provided, and a + relative ``root_dir`` is provided, the ``root_dir`` will be + considered relative to the Python :term:`package` specified by + ``package_name`` (a dotted path to a Python package). + + ``cache_max_age`` influences the ``Expires`` and ``Max-Age`` + response headers returned by the view (default is 3600 seconds or + five minutes). + + .. note:: If the ``root_dir`` is relative to a :term:`package`, or + is a :term:`resource specification` the BFG ``resource`` ZCML + directive or :term:`Configurator` method can be used to + override resources within the named ``root_dir`` + package-relative directory. However, if the ``root_dir`` is + absolute, the ``resource`` directive will not be able to + override the resources it contains. """ def __init__(self, root_dir, cache_max_age=3600, package_name=None): # package_name is for bw compat; it is preferred to pass in a @@ -200,31 +205,41 @@ class static(object): return request_copy.get_response(self.app) class bfg_view(object): - """ Function or class decorator which allows Python code to make - view registrations instead of using ZCML for the same purpose. + """ A function, class or method :term:`decorator` which allows a + developer to create view registrations nearer to a :term:`view + callable` definition than use of :term:`ZCML` or :term:`imperative + configuration` to do the same. - E.g. in the module ``views.py``:: + For example, this code in a module ``views.py``:: - from models import IMyModel - from repoze.bfg.interfaces import IRequest + from models import MyModel - @bfg_view(name='my_view', request_type=IRequest, for_=IMyModel, - permission='read', route_name='site1')) + @bfg_view(name='my_view', for_=MyModel, permission='read', + route_name='site1') def my_view(context, request): - return render_template_to_response('templates/my.pt') + return 'OK' + + Might replace the following call to the ``add_view`` method of a + :term:`Configurator`:: + + import views + import models + config.add_view(views.my_view, for_=models.MyModel, name='my_view', + permission='read', 'route_name='site1') - Equates to the ZCML:: + Or might relpace the following ZCML ``view`` declaration:: <view - for='.models.IMyModel' + for='.models.MyModel' view='.views.my_view' name='my_view' permission='read' route_name='site1' /> - The following arguments are supported: ``for_``, ``permission``, - ``name``, ``request_type``, ``route_name``, ``request_method``, + The following arguments are supported as arguments to + ``bfg_view``: ``for_``, ``permission``, ``name``, + ``request_type``, ``route_name``, ``request_method``, ``request_param``, ``containment``, ``xhr``, ``accept``, ``header`` and ``path_info``. @@ -251,10 +266,10 @@ class bfg_view(object): ``repoze.bfg.interfaces.IRequest`` is used, implying the standard request interface type. - If ``route_name`` is not supplied, the view declaration is + If ``route_name`` is not supplied, the view configuration is considered to be made against a URL that doesn't match any defined :term:`route`. The use of a ``route_name`` is an advanced - feature, useful only if you're using :term:`url dispatch`. + feature, useful only if you're also using :term:`url dispatch`. If ``request_method`` is not supplied, this view will match a request with any HTTP ``REQUEST_METHOD`` @@ -276,10 +291,11 @@ class bfg_view(object): current request. If ``containment`` is not supplied, this view will be called when - the context of the request has any location lineage. If - ``containment`` *is* supplied, it must be a class or :term:`interface`, - denoting that the view 'matches' the current request only if any graph - lineage node possesses this class or interface. + the context of the request has any (or no) :term:`lineage`. If + ``containment`` *is* supplied, it must be a class or + :term:`interface`, denoting that the view 'matches' the current + request only if any graph :term:`lineage` node possesses this + class or interface. If ``xhr`` is specified, it must be a boolean value. If the value is ``True``, the view will only be invoked if the request's @@ -314,12 +330,10 @@ class bfg_view(object): ... Such a registration implies that the view name will be - ``my_view``, registered for models with the - ``zope.interface.Interface`` interface, using no permission, - registered against requests which implement the default IRequest - interface when no urldispatch route matches, with any - REQUEST_METHOD, any set of request.params values, in any lineage - containment. + ``my_view``, registered for any :term:`context` object, using no + permission, registered against all non-URL-dispatch-based + requests, with any ``REQUEST_METHOD``, any set of request.params + values, without respect to any object in the :term:`lineage`. The ``bfg_view`` decorator can also be used as a class decorator in Python 2.6 and better (Python 2.5 and below do not support @@ -336,8 +350,8 @@ class bfg_view(object): def __call__(self): return Response('hello from %s!' % self.context) - In Python 2.5 and below, the bfg_view decorator can still be used - against a class, although not in decorator form:: + In Python 2.5 and below, the ``bfg_view`` decorator can still be + used against a class, although not in decorator form:: from webob import Response from repoze.bfg.view import bfg_view @@ -399,10 +413,16 @@ class bfg_view(object): method decorator is new in :mod:`repoze.bfg` version 1.1. - To make use of any bfg_view declaration, you *must* insert the - following boilerplate into your application registry's ZCML:: + To make use of any bfg_view declaration, you must perform a + :term:`scan`. To do so, either insert the following boilerplate + into your application registry's ZCML:: <scan package="."/> + + Or, if you don't use ZCML, use the ``scan`` method of a + :term:`Configurator`:: + + config.scan() """ def __init__(self, name='', request_type=None, for_=None, permission=None, route_name=None, request_method=None, request_param=None, @@ -486,12 +506,18 @@ def append_slash_notfound_view(context, request): data information (turning it into a GET), so you shouldn't rely on this to redirect POST requests. - Add the following to your application's ``configure.zcml`` to use - this view as the Not Found view:: + If you use ZCML, add the following to your application's + ``configure.zcml`` to use this view as the Not Found view:: <notfound view="repoze.bfg.view.append_slash_notfound_view"/> + Or use the ``notfound`` method of a :term:`Configurator` if you + don't use ZCML:: + + from repoze.bfg.view import append_slash_notfound_view + config.notfound(append_slash_notfound_view) + See also :ref:`changing_the_notfound_view`. .. note:: This function is new as of :mod:`repoze.bfg` version 1.1. diff --git a/repoze/bfg/wsgi.py b/repoze/bfg/wsgi.py index 10d067901..26229836a 100644 --- a/repoze/bfg/wsgi.py +++ b/repoze/bfg/wsgi.py @@ -8,7 +8,7 @@ def wsgiapp(wrapped): WSGI environment *are not* performed before the application is invoked. - E.g.:: + E.g., the following in a ``views.py`` module:: @wsgiapp def hello_world(environ, start_response): @@ -17,14 +17,18 @@ def wsgiapp(wrapped): ('Content-Length', len(body)) ] ) return [body] - Allows the following view declaration to be made:: + Allows the following ZCML view declaration to be made:: <view view=".views.hello_world" name="hello_world.txt" - context="*" /> + Or the following :term:`Configurator` ``add_view`` method call:: + + from views import hello_world + config.add_view(hello_world, name='hello_world.txt') + The wsgiapp decorator will convert the result of the WSGI application to a Response and return it to repoze.bfg as if the WSGI app were a repoze.bfg view. @@ -41,7 +45,7 @@ def wsgiapp2(wrapped): WSGI environment *are* performed before the application is invoked. - E.g.:: + E.g. the following in a ``views.py`` module:: @wsgiapp2 def hello_world(environ, start_response): @@ -50,14 +54,18 @@ def wsgiapp2(wrapped): ('Content-Length', len(body)) ] ) return [body] - Allows the following view declaration to be made:: + Allows the following ZCML view declaration to be made:: <view view=".views.hello_world" name="hello_world.txt" - context="*" /> + Or the following :term:`Configurator` ``add_view`` method call:: + + from views import hello_world + config.add_view(hello_world, name='hello_world.txt') + The wsgiapp2 decorator will convert the result of the WSGI application to a Response and return it to repoze.bfg as if the WSGI app were a repoze.bfg view. The ``SCRIPT_NAME`` and |
