Skip to content

Commit

Permalink
Finished existing decorators example and added an argument decorator …
Browse files Browse the repository at this point in the history
…example.
  • Loading branch information
epsy committed Feb 18, 2015
1 parent 3c20bc3 commit 30a6652
Showing 1 changed file with 148 additions and 5 deletions.
153 changes: 148 additions & 5 deletions docs/compositing.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.. currentmodule:: clize

.. _function-compositing:
.. |wrapper_decorator| replace::
`~sigtools.wrappers.wrapper_decorator`

.. _function-compositing:

Function compositing
====================
Expand All @@ -16,8 +18,11 @@ We will look at how you can create decorators that work along with Clize.
Creating decorators is useful if you want to share behaviour across multiple
functions passed to `run`, such as extra parameters or input/output formatting.

Using a decorator to add new parameters and modifies the return value
---------------------------------------------------------------------

.. _change return deco:

Using a decorator to add new parameters and modify the return value
-------------------------------------------------------------------

Let's create a decorator that transforms the output of the wrapped function
when passed a specific flag.
Expand Down Expand Up @@ -72,13 +77,151 @@ the decorator's docstring::
-h, --help Show the help


.. _add arg deco:

Providing an argument using a decorator
---------------------------------------

When you're passing new arguments to the wrapped function in addition to
``*args, **kwargs``, things get a little bit more complicated. You have to tell
Clize that some of the wrapped function's parameters shouldn't appear in place
of the wrapper's ``*args, **kwargs``. call |wrapper_decorator| with the number
of positional arguments you insert before ``*args``, then the names of each
named argument that you pass to the wrapped function.

.. seealso:: :ref:`sigtools:forwards-pick`

The arguments for |wrapper_decorator| are the same as in
`sigtools.specifiers.forwards`, so you may use this section for further
information.

.. literalinclude:: /../examples/decorators/provide.py
:lines: 1-2,4-22

Here we pass ``0, 'branch'`` to |wrapper_decorator| because we call wrapped
with no positional arguments besides ``*args`` and ``branch`` as named
argument.

You can then use the decorator like before:

.. literalinclude:: /../examples/decorators/provide.py
:lines: 3,23-47


.. _arg deco:

Using a composed function to process arguments to a parameter
-------------------------------------------------------------

You can use `clize.extra.parameters.argument_decorator` to have a second function process an argument while still being able to use parameters of its own:

.. code-block:: python
from clize import run
from clize.extra.parameters import argument_decorator
@argument_decorator
def read_server(arg, *, port=80, _6=False):
"""
Options for {param}:
port: Which port to connect on
_6: Use IPv6?
"""
return (arg, port, _6)
def get_page(server:read_server, path):
"""
server: The server to contact
path: The path of the resource to fetch
"""
print("Connecting to", server, "to get", path)
run(get_page)
``read_server``'s parameters will be available on the CLI. When a value is read
that would feed the ``server`` parameter, ``read_server`` is called with it and
its collected arguments. Its return value is then used as the ``server`` parameter of ``get_page``:

.. |wrapper_decorator| replace::
`wrapper_decorator<sigtools.wrappers.wrapper_decorator>`
.. code-block:: console
$ python argdeco.py --help
Usage: argdeco.py [OPTIONS] [--port=INT] [-6] server path
Arguments:
server The server to contact
path The path of the resource to fetch
Options for server:
--port=INT Which port to connect on (default: 80)
-6 Use IPv6?
Other actions:
-h, --help Show the help
A few notes:

* You can only use named parameters besides ``arg`` which receives the original
value.
* The decorator's docstring is used to document its parameters. It is usually
preferrable to use a :ref:`section <sections doc>` as they would not be
distinguished from other parameters otherwise.
* Appearances of ``{param}`` are replaced with the parameter's name.

You can also use this on named parameters as well as on ``*args``, but the
names of the composited parameters must not conflict:

.. code-block:: python
from clize import run
from clize.extra.parameters import argument_decorator
@argument_decorator
def read_server(arg, *, port=80, _6=False):
"""
Options for {param}:
port: Which port to connect on
_6: Use IPv6?
"""
return (arg, port, _6)
def get_page(path, *servers:read_server):
"""
server: The server to contact
path: The path of the resource to fetch
"""
print("Connecting to", servers, "to get", path)
run(get_page)
.. code-block:: console
$ python argdeco.py --help
Usage: argdeco.py [OPTIONS] path [[--port=INT] [-6] servers...]
Arguments:
path The path of the resource to fetch
servers...
Options for servers:
--port=INT Which port to connect on (default: 80)
-6 Use IPv6?
Other actions:
-h, --help Show the help
$ python argdeco.py -6 abc
argdeco.py: Missing required arguments: servers
Usage: argdeco.py [OPTIONS] path [[--port=INT] [-6] servers...]
$ python argdeco.py /eggs -6 abc
Connecting to (('abc', 80, True),) to get /eggs
$ python argdeco.py /eggs -6 abc def
Connecting to (('abc', 80, True), ('def', 80, False)) to get /eggs
$ python argdeco.py /eggs -6 abc def --port 8080 cheese
Connecting to (('abc', 80, True), ('def', 80, False), ('cheese', 8080, False)) to get /eggs

0 comments on commit 30a6652

Please sign in to comment.