From 73e7d1d2dfff8a6103faad7ee608083231c28be6 Mon Sep 17 00:00:00 2001 From: jason kirtland Date: Mon, 15 Feb 2010 16:35:48 -0800 Subject: Sphinx documentation. --- docs/source/Makefile | 45 ++++++++++ docs/source/api.rst | 39 ++++++++ docs/source/conf.py | 206 ++++++++++++++++++++++++++++++++++++++++++ docs/source/index.rst | 42 +++++++++ docs/source/signals.rst | 233 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 565 insertions(+) create mode 100644 docs/source/Makefile create mode 100644 docs/source/api.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/signals.rst (limited to 'docs') diff --git a/docs/source/Makefile b/docs/source/Makefile new file mode 100644 index 0000000..d524eb7 --- /dev/null +++ b/docs/source/Makefile @@ -0,0 +1,45 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build + +# Internal variables. +ALLSPHINXOPTS = -d ../doctrees $(SPHINXOPTS) . + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " text to make standalone text files" + @echo " sdist to build documentation for release" + @echo " doctest to run doctests" + @echo " pickles to build pickles" + @echo " clean to remove generated artifacts" + +sdist: clean text html + +clean: + for i in doctrees html text doctest pickles; do \ + rm -rf ../$$i; \ + done + +html: + mkdir -p ../html ../doctrees _static _template + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ../html + @echo + @echo "Build finished. The HTML pages are in ../html." + +text: + mkdir -p ../text ../doctrees + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) ../text + @echo + @echo "Build finished. The text pages are in ../text." + +doctest: + mkdir -p ../doctrees ../doctest + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) ../doctest + +pickles: + mkdir -p ../pickles ../doctest + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) ../pickles diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000..e80684d --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,39 @@ +.. _api: + +API Documentation +================= + +All public API members can (and should) be imported from ``blinker``:: + + from blinker import ANY, signal + +.. currentmodule:: blinker.base + +Basic Signals +------------- + +.. autoattribute:: blinker.base.ANY + +.. autoattribute:: blinker.base.receiver_connected + +.. autoclass:: Signal + :members: + :undoc-members: + +Named Signals +------------- + +.. function:: signal(name, doc=None) + + Return the :class:`NamedSignal` *name*, creating it if required. + + Repeated calls to this function will return the same signal object. + Signals are created in a global :class:`Namespace`. + +.. autoclass:: NamedSignal + :show-inheritance: + :members: + +.. autoclass:: Namespace + :show-inheritance: + :members: signal diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..c4adb72 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +# +# Blinker documentation build configuration file, created by +# sphinx-quickstart on Mon Feb 15 10:54:13 2010. +# +# This file is execfile()d with the current directory set to its containing +# dir. + +import os +import sys + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +sys.path.append(os.path.abspath('../../')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.coverage'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Blinker' +copyright = u'2010, Jason Kirtland' + +# 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.9' +# The full version, including alpha/beta/rc tags. +release = '0.9dev' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = [] + +autoclass_content = "both" +autodoc_member_order = "groupwise" +import sphinx.ext.autodoc +sphinx.ext.autodoc.AttributeDocumenter.member_order = 25 +sphinx.ext.autodoc.InstanceAttributeDocumenter.member_order = 26 + + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# 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 +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Blinkerdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Blinker.tex', u'Blinker Documentation', + u'Jason Kirtland', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..8a594bc --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,42 @@ +Blinker Documentation +===================== + +Blinker provides fast & simple object-to-object and broadcast +signaling for Python objects. + +The core of Blinker is quite small but provides powerful features: + + - a global registry of named signals + - anonymous signals + - custom name registries + - permanently or temporarily connected receivers + - automatically disconnected receivers via weak referencing + - sending arbitrary data payloads + - collecting return values from signal receivers + + +Requirements +------------ + +Python 2.4 or later. No other modules are required. + +As of Blinker 0.8, Python 3.1 passes all tests except for weakly +binding to instance methods. + + +License +------- + +Blinker is provided under the MIT License. + + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + signals + api + + diff --git a/docs/source/signals.rst b/docs/source/signals.rst new file mode 100644 index 0000000..8bb967a --- /dev/null +++ b/docs/source/signals.rst @@ -0,0 +1,233 @@ +======= +Signals +======= + +.. currentmodule:: blinker.base + +Decoupling With Named Signals +----------------------------- + +Named signals are created with :func:`signal`: + +.. doctest:: + + >>> from blinker import signal + >>> initialized = signal('initialized') + >>> initialized is signal('initialized') + True + +Every call to ``signal('name')`` returns the same signal object, +allowing unconnected parts of code (different modules, plugins, +anything) to all use the same signal without requiring any code +sharing or special imports. + + +Subscribing to Signals +---------------------- + +:meth:`Signal.connect` registers a function to be invoked each time +the signal is emitted. Connected functions are always passed the +object that caused the signal to be emitted. + +.. doctest:: + + >>> def subscriber(sender): + ... print("Got a signal sent by %r" % sender) + ... + >>> ready = signal('ready') + >>> ready.connect(subscriber) + + + +Emitting Signals +---------------- + +Code producing events of interest can :meth:`Signal.send` +notifications to all connected receivers. + +Below, a simple ``Processor`` class emits a ``ready`` signal when it's +about to process something, and ``complete`` when it is done. It +passes ``self`` to the :meth:`~Signal.send` method, signifying that +that particular instance was responsible for emitting the signal. + +.. doctest:: + + >>> class Processor: + ... def __init__(self, name): + ... self.name = name + ... + ... def go(self): + ... ready = signal('ready') + ... ready.send(self) + ... print("Processing.") + ... complete = signal('complete') + ... complete.send(self) + ... + ... def __repr__(self): + ... return '' % self.name + ... + >>> processor_a = Processor('a') + >>> processor_a.go() + Got a signal sent by + Processing. + +Notice the ``complete`` signal in ``go()``? No receivers have +connected to ``complete`` yet, and that's a-ok. Calling +:meth:`~Signal.send` on a signal with no receivers will result in no +notifications being sent, and these no-op sends are optimized to be as +inexpensive as possible. + + +Subscribing to Specific Senders +------------------------------- + +The default connection to a signal invokes the receiver function when +any sender emits it. The :meth:`Signal.connect` function accepts an +optional argument to restrict the subscription to one specific sending +object: + +.. doctest:: + + >>> def b_subscriber(sender): + ... print("Caught signal from processor_b.") + ... assert sender.name == 'b' + ... + >>> processor_b = Processor('b') + >>> ready.connect(b_subscriber, sender=processor_b) + + +This function has been subscribed to ``ready`` but only when sent by +``processor_b``: + +.. doctest:: + + >>> processor_a.go() + Got a signal sent by + Processing. + >>> processor_b.go() + Got a signal sent by + Caught signal from processor_b. + Processing. + + +Sending and Receiving Data Through Signals +------------------------------------------ + +Additional keyword arguments can be passed to :meth:`~Signal.send`. +These will in turn be passed to the connected functions: + +.. doctest:: + + >>> send_data = signal('send-data') + >>> @send_data.connect + ... def receive_data(sender, **kw): + ... print("Caught signal from %r, data %r" % (sender, kw)) + ... return 'received!' + ... + >>> result = send_data.send('anonymous', abc=123) + Caught signal from 'anonymous', data {'abc': 123} + +The return value of :meth:`~Signal.send` collects the return values of +each connected function as a list of (``receiver function``, ``return +value``) pairs: + +.. doctest:: + + >>> result + [(, 'received!')] + + +Anonymous Signals +----------------- + +Signals need not be named. The :class:`Signal` constructor creates a +unique signal each time it is invoked. For example, an alternative +implementation of the Processor from above might provide the +processing signals as class attributes: + +.. doctest:: + + >>> from blinker import Signal + >>> class AltProcessor: + ... on_ready = Signal() + ... on_complete = Signal() + ... + ... def __init__(self, name): + ... self.name = name + ... + ... def go(self): + ... self.on_ready.send(self) + ... print("Alternate processing.") + ... self.on_complete.send(self) + ... + ... def __repr__(self): + ... return '' % self.name + ... + +``connect`` as a Decorator +-------------------------- + +You may have noticed the return value of :meth:`~Signal.connect` in +the console output in the sections above. This allows ``connect`` to +be used as a decorator on functions: + +.. doctest:: + + >>> apc = AltProcessor('c') + >>> @apc.on_complete.connect + ... def completed(sender): + ... print "AltProcessor %s completed!" % sender.name + ... + >>> apc.go() + Alternate processing. + AltProcessor c completed! + +While convenient, this form unfortunately does not allow the +``sender`` or ``weak`` arguments to be customized for the connected +function. + + +Optimizing Signal Sending +------------------------- + +Signals are optimized to send very quickly, whether receivers are +connected or not. If the data to be sent down a signal is very +expensive, it can be more efficient to check to see if any receivers +are connected first by testing the :attr:`~Signal.receivers` property: + +.. doctest:: + + >>> bool(signal('ready').receivers) + True + >>> bool(signal('complete').receivers) + False + >>> bool(AltProcessor.on_complete.receivers) + True + +Checking for a receiver listening for a particular sender is also +possible: + +.. doctest:: + + >>> signal('ready').has_receivers_for(processor_a) + True + +Documenting Signals +------------------- + +Both named and anonymous signals can be passed a ``doc`` argument at +construction to set the pydoc help text for the signal. This +documentation will be picked up by most documentation generators (such +as sphinx) and is nice for documenting any additional data parameters +that will be sent down with the signal. + +See the documentation of the :obj:`receiver_connected` built-in signal +for an example. + +More +---- + +Disconnecting receivers from signals, introspection of connected +receivers, private namespaces for named signals and more are discussed +in the :ref:`api`. + -- cgit v1.2.1