summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2015-07-26 07:52:33 +0200
committerMichele Simionato <michele.simionato@gmail.com>2015-07-26 07:52:33 +0200
commit24d5f1539f0d876e4871ecca4f671d0710ab35bf (patch)
tree33b6d0b1322038f5fbaa183cd837be5c9c448ef4
parentbd0f62ec00f01073f72bf55bc8433c5735fe18d9 (diff)
downloadpython-decorator-git-24d5f1539f0d876e4871ecca4f671d0710ab35bf.tar.gz
Generated HTML docs and removed documentation.rst
-rw-r--r--Makefile20
-rw-r--r--README.md2
-rw-r--r--docs/README.rst (renamed from README.rst)6
-rw-r--r--docs/documentation.rst1410
-rw-r--r--docs/index.html403
-rw-r--r--documentation.pdf (renamed from docs/documentation.pdf)6
6 files changed, 17 insertions, 1830 deletions
diff --git a/Makefile b/Makefile
index aaf5ea1..116b2aa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,16 @@
-RST=python $(S)/ms/tools/rst.py
+RST=$(S)/ms/tools/rst.py -H
rst: src/tests/documentation.py
- PYTHONPATH=src:$(S) python3 $(S)/minidoc3.py -d tests.documentation
- cp /tmp/tests.documentation.rst docs/documentation.rst
+ PYTHONPATH=src:$(S) $(S)/ms/tools/minidoc.py -d tests.documentation
-html: docs/documentation.rst README.rst
- $(RST) docs/documentation.rst
- rst2html README.rst docs/index.html
+html: /tmp/tests.documentation.rst docs/README.rst
+ $(RST) /tmp/tests.documentation.rst
+ $(RST) docs/README.rst
+ mv docs/README.html docs/index.html
+ mv /tmp/tests.documentation.html docs/documentation.html
-pdf: docs/documentation.rst
- rst2pdf docs/documentation.rst -o docs/documentation.pdf
+pdf: /tmp/tests.documentation.rst
+ rst2pdf /tmp/tests.documentation.rst -o documentation.pdf
-upload: documentation.pdf
- git clean -f
+upload: documentation.pdf docs/index.html
python3 setup.py register sdist bdist_wheel upload upload_docs
diff --git a/README.md b/README.md
index 852dc06..ad68c5a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-[See the real README](README.rst)
+[See the real README](docs/README.rst)
[![Build Status](https://secure.travis-ci.org/micheles/decorator.png?branch=master)](https://travis-ci.org/micheles/decorator)
diff --git a/README.rst b/docs/README.rst
index bde4ac1..3a6bb3f 100644
--- a/README.rst
+++ b/docs/README.rst
@@ -25,7 +25,7 @@ the documentation, download the tarball_, unpack it and run
in the main directory, possibly as superuser.
.. _tarball: http://pypi.python.org/pypi/decorator
-.. _distribute: http://packages.python.org/distribute/
+
Testing
--------
@@ -51,8 +51,8 @@ There are various versions of the documentation:
- `HTML version`_
- `PDF version`_
-.. _HTML version: https://github.com/micheles/decorator/blob/4.0.0/docs/documentation.rst
-.. _PDF version: https://github.com/micheles/decorator/blob/4.0.0/docs/documentation.pdf
+.. _HTML version: http://pypi.python.org/pypi/decorator/documentation.html
+.. _PDF version: https://github.com/micheles/decorator/blob/4.0.1/documentation.pdf
Repository
---------------
diff --git a/docs/documentation.rst b/docs/documentation.rst
deleted file mode 100644
index 6c3cdcd..0000000
--- a/docs/documentation.rst
+++ /dev/null
@@ -1,1410 +0,0 @@
-
-The ``decorator`` module
-=============================================================
-
-:Author: Michele Simionato
-:E-mail: michele.simionato@gmail.com
-:Version: 4.0.0 (2015-07-24)
-:Supports: Python 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5
-:Download page: http://pypi.python.org/pypi/decorator/4.0.0
-:Installation: ``pip install decorator``
-:License: BSD license
-
-.. contents::
-
-Introduction
------------------------------------------
-
-The decorator module is over ten years old, but still alive and
-kicking. It is used by several frameworks (IPython, scipy, authkit,
-pylons, pycuda, sugar, ...) and has been stable for a *long*
-time. It is your best option if you want to preserve the signature of
-decorated functions in a consistent way across Python
-releases. Version 4.0 is fully compatible with the past, except for
-one thing: support for Python 2.4 and 2.5 has been dropped. That
-decision made it possible to use a single code base both for Python
-2.X and Python 3.X. This is a *huge* bonus, since I could remove over
-2,000 lines of duplicated documentation/doctests. Having to maintain
-separate docs for Python 2 and Python 3 effectively stopped any
-development on the module for several years. Moreover, it is now
-trivial to distribute the module as an universal wheel_ since 2to3 is no more
-required. Since Python 2.5 has been released 9 years ago, I felt that
-it was reasonable to drop the support for it. If you need to support
-ancient versions of Python, stick with the decorator module version
-3.4.2. This version supports all Python releases from 2.6 up to 3.5,
-which currently is still in beta status.
-
-.. _wheel: http://pythonwheels.com/
-
-What's new
----------------------
-
-Since now there is a single manual for all Python versions, I took the
-occasion for overhauling the documentation. Therefore, even if you are
-an old time user, you may want to read the docs again, since several
-examples have been improved. The packaging has been improved and I
-am distributing the code in wheel format too. The integration with
-setuptools has been improved and now you can use ``python setup.py
-test`` to run the tests. A new utility function ``decorate(func,
-caller)`` has been added, doing the same job that in the past was done
-by ``decorator(caller, func)``. The old functionality is still there
-for compatibility sake, but it is deprecated and not documented
-anymore.
-
-Apart from that, there is a new experimental feature. The decorator
-module now includes an implementation of generic (multiple dispatch)
-functions. The API is designed to mimic the one of
-``functools.singledispatch`` (introduced in Python 3.4) but the
-implementation is much simpler; moreover all the decorators involved
-preserve the signature of the decorated functions. For the moment the
-facility is there mostly to exemplify the power of the module. In the
-future it could be enhanced/optimized; on the other hand, both its
-behavior and its API could change. Such is the fate of experimental
-features. In any case it is very short and compact (less then one
-hundred lines) so you can extract it for your own use. Take it as food
-for thought.
-
-Usefulness of decorators
-------------------------------------------------
-
-Python decorators are an interesting example of why syntactic sugar
-matters. In principle, their introduction in Python 2.4 changed
-nothing, since they do not provide any new functionality which was not
-already present in the language. In practice, their introduction has
-significantly changed the way we structure our programs in Python. I
-believe the change is for the best, and that decorators are a great
-idea since:
-
-* decorators help reducing boilerplate code;
-* decorators help separation of concerns;
-* decorators enhance readability and maintenability;
-* decorators are explicit.
-
-Still, as of now, writing custom decorators correctly requires
-some experience and it is not as easy as it could be. For instance,
-typical implementations of decorators involve nested functions, and
-we all know that flat is better than nested.
-
-The aim of the ``decorator`` module it to simplify the usage of
-decorators for the average programmer, and to popularize decorators by
-showing various non-trivial examples. Of course, as all techniques,
-decorators can be abused (I have seen that) and you should not try to
-solve every problem with a decorator, just because you can.
-
-You may find the source code for all the examples
-discussed here in the ``documentation.py`` file, which contains
-the documentation you are reading in the form of doctests.
-
-Definitions
-------------------------------------
-
-Technically speaking, any Python object which can be called with one argument
-can be used as a decorator. However, this definition is somewhat too large
-to be really useful. It is more convenient to split the generic class of
-decorators in two subclasses:
-
-+ *signature-preserving* decorators, i.e. callable objects taking a
- function as input and returning a function *with the same
- signature* as output;
-
-+ *signature-changing* decorators, i.e. decorators that change
- the signature of their input function, or decorators returning
- non-callable objects.
-
-Signature-changing decorators have their use: for instance the
-builtin classes ``staticmethod`` and ``classmethod`` are in this
-group, since they take functions and return descriptor objects which
-are not functions, nor callables.
-
-However, signature-preserving decorators are more common and easier to
-reason about; in particular signature-preserving decorators can be
-composed together whereas other decorators in general cannot.
-
-Writing signature-preserving decorators from scratch is not that
-obvious, especially if one wants to define proper decorators that
-can accept functions with any signature. A simple example will clarify
-the issue.
-
-Statement of the problem
-------------------------------
-
-A very common use case for decorators is the memoization of functions.
-A ``memoize`` decorator works by caching
-the result of the function call in a dictionary, so that the next time
-the function is called with the same input parameters the result is retrieved
-from the cache and not recomputed. There are many implementations of
-``memoize`` in http://www.python.org/moin/PythonDecoratorLibrary,
-but they do not preserve the signature. In recent versions of
-Python you can find a sophisticated ``lru_cache`` decorator
-in the standard library (in ``functools``). Here I am just
-interested in giving an example.
-
-A simple implementation could be the following (notice
-that in general it is impossible to memoize correctly something
-that depends on non-hashable arguments):
-
-.. code-block:: python
-
- def memoize_uw(func):
- func.cache = {}
-
- def memoize(*args, **kw):
- if kw: # frozenset is used to ensure hashability
- key = args, frozenset(kw.items())
- else:
- key = args
- if key not in func.cache:
- func.cache[key] = func(*args, **kw)
- return func.cache[key]
- return functools.update_wrapper(memoize, func)
-
-
-Here i used the functools.update_wrapper_ utility, which has
-been added in Python 2.5 expressly to simplify the definition of decorators
-(in older versions of Python you need to copy the function attributes
-``__name__``, ``__doc__``, ``__module__`` and ``__dict__``
-from the original function to the decorated function by hand).
-
-.. _functools.update_wrapper: https://docs.python.org/3/library/functools.html#functools.update_wrapper
-
-The implementation above works in the sense that the decorator
-can accept functions with generic signatures; unfortunately this
-implementation does *not* define a signature-preserving decorator, since in
-general ``memoize_uw`` returns a function with a
-*different signature* from the original function.
-
-Consider for instance the following case:
-
-.. code-block:: python
-
- @memoize_uw
- def f1(x):
- "Simulate some long computation"
- time.sleep(1)
- return x
-
-
-Here the original function takes a single argument named ``x``,
-but the decorated function takes any number of arguments and
-keyword arguments:
-
-.. code-block:: python
-
- >>> from decorator import getargspec # akin to inspect.getargspec
- >>> print(getargspec(f1))
- ArgSpec(args=[], varargs='args', varkw='kw', defaults=None)
-
-This means that introspection tools such as ``pydoc`` will give wrong
-informations about the signature of ``f1``, unless you are using
-Python 3.5. This is pretty bad: ``pydoc`` will tell you that the
-function accepts a generic signature ``*args``, ``**kw``, but when you
-try to call the function with more than an argument, you will get an
-error:
-
-.. code-block:: python
-
- >>> f1(0, 1)
- Traceback (most recent call last):
- ...
- TypeError: f1() takes exactly 1 positional argument (2 given)
-
-Notice even in Python 3.5 ``inspect.getargspec`` and
-``inspect.getfullargspec`` (which are deprecated in that release) will
-give the wrong signature.
-
-
-The solution
------------------------------------------
-
-The solution is to provide a generic factory of generators, which
-hides the complexity of making signature-preserving decorators
-from the application programmer. The ``decorate`` function in
-the ``decorator`` module is such a factory:
-
-.. code-block:: python
-
- >>> from decorator import decorate
-
-``decorate`` takes two arguments, a caller function describing the
-functionality of the decorator and a function to be decorated; it
-returns the decorated function. The caller function must have
-signature ``(f, *args, **kw)`` and it must call the original function ``f``
-with arguments ``args`` and ``kw``, implementing the wanted capability,
-i.e. memoization in this case:
-
-.. code-block:: python
-
- def _memoize(func, *args, **kw):
- if kw: # frozenset is used to ensure hashability
- key = args, frozenset(kw.items())
- else:
- key = args
- cache = func.cache # attribute added by memoize
- if key not in cache:
- cache[key] = func(*args, **kw)
- return cache[key]
-
-
-At this point you can define your decorator as follows:
-
-.. code-block:: python
-
- def memoize(f):
- f.cache = {}
- return decorate(f, _memoize)
-
-
-The difference with respect to the ``memoize_uw`` approach, which is based
-on nested functions, is that the decorator module forces you to lift
-the inner function at the outer level.
-Moreover, you are forced to pass explicitly the function you want to
-decorate, there are no closures.
-
-Here is a test of usage:
-
-.. code-block:: python
-
- >>> @memoize
- ... def heavy_computation():
- ... time.sleep(2)
- ... return "done"
-
- >>> print(heavy_computation()) # the first time it will take 2 seconds
- done
-
- >>> print(heavy_computation()) # the second time it will be instantaneous
- done
-
-The signature of ``heavy_computation`` is the one you would expect:
-
-.. code-block:: python
-
- >>> print(getargspec(heavy_computation))
- ArgSpec(args=[], varargs=None, varkw=None, defaults=None)
-
-A ``trace`` decorator
-------------------------------------------------------
-
-As an additional example, here is how you can define a trivial
-``trace`` decorator, which prints a message everytime the traced
-function is called:
-
-.. code-block:: python
-
- def _trace(f, *args, **kw):
- kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw))
- print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr))
- return f(*args, **kw)
-
-
-.. code-block:: python
-
- def trace(f):
- return decorate(f, _trace)
-
-
-Here is an example of usage:
-
-.. code-block:: python
-
- >>> @trace
- ... def f1(x):
- ... pass
-
-It is immediate to verify that ``f1`` works
-
-.. code-block:: python
-
- >>> f1(0)
- calling f1 with args (0,), {}
-
-and it that it has the correct signature:
-
-.. code-block:: python
-
- >>> print(getargspec(f1))
- ArgSpec(args=['x'], varargs=None, varkw=None, defaults=None)
-
-The same decorator works with functions of any signature:
-
-.. code-block:: python
-
- >>> @trace
- ... def f(x, y=1, z=2, *args, **kw):
- ... pass
-
- >>> f(0, 3)
- calling f with args (0, 3, 2), {}
-
- >>> print(getargspec(f))
- ArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2))
-
-Function annotations
----------------------------------------------
-
-Python 3 introduced the concept of `function annotations`_,i.e. the ability
-to annotate the signature of a function with additional information,
-stored in a dictionary named ``__annotations__``. The decorator module,
-starting from release 3.3, is able to understand and to preserve the
-annotations. Here is an example:
-
-.. code-block:: python
-
- >>> @trace
- ... def f(x: 'the first argument', y: 'default argument'=1, z=2,
- ... *args: 'varargs', **kw: 'kwargs'):
- ... pass
-
-In order to introspect functions with annotations, one needs the
-utility ``inspect.getfullargspec``, new in Python 3 (and deprecated
-in favor of ``inspect.signature`` in Python 3.5):
-
-.. code-block:: python
-
- >>> from inspect import getfullargspec
- >>> argspec = getfullargspec(f)
- >>> argspec.args
- ['x', 'y', 'z']
- >>> argspec.varargs
- 'args'
- >>> argspec.varkw
- 'kw'
- >>> argspec.defaults
- (1, 2)
- >>> argspec.kwonlyargs
- []
- >>> argspec.kwonlydefaults
-
-You can check that the ``__annotations__`` dictionary is preserved:
-
-.. code-block:: python
-
- >>> f.__annotations__ is f.__wrapped__.__annotations__
- True
-
-Here ``f.__wrapped__`` is the original undecorated function. Such an attribute
-is added to be consistent with the way ``functools.update_wrapper`` work.
-Another attribute which is copied from the original function is
-``__qualname__``, the qualified name. This is a concept introduced
-in Python 3. In Python 2 the decorator module will still add a
-qualified name, but its value will always be ``None``.
-
-
-``decorator.decorator``
----------------------------------------------
-
-It may be annoying to write a caller function (like the ``_trace``
-function above) and then a trivial wrapper
-(``def trace(f): return decorate(f, _trace)``) every time. For this reason,
-the ``decorator`` module provides an easy shortcut to convert
-the caller function into a signature-preserving decorator: the
-``decorator`` function:
-
-.. code-block:: python
-
- >>> from decorator import decorator
- >>> print(decorator.__doc__)
- decorator(caller) converts a caller function into a decorator
-
-The ``decorator`` function can be used as a signature-changing
-decorator, just as ``classmethod`` and ``staticmethod``.
-However, ``classmethod`` and ``staticmethod`` return generic
-objects which are not callable, while ``decorator`` returns
-signature-preserving decorators, i.e. functions of a single argument.
-For instance, you can write directly
-
-.. code-block:: python
-
- >>> @decorator
- ... def trace(f, *args, **kw):
- ... kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw))
- ... print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr))
- ... return f(*args, **kw)
-
-and now ``trace`` will be a decorator.
-
-.. code-block:: python
-
- >>> trace
- <function trace at 0x...>
-
-Here is an example of usage:
-
-.. code-block:: python
-
- >>> @trace
- ... def func(): pass
-
- >>> func()
- calling func with args (), {}
-
-``blocking``
--------------------------------------------
-
-Sometimes one has to deal with blocking resources, such as ``stdin``, and
-sometimes it is best to have back a "busy" message than to block everything.
-This behavior can be implemented with a suitable family of decorators,
-where the parameter is the busy message:
-
-.. code-block:: python
-
- def blocking(not_avail):
- def _blocking(f, *args, **kw):
- if not hasattr(f, "thread"): # no thread running
- def set_result():
- f.result = f(*args, **kw)
- f.thread = threading.Thread(None, set_result)
- f.thread.start()
- return not_avail
- elif f.thread.isAlive():
- return not_avail
- else: # the thread is ended, return the stored result
- del f.thread
- return f.result
- return decorator(_blocking)
-
-
-Functions decorated with ``blocking`` will return a busy message if
-the resource is unavailable, and the intended result if the resource is
-available. For instance:
-
-.. code-block:: python
-
- >>> @blocking("Please wait ...")
- ... def read_data():
- ... time.sleep(3) # simulate a blocking resource
- ... return "some data"
-
- >>> print(read_data()) # data is not available yet
- Please wait ...
-
- >>> time.sleep(1)
- >>> print(read_data()) # data is not available yet
- Please wait ...
-
- >>> time.sleep(1)
- >>> print(read_data()) # data is not available yet
- Please wait ...
-
- >>> time.sleep(1.1) # after 3.1 seconds, data is available
- >>> print(read_data())
- some data
-
-``decorator(cls)``
---------------------------------------------
-
-The ``decorator`` facility can also produce a decorator starting
-from a class with the signature of a caller. In such a case the
-produced generator is able to convert functions into factories
-of instances of that class.
-
-As an example, here will I show a decorator which is able to convert a
-blocking function into an asynchronous function. The function, when
-called, is executed in a separate thread. This is very similar
-to the approach used in the ``concurrent.futures`` package. Of
-course the code here is just an example, it is not a recommended way
-of implementing futures. The implementation is the following:
-
-.. code-block:: python
-
- class Future(threading.Thread):
- """
- A class converting blocking functions into asynchronous
- functions by using threads.
- """
- def __init__(self, func, *args, **kw):
- try:
- counter = func.counter
- except AttributeError: # instantiate the counter at the first call
- counter = func.counter = itertools.count(1)
- name = '%s-%s' % (func.__name__, next(counter))
-
- def func_wrapper():
- self._result = func(*args, **kw)
- super(Future, self).__init__(target=func_wrapper, name=name)
- self.start()
-
- def result(self):
- self.join()
- return self._result
-
-
-The decorated function returns a ``Future`` object, which has a ``.result()``
-method which blocks until the underlying thread finishes and returns
-the final result. Here is a minimalistic example of usage:
-
-.. code-block:: python
-
- >>> futurefactory = decorator(Future)
- >>> @futurefactory
- ... def long_running(x):
- ... time.sleep(.5)
- ... return x
-
- >>> fut1 = long_running(1)
- >>> fut2 = long_running(2)
- >>> fut1.result() + fut2.result()
- 3
-
-contextmanager
--------------------------------------
-
-For a long time Python had in its standard library a ``contextmanager``
-decorator, able to convert generator functions into
-``GeneratorContextManager`` factories. For instance if you write
-
-.. code-block:: python
-
- >>> from contextlib import contextmanager
- >>> @contextmanager
- ... def before_after(before, after):
- ... print(before)
- ... yield
- ... print(after)
-
-
-then ``before_after`` is a factory function returning
-``GeneratorContextManager`` objects which can be used with
-the ``with`` statement:
-
-.. code-block:: python
-
- >>> with before_after('BEFORE', 'AFTER'):
- ... print('hello')
- BEFORE
- hello
- AFTER
-
-Basically, it is as if the content of the ``with`` block was executed
-in the place of the ``yield`` expression in the generator function.
-In Python 3.2 ``GeneratorContextManager``
-objects were enhanced with a ``__call__``
-method, so that they can be used as decorators as in this example:
-
-.. code-block:: python
-
- >>> @ba
- ... def hello():
- ... print('hello')
- ...
- >>> hello()
- BEFORE
- hello
- AFTER
-
-The ``ba`` decorator is basically inserting a ``with ba:`` block
-inside the function. However there two issues: the first is that
-``GeneratorContextManager`` objects are callable only in Python 3.2,
-so the previous example will break in older versions of Python (you
-can solve this by installing ``contextlib2``); the second is that
-``GeneratorContextManager`` objects do not preserve the signature of
-the decorated functions: the decorated ``hello`` function here will
-have a generic signature ``hello(*args, **kwargs)`` but will break
-when called with more than zero arguments. For such reasons the
-decorator module, starting with release 3.4, offers a
-``decorator.contextmanager`` decorator that solves both problems and
-works in all supported Python versions. The usage is the same and
-factories decorated with ``decorator.contextmanager`` will returns
-instances of ``ContextManager``, a subclass of
-``contextlib.GeneratorContextManager`` with a ``__call__`` method
-acting as a signature-preserving decorator.
-
-The ``FunctionMaker`` class
----------------------------------------------------------------
-
-You may wonder about how the functionality of the ``decorator`` module
-is implemented. The basic building block is
-a ``FunctionMaker`` class which is able to generate on the fly
-functions with a given name and signature from a function template
-passed as a string. Generally speaking, you should not need to
-resort to ``FunctionMaker`` when writing ordinary decorators, but
-it is handy in some circumstances. You will see an example shortly, in
-the implementation of a cool decorator utility (``decorator_apply``).
-
-``FunctionMaker`` provides a ``.create`` classmethod which
-takes as input the name, signature, and body of the function
-we want to generate as well as the execution environment
-were the function is generated by ``exec``. Here is an example:
-
-.. code-block:: python
-
- >>> def f(*args, **kw): # a function with a generic signature
- ... print(args, kw)
-
- >>> f1 = FunctionMaker.create('f1(a, b)', 'f(a, b)', dict(f=f))
- >>> f1(1,2)
- (1, 2) {}
-
-It is important to notice that the function body is interpolated
-before being executed, so be careful with the ``%`` sign!
-
-``FunctionMaker.create`` also accepts keyword arguments and such
-arguments are attached to the resulting function. This is useful
-if you want to set some function attributes, for instance the
-docstring ``__doc__``.
-
-For debugging/introspection purposes it may be useful to see
-the source code of the generated function; to do that, just
-pass the flag ``addsource=True`` and a ``__source__`` attribute will
-be added to the generated function:
-
-.. code-block:: python
-
- >>> f1 = FunctionMaker.create(
- ... 'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True)
- >>> print(f1.__source__)
- def f1(a, b):
- f(a, b)
- <BLANKLINE>
-
-``FunctionMaker.create`` can take as first argument a string,
-as in the examples before, or a function. This is the most common
-usage, since typically you want to decorate a pre-existing
-function. A framework author may want to use directly ``FunctionMaker.create``
-instead of ``decorator``, since it gives you direct access to the body
-of the generated function. For instance, suppose you want to instrument
-the ``__init__`` methods of a set of classes, by preserving their
-signature (such use case is not made up; this is done in SQAlchemy
-and in other frameworks). When the first argument of ``FunctionMaker.create``
-is a function, a ``FunctionMaker`` object is instantiated internally,
-with attributes ``args``, ``varargs``,
-``keywords`` and ``defaults`` which are the
-the return values of the standard library function ``inspect.getargspec``.
-For each argument in the ``args`` (which is a list of strings containing
-the names of the mandatory arguments) an attribute ``arg0``, ``arg1``,
-..., ``argN`` is also generated. Finally, there is a ``signature``
-attribute, a string with the signature of the original function.
-
-Notice: you should not pass signature strings with default arguments,
-i.e. something like ``'f1(a, b=None)'``. Just pass ``'f1(a, b)'`` and then
-a tuple of defaults:
-
-.. code-block:: python
-
- >>> f1 = FunctionMaker.create(
- ... 'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True, defaults=(None,))
- >>> print(getargspec(f1))
- ArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(None,))
-
-
-Getting the source code
----------------------------------------------------
-
-Internally ``FunctionMaker.create`` uses ``exec`` to generate the
-decorated function. Therefore
-``inspect.getsource`` will not work for decorated functions. That
-means that the usual ``??`` trick in IPython will give you the (right on
-the spot) message ``Dynamically generated function. No source code
-available``. In the past I have considered this acceptable, since
-``inspect.getsource`` does not really work even with regular
-decorators. In that case ``inspect.getsource`` gives you the wrapper
-source code which is probably not what you want:
-
-.. code-block:: python
-
- def identity_dec(func):
- def wrapper(*args, **kw):
- return func(*args, **kw)
- return wrapper
-
-.. code-block:: python
-
- def wrapper(*args, **kw):
- return func(*args, **kw)
-
-
-.. code-block:: python
-
- >>> import inspect
- >>> print(inspect.getsource(example))
- def wrapper(*args, **kw):
- return func(*args, **kw)
- <BLANKLINE>
-
-(see bug report 1764286_ for an explanation of what is happening).
-Unfortunately the bug is still there, in all versions of Python except
-Python 3.5, which is not yet released. There is however a
-workaround. The decorated function has an attribute ``__wrapped__``,
-pointing to the original function. The easy way to get the source code
-is to call ``inspect.getsource`` on the undecorated function:
-
-.. code-block:: python
-
- >>> print(inspect.getsource(factorial.__wrapped__))
- @tail_recursive
- def factorial(n, acc=1):
- "The good old factorial"
- if n == 0:
- return acc
- return factorial(n-1, n*acc)
- <BLANKLINE>
-
-.. _1764286: http://bugs.python.org/issue1764286
-
-Dealing with third party decorators
------------------------------------------------------------------
-
-Sometimes you find on the net some cool decorator that you would
-like to include in your code. However, more often than not the cool
-decorator is not signature-preserving. Therefore you may want an easy way to
-upgrade third party decorators to signature-preserving decorators without
-having to rewrite them in terms of ``decorator``. You can use a
-``FunctionMaker`` to implement that functionality as follows:
-
-.. code-block:: python
-
- def decorator_apply(dec, func):
- """
- Decorate a function by preserving the signature even if dec
- is not a signature-preserving decorator.
- """
- return FunctionMaker.create(
- func, 'return decfunc(%(signature)s)',
- dict(decfunc=dec(func)), __wrapped__=func)
-
-
-``decorator_apply`` sets the attribute ``__wrapped__`` of the generated
-function to the original function, so that you can get the right
-source code. If you are using Python 3, you should also set the
-``__qualname__`` attribute to preserve the qualified name of the
-original function.
-
-Notice that I am not providing this functionality in the ``decorator``
-module directly since I think it is best to rewrite the decorator rather
-than adding an additional level of indirection. However, practicality
-beats purity, so you can add ``decorator_apply`` to your toolbox and
-use it if you need to.
-
-In order to give an example of usage of ``decorator_apply``, I will show a
-pretty slick decorator that converts a tail-recursive function in an iterative
-function. I have shamelessly stolen the basic idea from Kay Schluehr's recipe
-in the Python Cookbook,
-http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691.
-
-.. code-block:: python
-
- class TailRecursive(object):
- """
- tail_recursive decorator based on Kay Schluehr's recipe
- http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691
- with improvements by me and George Sakkis.
- """
-
- def __init__(self, func):
- self.func = func
- self.firstcall = True
- self.CONTINUE = object() # sentinel
-
- def __call__(self, *args, **kwd):
- CONTINUE = self.CONTINUE
- if self.firstcall:
- func = self.func
- self.firstcall = False
- try:
- while True:
- result = func(*args, **kwd)
- if result is CONTINUE: # update arguments
- args, kwd = self.argskwd
- else: # last call
- return result
- finally:
- self.firstcall = True
- else: # return the arguments of the tail call
- self.argskwd = args, kwd
- return CONTINUE
-
-
-Here the decorator is implemented as a class returning callable
-objects.
-
-.. code-block:: python
-
- def tail_recursive(func):
- return decorator_apply(TailRecursive, func)
-
-
-Here is how you apply the upgraded decorator to the good old factorial:
-
-.. code-block:: python
-
- @tail_recursive
- def factorial(n, acc=1):
- "The good old factorial"
- if n == 0:
- return acc
- return factorial(n-1, n*acc)
-
-
-.. code-block:: python
-
- >>> print(factorial(4))
- 24
-
-This decorator is pretty impressive, and should give you some food for
-your mind ;) Notice that there is no recursion limit now, and you can
-easily compute ``factorial(1001)`` or larger without filling the stack
-frame. Notice also that the decorator will not work on functions which
-are not tail recursive, such as the following
-
-.. code-block:: python
-
- def fact(n): # this is not tail-recursive
- if n == 0:
- return 1
- return n * fact(n-1)
-
-
-(reminder: a function is tail recursive if it either returns a value without
-making a recursive call, or returns directly the result of a recursive
-call).
-
-Multiple dispatch
--------------------------------------------
-
-There has been talk of implementing multiple dispatch (i.e. generic)
-functions in Python for over ten years. Last year for the first time
-something concrete was done and now in Python 3.4 we have a decorator
-``functools.singledispatch`` which can be used to implement generic
-functions. As the name implies, it has the restriction of being
-limited to single dispatch, i.e. it is able to dispatch on the first
-argument of the function only. The decorator module provide a
-decorator factory ``dispatch_on`` which can be used to implement generic
-functions dispatching on any argument; moreover it can manage
-dispatching on more than one argument and, of course, it is
-signature-preserving.
-
-Here I will give a very concrete example (taken from a real-life use
-case) where it is desiderable to dispatch on the second
-argument. Suppose you have an XMLWriter class, which is instantiated
-with some configuration parameters and has a ``.write`` method which
-is able to serialize objects to XML:
-
-.. code-block:: python
-
- class XMLWriter(object):
- def __init__(self, **config):
- self.cfg = config
-
- @dispatch_on('obj')
- def write(self, obj):
- raise NotImplementedError(type(obj))
-
-
-Here you want to dispatch on the second argument since the first, ``self``
-is already taken. The ``dispatch_on`` decorator factory allows you to specify
-the dispatch argument by simply passing its name as a string (notice
-that if you mispell the name you will get an error). The function
-decorated is turned into a generic function
-and it is the one which is called if there are no more specialized
-implementations. Usually such default function should raise a
-``NotImplementedError``, thus forcing people to register some implementation.
-The registration can be done with a decorator:
-
-.. code-block:: python
-
- @XMLWriter.write.register(float)
- def writefloat(self, obj):
- return '<float>%s</float>' % obj
-
-
-Now the XMLWriter is able to serialize floats:
-
-.. code-block:: python
-
- >>> writer = XMLWriter()
- >>> writer.write(2.3)
- '<float>2.3</float>'
-
-I could give a down-to-earth example of situations in which it is desiderable
-to dispatch on more than one argument (for instance once I implemented
-a database-access library where the first dispatching argument was the
-the database driver and the second one was the database record),
-but here I prefer to follow the tradition and show the time-honored
-Rock-Paper-Scissors example:
-
-.. code-block:: python
-
- class Rock(object):
- ordinal = 0
-
-.. code-block:: python
-
- class Paper(object):
- ordinal = 1
-
-.. code-block:: python
-
- class Scissors(object):
- ordinal = 2
-
-
-I have added an ordinal to the Rock-Paper-Scissors classes to simplify
-the implementation. The idea is to define a generic function ``win(a,
-b)`` of two arguments corresponding to the moves of the first and
-second player respectively. The moves are instances of the classes
-Rock, Paper and Scissors; Paper wins over Rock, Scissors wins over
-Paper and Rock wins over Scissors. The function will return +1 for a
-win, -1 for a loss and 0 for parity. There are 9 combinations, however
-combinations with the same ordinal (i.e. the same class) return 0;
-moreover by exchanging the order of the arguments the sign of the
-result changes, so it is enough to specify directly only 3
-implementations:
-
-.. code-block:: python
-
- @dispatch_on('a', 'b')
- def win(a, b):
- if a.ordinal == b.ordinal:
- return 0
- elif a.ordinal > b.ordinal:
- return -win(b, a)
- raise NotImplementedError((type(a), type(b)))
-
-.. code-block:: python
-
- @win.register(Rock, Paper)
- def winRockPaper(a, b):
- return -1
-
-.. code-block:: python
-
- @win.register(Paper, Scissors)
- def winPaperScissors(a, b):
- return -1
-
-.. code-block:: python
-
- @win.register(Rock, Scissors)
- def winRockScissors(a, b):
- return 1
-
-
-Here is the result:
-
-.. code-block:: python
-
- >>> win(Paper(), Rock())
- 1
- >>> win(Scissors(), Paper())
- 1
- >>> win(Rock(), Scissors())
- 1
- >>> win(Paper(), Paper())
- 0
- >>> win(Rock(), Rock())
- 0
- >>> win(Scissors(), Scissors())
- 0
- >>> win(Rock(), Paper())
- -1
- >>> win(Paper(), Scissors())
- -1
- >>> win(Scissors(), Rock())
- -1
-
-The point of generic functions is that they play well with subclassing.
-For instance, suppose we define a StrongRock which does not lose against
-Paper:
-
-.. code-block:: python
-
- class StrongRock(Rock):
- pass
-
-.. code-block:: python
-
- @win.register(StrongRock, Paper)
- def winStrongRockPaper(a, b):
- return 0
-
-
-Then we do not need to define other implementations, since they are
-inherited from the parent:
-
-.. code-block:: python
-
- >>> win(StrongRock(), Scissors())
- 1
-
-You can introspect the precedence used by the dispath algorithm by
-calling ``.dispatch_info(*types)``:
-
-.. code-block:: python
-
- >>> win.dispatch_info(StrongRock, Scissors)
- [('StrongRock', 'Scissors'), ('Rock', 'Scissors')]
-
-Since there is no direct implementation for (StrongRock, Scissors)
-the dispatcher will look at the implementation for (Rock, Scissors)
-which is available. Internally the algorithm is doing a cross
-product of the class precedence lists (or Method Resolution Orders,
-MRO_ for short) of StrongRock and Scissors respectively.
-
-.. _MRO: http://www.python.org/2.3/mro.html
-
-Generic functions and virtual ancestors
--------------------------------------------------
-
-Generic function implementations in Python are complicated by the
-existence of "virtual ancestors", i.e. superclasses which are not in
-the class hierarchy. Consider for instance this class:
-
-.. code-block:: python
-
- class WithLength(object):
- def __len__(self):
- return 0
-
-
-This class defines a ``__len__`` method and as such is
-considered to be a subclass of the abstract base class ``collections.Sized``:
-
-.. code-block:: python
-
- >>> issubclass(WithLength, collections.Sized)
- True
-
-However, ``collections.Sized`` is not in the MRO_ of ``WithLength``, it
-is not a true ancestor. Any implementation of generic functions, even
-with single dispatch, must go through some contorsion to take into
-account the virtual ancestors.
-
-In particular if we define a generic function
-
-.. code-block:: python
-
- @dispatch_on('obj')
- def get_length(obj):
- raise NotImplementedError(type(obj))
-
-
-implemented on all classes with a length
-
-.. code-block:: python
-
- @get_length.register(collections.Sized)
- def get_length_sized(obj):
- return len(obj)
-
-
-then ``get_length`` must be defined on ``WithLength`` instances
-
-.. code-block:: python
-
- >>> get_length(WithLength())
- 0
-
-even if ``collections.Sized`` is not a true ancestor of ``WithLength``.
-Of course this is a contrived example since you could just use the
-builtin ``len``, but you should get the idea.
-
-Since in Python it is possible to consider any instance of ABCMeta
-as a virtual ancestor of any other class (it is enough to register it
-as ``ancestor.register(cls)``), any implementation of generic functions
-must take virtual ancestors into account. Let me give an example.
-
-Suppose you are using a third party set-like class like
-the following:
-
-.. code-block:: python
-
- class SomeSet(collections.Sized):
- # methods that make SomeSet set-like
- # not shown ...
- def __len__(self):
- return 0
-
-
-Here the author of ``SomeSet`` made a mistake by not inheriting
-from ``collections.Set``, but only from ``collections.Sized``.
-
-This is not a problem since you can register *a posteriori*
-``collections.Set`` as a virtual ancestor of ``SomeSet``:
-
-.. code-block:: python
-
- >>> _ = collections.Set.register(SomeSet)
- >>> issubclass(SomeSet, collections.Set)
- True
-
-Now, let us define an implementation of ``get_length`` specific to set:
-
-.. code-block:: python
-
- @get_length.register(collections.Set)
- def get_length_set(obj):
- return 1
-
-
-The current implementation, as the one used by ``functools.singledispatch``,
-is able to discern that a ``Set`` is a ``Sized`` object, so the more specific
-implementation for ``Set`` is taken:
-
-.. code-block:: python
-
- >>> get_length(SomeSet()) # NB: the implementation for Sized would give 0
- 1
-
-Sometimes it is not clear how to dispatch. For instance, consider a
-class ``C`` registered both as ``collections.Iterable`` and
-``collections.Sized`` and define a generic function ``g`` with
-implementations both for ``collections.Iterable`` and
-``collections.Sized``. It is impossible to decide which implementation
-to use, since the ancestors are independent, and the following function
-will raise a RuntimeError when called:
-
-.. code-block:: python
-
- def singledispatch_example1():
- singledispatch = dispatch_on('obj')
-
- @singledispatch
- def g(obj):
- raise NotImplementedError(type(g))
-
- @g.register(collections.Sized)
- def g_sized(object):
- return "sized"
-
- @g.register(collections.Iterable)
- def g_iterable(object):
- return "iterable"
-
- g(C()) # RuntimeError: Ambiguous dispatch: Iterable or Sized?
-
-
-This is consistent with the "refuse the temptation to guess"
-philosophy. ``functools.singledispatch`` would raise a similar error.
-
-It would be easy to rely on the order of registration to decide the
-precedence order. This is reasonable, but also fragile: if during some
-refactoring you change the registration order by mistake, a different
-implementation could be taken. If implementations of the generic
-functions are distributed across modules, and you change the import
-order, a different implementation could be taken. So the decorator
-module prefers to raise an error in the face of ambiguity. This is the
-same approach taken by the standard library.
-
-However, it should be noticed that the dispatch
-algorithm used by the decorator module is different from the one used
-by the standard library, so there are cases where you will get
-different answers. The difference is that ``functools.singledispatch``
-tries to insert the virtual ancestors *before* the base classes, whereas
-``decorator.dispatch_on`` tries to insert them *after* the base classes.
-I will give an example showing the difference:
-
-.. code-block:: python
-
- def singledispatch_example2():
- # adapted from functools.singledispatch test case
- singledispatch = dispatch_on('arg')
-
- class S(object):
- pass
-
- class V(c.Sized, S):
- def __len__(self):
- return 0
-
- @singledispatch
- def g(arg):
- return "base"
-
- @g.register(S)
- def g_s(arg):
- return "s"
-
- @g.register(c.Container)
- def g_container(arg):
- return "container"
-
- v = V()
- assert g(v) == "s"
- c.Container.register(V) # add c.Container to the virtual mro of V
- assert g(v) == "s" # since the virtual mro is V, Sized, S, Container
- return g, V
-
-
-If you play with this example and replace the ``singledispatch`` definition
-with ``functools.singledispatch``, the assert will break: ``g`` will return
-``"container"`` instead of ``"s"``, because ``functools.singledispatch``
-will insert the ``Container`` class right before ``S``.
-The only way to understand what is happening here is to scratch your
-head by looking at the implementations. I will just notice that
-``.dispatch_info`` is quite useful:
-
-.. code-block:: python
-
- >>> g, V = singledispatch_example2()
- >>> g.dispatch_info(V)
- [('V',), ('Sized',), ('S',), ('Container',)]
-
-The current implementation does not implement any kind of cooperation
-between implementations, i.e. there is nothing akin to call-next-method
-in Lisp, nor akin to ``super`` in Python.
-
-Finally, let me notice that the decorator module implementation does
-not use any cache, whereas the one in ``singledispatch`` has a cache.
-
-Caveats and limitations
--------------------------------------------
-
-One thing you should be aware of, is the performance penalty of decorators.
-The worse case is shown by the following example::
-
- $ cat performance.sh
- python3 -m timeit -s "
- from decorator import decorator
-
- @decorator
- def do_nothing(func, *args, **kw):
- return func(*args, **kw)
-
- @do_nothing
- def f():
- pass
- " "f()"
-
- python3 -m timeit -s "
- def f():
- pass
- " "f()"
-
-On my laptop, using the ``do_nothing`` decorator instead of the
-plain function is five times slower::
-
- $ bash performance.sh
- 1000000 loops, best of 3: 1.39 usec per loop
- 1000000 loops, best of 3: 0.278 usec per loop
-
-It should be noted that a real life function would probably do
-something more useful than ``f`` here, and therefore in real life the
-performance penalty could be completely negligible. As always, the
-only way to know if there is
-a penalty in your specific use case is to measure it.
-
-More importantly, you should be aware that decorators will make your
-tracebacks longer and more difficult to understand. Consider this
-example:
-
-.. code-block:: python
-
- >>> @trace
- ... def f():
- ... 1/0
-
-Calling ``f()`` will give you a ``ZeroDivisionError``, but since the
-function is decorated the traceback will be longer:
-
-.. code-block:: python
-
- >>> f()
- Traceback (most recent call last):
- ...
- File "<string>", line 2, in f
- File "<doctest __main__[22]>", line 4, in trace
- return f(*args, **kw)
- File "<doctest __main__[51]>", line 3, in f
- 1/0
- ZeroDivisionError: ...
-
-You see here the inner call to the decorator ``trace``, which calls
-``f(*args, **kw)``, and a reference to ``File "<string>", line 2, in f``.
-This latter reference is due to the fact that internally the decorator
-module uses ``exec`` to generate the decorated function. Notice that
-``exec`` is *not* responsibile for the performance penalty, since is the
-called *only once* at function decoration time, and not every time
-the decorated function is called.
-
-At present, there is no clean way to avoid ``exec``. A clean solution
-would require to change the CPython implementation of functions and
-add an hook to make it possible to change their signature directly.
-However, at present, even in Python 3.5 it is impossible to change the
-function signature directly, therefore the ``decorator`` module is
-still useful. Actually, this is the main reasons why I keep
-maintaining the module and releasing new versions. It should be
-noticed that in Python 3.5 a lot of improvements have been made: in
-that version you can decorated a function with
-``func_tools.update_wrapper`` and ``pydoc`` will see the correct
-signature; still internally the function will have an incorrect
-signature, as you can see by using ``inspect.getfullargspec``: all
-documentation tools using such function (which has been correctly
-deprecated) will see the wrong signature.
-
-.. _362: http://www.python.org/dev/peps/pep-0362
-
-In the present implementation, decorators generated by ``decorator``
-can only be used on user-defined Python functions or methods, not on generic
-callable objects, nor on built-in functions, due to limitations of the
-``inspect`` module in the standard library, especially for Python 2.X
-(in Python 3.5 a lot of such limitations have been removed).
-
-There is a restriction on the names of the arguments: for instance,
-if try to call an argument ``_call_`` or ``_func_``
-you will get a ``NameError``:
-
-.. code-block:: python
-
- >>> @trace
- ... def f(_func_): print(f)
- ...
- Traceback (most recent call last):
- ...
- NameError: _func_ is overridden in
- def f(_func_):
- return _call_(_func_, _func_)
-
-Finally, the implementation is such that the decorated function makes
-a (shallow) copy of the original function dictionary:
-
-.. code-block:: python
-
- >>> def f(): pass # the original function
- >>> f.attr1 = "something" # setting an attribute
- >>> f.attr2 = "something else" # setting another attribute
-
- >>> traced_f = trace(f) # the decorated function
-
- >>> traced_f.attr1
- 'something'
- >>> traced_f.attr2 = "something different" # setting attr
- >>> f.attr2 # the original attribute did not change
- 'something else'
-
-.. _function annotations: http://www.python.org/dev/peps/pep-3107/
-.. _docutils: http://docutils.sourceforge.net/
-.. _pygments: http://pygments.org/
-
-LICENSE
----------------------------------------------
-
-Copyright (c) 2005-2015, Michele Simionato
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- Redistributions in bytecode form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-If you use this software and you are happy with it, consider sending me a
-note, just to gratify my ego. On the other hand, if you use this software and
-you are unhappy with it, send me a patch!
diff --git a/docs/index.html b/docs/index.html
deleted file mode 100644
index ebd74ac..0000000
--- a/docs/index.html
+++ /dev/null
@@ -1,403 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.12: http://docutils.sourceforge.net/" />
-<title>Decorator module</title>
-<meta name="author" content="Michele Simionato" />
-<style type="text/css">
-
-/*
-:Author: David Goodger (goodger@python.org)
-:Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
-:Copyright: This stylesheet has been placed in the public domain.
-
-Default cascading style sheet for the HTML output of Docutils.
-
-See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
-customize this style sheet.
-*/
-
-/* used to remove borders from tables and images */
-.borderless, table.borderless td, table.borderless th {
- border: 0 }
-
-table.borderless td, table.borderless th {
- /* Override padding for "table.docutils td" with "! important".
- The right padding separates the table cells. */
- padding: 0 0.5em 0 0 ! important }
-
-.first {
- /* Override more specific margin styles with "! important". */
- margin-top: 0 ! important }
-
-.last, .with-subtitle {
- margin-bottom: 0 ! important }
-
-.hidden {
- display: none }
-
-a.toc-backref {
- text-decoration: none ;
- color: black }
-
-blockquote.epigraph {
- margin: 2em 5em ; }
-
-dl.docutils dd {
- margin-bottom: 0.5em }
-
-object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
- overflow: hidden;
-}
-
-/* Uncomment (and remove this text!) to get bold-faced definition list terms
-dl.docutils dt {
- font-weight: bold }
-*/
-
-div.abstract {
- margin: 2em 5em }
-
-div.abstract p.topic-title {
- font-weight: bold ;
- text-align: center }
-
-div.admonition, div.attention, div.caution, div.danger, div.error,
-div.hint, div.important, div.note, div.tip, div.warning {
- margin: 2em ;
- border: medium outset ;
- padding: 1em }
-
-div.admonition p.admonition-title, div.hint p.admonition-title,
-div.important p.admonition-title, div.note p.admonition-title,
-div.tip p.admonition-title {
- font-weight: bold ;
- font-family: sans-serif }
-
-div.attention p.admonition-title, div.caution p.admonition-title,
-div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title, .code .error {
- color: red ;
- font-weight: bold ;
- font-family: sans-serif }
-
-/* Uncomment (and remove this text!) to get reduced vertical space in
- compound paragraphs.
-div.compound .compound-first, div.compound .compound-middle {
- margin-bottom: 0.5em }
-
-div.compound .compound-last, div.compound .compound-middle {
- margin-top: 0.5em }
-*/
-
-div.dedication {
- margin: 2em 5em ;
- text-align: center ;
- font-style: italic }
-
-div.dedication p.topic-title {
- font-weight: bold ;
- font-style: normal }
-
-div.figure {
- margin-left: 2em ;
- margin-right: 2em }
-
-div.footer, div.header {
- clear: both;
- font-size: smaller }
-
-div.line-block {
- display: block ;
- margin-top: 1em ;
- margin-bottom: 1em }
-
-div.line-block div.line-block {
- margin-top: 0 ;
- margin-bottom: 0 ;
- margin-left: 1.5em }
-
-div.sidebar {
- margin: 0 0 0.5em 1em ;
- border: medium outset ;
- padding: 1em ;
- background-color: #ffffee ;
- width: 40% ;
- float: right ;
- clear: right }
-
-div.sidebar p.rubric {
- font-family: sans-serif ;
- font-size: medium }
-
-div.system-messages {
- margin: 5em }
-
-div.system-messages h1 {
- color: red }
-
-div.system-message {
- border: medium outset ;
- padding: 1em }
-
-div.system-message p.system-message-title {
- color: red ;
- font-weight: bold }
-
-div.topic {
- margin: 2em }
-
-h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
-h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
- margin-top: 0.4em }
-
-h1.title {
- text-align: center }
-
-h2.subtitle {
- text-align: center }
-
-hr.docutils {
- width: 75% }
-
-img.align-left, .figure.align-left, object.align-left {
- clear: left ;
- float: left ;
- margin-right: 1em }
-
-img.align-right, .figure.align-right, object.align-right {
- clear: right ;
- float: right ;
- margin-left: 1em }
-
-img.align-center, .figure.align-center, object.align-center {
- display: block;
- margin-left: auto;
- margin-right: auto;
-}
-
-.align-left {
- text-align: left }
-
-.align-center {
- clear: both ;
- text-align: center }
-
-.align-right {
- text-align: right }
-
-/* reset inner alignment in figures */
-div.align-right {
- text-align: inherit }
-
-/* div.align-center * { */
-/* text-align: left } */
-
-ol.simple, ul.simple {
- margin-bottom: 1em }
-
-ol.arabic {
- list-style: decimal }
-
-ol.loweralpha {
- list-style: lower-alpha }
-
-ol.upperalpha {
- list-style: upper-alpha }
-
-ol.lowerroman {
- list-style: lower-roman }
-
-ol.upperroman {
- list-style: upper-roman }
-
-p.attribution {
- text-align: right ;
- margin-left: 50% }
-
-p.caption {
- font-style: italic }
-
-p.credits {
- font-style: italic ;
- font-size: smaller }
-
-p.label {
- white-space: nowrap }
-
-p.rubric {
- font-weight: bold ;
- font-size: larger ;
- color: maroon ;
- text-align: center }
-
-p.sidebar-title {
- font-family: sans-serif ;
- font-weight: bold ;
- font-size: larger }
-
-p.sidebar-subtitle {
- font-family: sans-serif ;
- font-weight: bold }
-
-p.topic-title {
- font-weight: bold }
-
-pre.address {
- margin-bottom: 0 ;
- margin-top: 0 ;
- font: inherit }
-
-pre.literal-block, pre.doctest-block, pre.math, pre.code {
- margin-left: 2em ;
- margin-right: 2em }
-
-pre.code .ln { color: grey; } /* line numbers */
-pre.code, code { background-color: #eeeeee }
-pre.code .comment, code .comment { color: #5C6576 }
-pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
-pre.code .literal.string, code .literal.string { color: #0C5404 }
-pre.code .name.builtin, code .name.builtin { color: #352B84 }
-pre.code .deleted, code .deleted { background-color: #DEB0A1}
-pre.code .inserted, code .inserted { background-color: #A3D289}
-
-span.classifier {
- font-family: sans-serif ;
- font-style: oblique }
-
-span.classifier-delimiter {
- font-family: sans-serif ;
- font-weight: bold }
-
-span.interpreted {
- font-family: sans-serif }
-
-span.option {
- white-space: nowrap }
-
-span.pre {
- white-space: pre }
-
-span.problematic {
- color: red }
-
-span.section-subtitle {
- /* font-size relative to parent (h1..h6 element) */
- font-size: 80% }
-
-table.citation {
- border-left: solid 1px gray;
- margin-left: 1px }
-
-table.docinfo {
- margin: 2em 4em }
-
-table.docutils {
- margin-top: 0.5em ;
- margin-bottom: 0.5em }
-
-table.footnote {
- border-left: solid 1px black;
- margin-left: 1px }
-
-table.docutils td, table.docutils th,
-table.docinfo td, table.docinfo th {
- padding-left: 0.5em ;
- padding-right: 0.5em ;
- vertical-align: top }
-
-table.docutils th.field-name, table.docinfo th.docinfo-name {
- font-weight: bold ;
- text-align: left ;
- white-space: nowrap ;
- padding-left: 0 }
-
-/* "booktabs" style (no vertical lines) */
-table.docutils.booktabs {
- border: 0px;
- border-top: 2px solid;
- border-bottom: 2px solid;
- border-collapse: collapse;
-}
-table.docutils.booktabs * {
- border: 0px;
-}
-table.docutils.booktabs th {
- border-bottom: thin solid;
- text-align: left;
-}
-
-h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
-h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
- font-size: 100% }
-
-ul.auto-toc {
- list-style-type: none }
-
-</style>
-</head>
-<body>
-<div class="document" id="decorator-module">
-<h1 class="title">Decorator module</h1>
-<table class="docinfo" frame="void" rules="none">
-<col class="docinfo-name" />
-<col class="docinfo-content" />
-<tbody valign="top">
-<tr><th class="docinfo-name">Author:</th>
-<td>Michele Simionato</td></tr>
-<tr class="field"><th class="docinfo-name">E-mail:</th><td class="field-body"><a class="reference external" href="mailto:michele.simionato&#64;gmail.com">michele.simionato&#64;gmail.com</a></td>
-</tr>
-<tr class="field"><th class="docinfo-name">Requires:</th><td class="field-body">Python 2.6+</td>
-</tr>
-<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/decorator">http://pypi.python.org/pypi/decorator</a></td>
-</tr>
-<tr class="field"><th class="docinfo-name">Installation:</th><td class="field-body"><tt class="docutils literal">pip install decorator</tt></td>
-</tr>
-<tr class="field"><th class="docinfo-name">License:</th><td class="field-body">BSD license</td>
-</tr>
-</tbody>
-</table>
-<div class="section" id="installation">
-<h1>Installation</h1>
-<p>If you are lazy, just perform</p>
-<blockquote>
-<cite>$ pip install decorator</cite></blockquote>
-<p>which will install just the module on your system.</p>
-<p>If you prefer to install the full distribution from source, including
-the documentation, download the <a class="reference external" href="http://pypi.python.org/pypi/decorator">tarball</a>, unpack it and run</p>
-<blockquote>
-<cite>$ python setup.py install</cite></blockquote>
-<p>in the main directory, possibly as superuser.</p>
-</div>
-<div class="section" id="testing">
-<h1>Testing</h1>
-<p>Run</p>
-<blockquote>
-<cite>$ python src/tests/test.py -v</cite></blockquote>
-<p>or (if you have setuptools installed)</p>
-<blockquote>
-<cite>$ python setup.py test</cite></blockquote>
-<p>Notice that you may run into trouble if in your system there
-is an older version of the decorator module; in such a case remove the
-old version. It is safe even to copy the module <cite>decorator.py</cite> over
-an existing one, since version 4.0 is backward-compatible.</p>
-</div>
-<div class="section" id="documentation">
-<h1>Documentation</h1>
-<p>There are various versions of the documentation:</p>
-<ul class="simple">
-<li><a class="reference external" href="https://github.com/micheles/decorator/blob/4.0.0/docs/documentation.rst">HTML version</a></li>
-<li><a class="reference external" href="https://github.com/micheles/decorator/blob/4.0.0/docs/documentation.pdf">PDF version</a></li>
-</ul>
-</div>
-<div class="section" id="repository">
-<h1>Repository</h1>
-<p>The project is hosted on GitHub. You can look at the source here:</p>
-<blockquote>
-<a class="reference external" href="https://github.com/micheles/decorator">https://github.com/micheles/decorator</a></blockquote>
-</div>
-</div>
-</body>
-</html>
diff --git a/docs/documentation.pdf b/documentation.pdf
index 20cfdce..f448e99 100644
--- a/docs/documentation.pdf
+++ b/documentation.pdf
@@ -265,7 +265,7 @@ endobj
<< /Outlines 82 0 R /PageLabels 123 0 R /PageMode /UseNone /Pages 102 0 R /Type /Catalog >>
endobj
81 0 obj
-<< /Author (Michele Simionato) /CreationDate (D:20150724191345-01'00') /Creator (\(unspecified\)) /Keywords () /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\))
+<< /Author (Michele Simionato) /CreationDate (D:20150726073553-01'00') /Creator (\(unspecified\)) /Keywords () /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\))
/Title (The decorator module) >>
endobj
82 0 obj
@@ -398,7 +398,7 @@ q
1 0 0 1 91.03937 3 cm
q
0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (4.0.0 \(2015-07-24\)) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (4.0.0 \(2015-07-25\)) Tj T* ET
Q
Q
q
@@ -8753,7 +8753,7 @@ xref
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(W\233#\215\347\022,\262\005\255\014\35483\375\026) (W\233#\215\347\022,\262\005\255\014\35483\375\026)]
+ [(\324>EL\326}\272\001]o/\2719G\020a) (\324>EL\326}\272\001]o/\2719G\020a)]
/Info 81 0 R /Root 80 0 R /Size 144 >>
startxref
307933