Request method decorators
=========================

.. Note::
    This is a partial backport from Zope 2.11's new request method
    decorators, condensed into a postonly decorator.

Using request method decorators, you can limit functions or methods to only
be callable when the HTTP request was made using a particular method. 

To limit access to a function or method to POST requests, use the postonly
decorator::

  >>> from AccessControl.requestmethod import *
  >>> @postonly
  ... def foo(bar, REQUEST):
  ...     return bar
  
When this method is accessed through a request that does not use POST, the
Forbidden exception will be raised::

  >>> foo('spam', GET)
  Traceback (most recent call last):
  ...
  Forbidden: Request must be POST
  
Only when the request was made using POST, will the call succeed::

  >>> foo('spam', POST)
  'spam'

It doesn't matter if REQUEST is a positional or a keyword parameter::

  >>> @postonly
  ... def foo(bar, REQUEST=None):
  ...     return bar
  >>> foo('spam', REQUEST=GET)
  Traceback (most recent call last):
  ...
  Forbidden: Request must be POST
  
*Not* passing an optional REQUEST always succeeds::

  >>> foo('spam')
  'spam'
  
Note that the REQUEST parameter is a requirement for the decorator to operate,
not including it in the callable signature results in an error::

  >>> @postonly
  ... def foo(bar):
  ...     return bar
  Traceback (most recent call last):
  ...
  ValueError: No REQUEST parameter in callable signature

Because the Zope Publisher uses introspection to match REQUEST variables
against callable signatures, the result of the decorator must match the
original closely, and keyword parameter defaults must be preserved::

  >>> import inspect
  >>> mutabledefault = dict()
  >>> @postonly
  ... def foo(bar, baz=mutabledefault, REQUEST=None, **kw):
  ...     return bar, baz is mutabledefault, REQUEST
  >>> inspect.getargspec(foo)[:3]
  (['bar', 'baz', 'REQUEST'], None, 'kw')
  >>> foo('spam')
  ('spam', True, None)
