M docs/acknowledgements.rst +2 -2
@@ 1,9 1,9 @@
Acknowledgements
================
Guido van Rossum created the core of this package. I just renamed some things
-and added some convenience stuff. Thank you Guido!
+and added some^H^H^H^H oodles of convenience stuff. Thank you Guido!
Copyright
=========
© 2006-2013 Python Software Foundation.
-© 2013-2017 Gerald Klix.
+© 2013-2018 Gerald Klix.
M docs/api.rst +199 -3
@@ 183,9 183,9 @@ or the :meth:`<generic>.method` method.
def varfun1(tc: TC, o1: object, o2: object: o3: object, o4: object):
return (tc,) + (o4, o3, o2, o1)
- Overlaps of variadic method definitions are always resolved
- towards the method with the explicitly specified types.
-
+ Overlaps of variadic method definitions with non-variadic method
+ definitions are always resolved towards the non-variadic method
+ with the explicitly specified types.
.. decorator:: <generic>.method(implementation_function)
@@ 228,11 228,38 @@ or the :meth:`<generic>.method` method.
Calling Other Multi-Methods of The Same Generic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+:mod:`gf` implements two ways to calls other methods of
+the same generic.
+
+New Style of :class:`super` Calls
+.................................
+
+The new way of calling other methods with the same arity of the same
+generic (mis)uses the built-in :class:`super` type.
+
+:class:`super` can be used to define :func:`foo` for integers:
+
+ >>> @method()
+ ... def foo(an_integer: int):
+ ... return foo(super(str, str(an_integer)))
+
+Calling :func:`foo` with an integer now works as expected:
+
+ >>> foo(42)
+ '<42>'
+
+Old Style of :class:`super` Calls
+.................................
+
+.. note:: This way of calling other methods of a generic
+ function is deprecated.
+
As it is sometimes necessary with ordinary single dispatch methods
to call methods defined in a base class, it it is sometimes
necessary to reuse other implementations of a generic.
For this purpose the generic has :meth:`super`-method.
+.. deprecated:: 0.2
.. method:: <generic>.super(*types)(*arguments)
:param type types: An optionally empty list of built-in types or
@@ 264,6 291,175 @@ For this purpose the generic has :meth:`
are actually instances of `types`. This is consistent
with Python's notion of duck typing.
+Dispatch on Instances
+~~~~~~~~~~~~~~~~~~~~~
+
+Since version 0.2 :mod:`gf`'s
+default dispatch algorithm dispatches on single instances, too:
+
+ >>> silly = generic('silly')
+ >>> @method()
+ ... def silly(bla: str):
+ ... return '<S|' + bla + '|S>'
+
+Thus we can call :func:`silly` with a string:
+
+ >>> silly('Hello')
+ '<S|Hello|S>'
+
+But we can also define :func:`silly` for two integers:
+
+ >>> @method()
+ ... def silly(hitchhiker: 42, star_trek: 47):
+ ... return 'Bingo'
+
+Now we can call :func:`silly` with exactly the right numbers:
+
+ >>> silly(42, 47)
+ 'Bingo'
+
+But calling silly with others fails like this:
+
+ >>> silly(21, 21)
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: Generic 'silly' has no implementation for type(s): builtins.int, builtins.int
+
+The old behavior can be achieved by using the dispatch type
+:attr:`Dispatch.ON_CLASS`.
+
+ >>> from gf import Dispatch
+ >>> even_sillier = generic(Dispatch.ON_CLASS)
+ >>> @method()
+ ... def even_sillier(bla: str):
+ ... return '<SS|' + bla + '|SS>'
+
+Thus we can call :func:`even_sillier` with a string:
+
+ >>> even_sillier('Hello')
+ '<SS|Hello|SS>'
+
+But we can't define :func:`even_sillier` for two integers:
+
+ >>> @method()
+ ... def even_sillier(hitchhiker: 42, star_trek: 47):
+ ... return 'Bingo'
+ Traceback (most recent call last):
+ ...
+ TypeError: Can't dispatch on instances in state: Dispatch.ON_CLASS
+
+.. note:: The enumeration :class:`Dispatch` also has the option
+ :attr:`ON_OBJECT`, which is the new default for generic functions.
+
+Class-Generics
+~~~~~~~~~~~~~~
+
+Since release 0.2 :mod:`gf` has some means to define the equivalent
+of a class function with generic functions. This capability is defined
+on a per :func:`generic` basis and not -- as one might expect -- on
+a per :func:`method` basis.
+
+The following example will explain this feature:
+
+ >>> cm = generic(
+ ... 'cm',
+ ... """A class method (sort of)""",
+ ... Dispatch.ON_OBJECT_AND_CLASS_HIERARCHY)
+
+
+One now can add methods to :func:`cm` that dispatch on the class
+passed:
+
+ >>> @method()
+ ... def cm(integer: int):
+ ... return 'Integer'
+ >>> @method()
+ ... def cm(string: str):
+ ... return 'String'
+
+This way we can dispatch on classes like:
+
+ >>> cm(int)
+ 'Integer'
+ >>> cm(str)
+ 'String'
+ >>> cm(1)
+ 'Integer'
+ >>> cm('Sepp')
+ 'String'
+
+With the same dispatch type it is also possible to dispatch on instances:
+
+ >>> @method()
+ ... def cm(wow: 42):
+ ... return 'Jackpot'
+ >>> cm(42)
+ 'Jackpot'
+ >>> cm(4711)
+ 'Integer'
+
+The normal -- and also the pre version 0.2 -- behavior is to dispatch
+on the type of an instance only:
+
+ >>> im = generic(
+ ... 'im',
+ ... """An instance method""",
+ ... Dispatch.ON_OBJECT)
+
+
+One now can add methods to :func:`im` that dispatch on the class
+of an instance passed as argument:
+
+ >>> @method()
+ ... def im(integer: int):
+ ... return 'Integer'
+ >>> @method()
+ ... def im(string: str):
+ ... return 'String'
+
+But we can't dispatch on class arguments:
+
+ >>> im(int)
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: Generic 'im' has no implementation for type(s): builtins.type
+ >>> im(str)
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: Generic 'im' has no implementation for type(s): builtins.type
+ >>> im(1)
+ 'Integer'
+ >>> im('Sepp')
+ 'String'
+
+
+Since the type of class is :class:`type` we can write one method
+to dispatch on all classes:
+
+ >>> @method()
+ ... def im(cls: type):
+ ... return 'Class'
+
+and get at least:
+
+ >>> im(int)
+ 'Class'
+ >>> im(str)
+ 'Class'
+
+
+
+As mentioned above, it is also possible to dispatch on instances
+with the default dispatch type :attr:`Dispatch.ON_OBJECT`:
+
+ >>> @method()
+ ... def im(wow: 42):
+ ... return 'Oh Baby'
+ >>> im(42)
+ 'Oh Baby'
+ >>> im(4711)
+ 'Integer'
+
Advanced Usage
--------------
M docs/conf.py +11 -6
@@ 28,7 28,12 @@ sys.path.insert(0, os.path.abspath(os.pa
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
#o#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.doctest',
+ 'sphinx.ext.ifconfig',
+ 'sphinx.ext.viewcode'
+]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ 44,16 49,16 @@ master_doc = 'index'
# General information about the project.
project = 'gf'
-copyright = '2006-2013 PSF, 2013-2017 Gerald Klix'
+copyright = '2006-2013 PSF, 2013-2018 Gerald Klix'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '0.2.0'
+version = '0.2'
# The full version, including alpha/beta/rc tags.
-release = '0.2.0b'
+release = '0.2.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ 97,7 102,7 @@ exclude_patterns = ['_build']
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
+html_theme = 'python_docs_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ 258,7 263,7 @@ texinfo_documents = [
epub_title = u'gf'
epub_author = u'Gerald Klix'
epub_publisher = u'Gerald Klix'
-epub_copyright = u'2013-2017, Gerald Klix'
+epub_copyright = u'2013-2018, Gerald Klix'
# The language of the text. It defaults to the language option
# or en if the language is not set.
M docs/overview.rst +8 -1
@@ 117,14 117,21 @@ Release 0.2.0
The following was change in Release 0.2.0:
- * Ported the whole module to Python 3.6.
+ * Ported the whole module to Python 3.6 and Python 3.7.
* Exclusively uses `parameter annotations`_ to specify the types to dispatch on.
* Added standard conforming default implementations for methods
like :meth:`__add__`. All these methods now raise a proper
`TypeError` instead of raising a `NotImplementedError`.
+ * Added some means to write generic functions that dispatch types only.
+ This is the generic function equivalent of a class-method.
+ * Added some means to dispatch on single objects.
+ This is the equivalent adding methods to class-instances [#]_.
.. _parameter annotations: https://docs.python.org/3/reference/compound_stmts.html#grammar-token-parameter
+.. [#] Of course this is not possible with standard python classes
+ and their instances.
+
Release 0.1.4
~~~~~~~~~~~~~
M setup.py +4 -3
@@ 25,8 25,8 @@ except IOError:
sys.path.insert(0, "tests")
-setup(name="gf",
- version='0.2.0b',
+setup(name="gf3",
+ version='0.2.0',
description="A package with lisp-like generic functions for python 3.",
long_description = long_description,
keywords="generic-function multi-method",
@@ 35,6 35,7 @@ setup(name="gf",
"Intended Audience :: Developers",
"License :: OSI Approved :: Python Software Foundation License",
"Operating System :: OS Independent",
+ "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation",
@@ 43,7 44,7 @@ setup(name="gf",
author="Gerald Klix",
author_email="gf@klix.ch",
packages=['gf'],
- url="http://pypi.python.org/pypi/gf3",
+ url="https://pythonhosted.org/gf3/",
zip_safe=True,
test_suite="testgo",
license="PSF",