[med-svn] [sphinxcontrib-bibtex] 01/04: Imported Upstream version 0.3.2

Kevin Murray daube-guest at moszumanska.debian.org
Mon Sep 28 12:37:33 UTC 2015


This is an automated email from the git hooks/post-receive script.

daube-guest pushed a commit to branch master
in repository sphinxcontrib-bibtex.

commit 588db65dba384c47bc4db4ca825b61a188ffa95c
Author: Kevin Murray <spam at kdmurray.id.au>
Date:   Mon Sep 28 21:52:28 2015 +1000

    Imported Upstream version 0.3.2
---
 .travis.yml                                  |  27 ++
 CHANGELOG.rst                                | 158 +++++++++
 INSTALL.rst                                  |  28 ++
 LICENSE.rst                                  |  26 ++
 MANIFEST.in                                  |  14 +
 README.rst                                   |  45 +++
 VERSION                                      |   1 +
 doc/Makefile                                 | 153 +++++++++
 doc/api.rst                                  |  12 +
 doc/api/cache.rst                            |   1 +
 doc/api/directives.rst                       |   1 +
 doc/api/interface.rst                        |   1 +
 doc/api/nodes.rst                            |   1 +
 doc/api/roles.rst                            |   1 +
 doc/api/transforms.rst                       |   1 +
 doc/changes.rst                              |   7 +
 doc/conf.py                                  | 248 ++++++++++++++
 doc/index.rst                                |  26 ++
 doc/license.rst                              |   5 +
 doc/make.bat                                 | 190 +++++++++++
 doc/quickstart.rst                           |  13 +
 doc/related.rst                              |  27 ++
 doc/usage.rst                                | 462 +++++++++++++++++++++++++++
 release_checklist.txt                        |  40 +++
 requirements.txt                             |   7 +
 setup.cfg                                    |   8 +
 setup.py                                     |  53 +++
 sphinxcontrib/__init__.py                    |  13 +
 sphinxcontrib/bibtex/__init__.py             | 136 ++++++++
 sphinxcontrib/bibtex/cache.py                | 393 +++++++++++++++++++++++
 sphinxcontrib/bibtex/directives.py           | 218 +++++++++++++
 sphinxcontrib/bibtex/nodes.py                |  17 +
 sphinxcontrib/bibtex/roles.py                |  43 +++
 sphinxcontrib/bibtex/transforms.py           | 127 ++++++++
 test/bibfile_out_of_date/conf.py             |   2 +
 test/bibfile_out_of_date/contents.rst        |   3 +
 test/bibfile_out_of_date/test_new.bib        |  16 +
 test/bibfile_out_of_date/test_old.bib        |  16 +
 test/bibfilenotfound/conf.py                 |   2 +
 test/bibfilenotfound/contents.rst            |   1 +
 test/citationnotfound/conf.py                |   2 +
 test/citationnotfound/contents.rst           |   3 +
 test/citationnotfound/test.bib               |   0
 test/custom_style/conf.py                    |  17 +
 test/custom_style/contents.rst               |   4 +
 test/custom_style/test.bib                   |  27 ++
 test/filter/bitand.rst                       |   6 +
 test/filter/bitor.rst                        |   6 +
 test/filter/conf.py                          |   2 +
 test/filter/contents.rst                     |  20 ++
 test/filter/false.rst                        |   6 +
 test/filter/gt.rst                           |   6 +
 test/filter/gte.rst                          |   6 +
 test/filter/in.rst                           |   6 +
 test/filter/key.rst                          |   6 +
 test/filter/lt.rst                           |   6 +
 test/filter/lte.rst                          |   6 +
 test/filter/noteq.rst                        |   6 +
 test/filter/notin.rst                        |   6 +
 test/filter/or.rst                           |   6 +
 test/filter/set.rst                          |   6 +
 test/filter/test.bib                         |  18 ++
 test/filter/title.rst                        |   6 +
 test/filter_fix_author_keyerror/conf.py      |   2 +
 test/filter_fix_author_keyerror/contents.rst |   3 +
 test/filter_fix_author_keyerror/test.bib     |   4 +
 test/filter_option_clash/conf.py             |   2 +
 test/filter_option_clash/contents.rst        |   5 +
 test/filter_option_clash/test.bib            |   0
 test/filter_syntax_error/conf.py             |   2 +
 test/filter_syntax_error/contents.rst        |  26 ++
 test/filter_syntax_error/test.bib            |   5 +
 test/invalid_cite_option/conf.py             |   2 +
 test/invalid_cite_option/contents.rst        |   2 +
 test/invalid_cite_option/test.bib            |   0
 test/issue1/2012/07/24/hello_world_.rst      |  11 +
 test/issue1/conf.py                          |  28 ++
 test/issue1/master.rst                       |   8 +
 test/issue1/refs.bib                         |   6 +
 test/issue14/conf.py                         |   2 +
 test/issue14/contents.rst                    |   7 +
 test/issue14/doc1.rst                        |   6 +
 test/issue14/doc2.rst                        |   6 +
 test/issue14/test1.bib                       |   4 +
 test/issue14/test2.bib                       |   4 +
 test/issue14_2/conf.py                       |   2 +
 test/issue14_2/contents.rst                  |   7 +
 test/issue14_2/doc1.rst                      |   7 +
 test/issue14_2/doc2.rst                      |   7 +
 test/issue14_2/test1.bib                     |   4 +
 test/issue14_2/test2.bib                     |   4 +
 test/issue15/conf.py                         |   2 +
 test/issue15/contents.rst                    |   5 +
 test/issue15/test.bib                        |   8 +
 test/issue17/conf.py                         |  11 +
 test/issue17/contents.rst                    |   2 +
 test/issue17/somemodule.py                   |   6 +
 test/issue2/adoc1.rst                        |   4 +
 test/issue2/adoc2.rst                        |   4 +
 test/issue2/conf.py                          |   2 +
 test/issue2/contents.rst                     |  10 +
 test/issue2/test.bib                         |   4 +
 test/issue4/conf.py                          |   2 +
 test/issue4/contents.rst                     |   3 +
 test/issue4/test.bib                         |   4 +
 test/issue61/conf.py                         |   2 +
 test/issue61/contents.rst                    |   6 +
 test/issue61/refs.bib                        |   9 +
 test/issue62/conf.py                         |   2 +
 test/issue62/contents.rst                    |   9 +
 test/issue62/doc1.rst                        |  56 ++++
 test/issue62/doc2.rst                        |  46 +++
 test/issue62/refs.bib                        | 128 ++++++++
 test/issue62/summary.rst                     |  47 +++
 test/issue77/conf.py                         |  21 ++
 test/issue77/contents.rst                    |   5 +
 test/issue77/test.bib                        |  27 ++
 test/issue80/conf.py                         |   2 +
 test/issue80/contents.rst                    |  15 +
 test/issue80/doc0.rst                        |   2 +
 test/issue80/doc1.rst                        |   4 +
 test/issue80/doc2.rst                        |   4 +
 test/issue80/doc3.rst                        |   4 +
 test/issue80/doc4.rst                        |   4 +
 test/issue80/doc5.rst                        |   4 +
 test/issue80/doc6.rst                        |   4 +
 test/issue80/doc7.rst                        |   4 +
 test/issue80/doc8.rst                        |   4 +
 test/issue80/doc9.rst                        |   4 +
 test/issue80/refs.bib                        |  85 +++++
 test/latex_refs/conf.py                      |   7 +
 test/latex_refs/contents.rst                 |   7 +
 test/latex_refs/test.bib                     |  10 +
 test/list_bullet/conf.py                     |   2 +
 test/list_bullet/contents.rst                |   3 +
 test/list_bullet/test.bib                    |  16 +
 test/list_citation/conf.py                   |   2 +
 test/list_citation/contents.rst              |   4 +
 test/list_citation/test.bib                  |  16 +
 test/list_enumerated/conf.py                 |   2 +
 test/list_enumerated/contents.rst            |  14 +
 test/list_enumerated/test.bib                |  16 +
 test/list_enumerated/test2.bib               |  16 +
 test/list_enumerated/test3.bib               |  16 +
 test/list_invalid/conf.py                    |   2 +
 test/list_invalid/contents.rst               |   2 +
 test/list_invalid/test.bib                   |   0
 test/path.py                                 | 198 ++++++++++++
 test/sphinx/Makefile                         | 130 ++++++++
 test/sphinx/conf.py                          |   2 +
 test/sphinx/contents.rst                     |  25 ++
 test/sphinx/make.bat                         | 170 ++++++++++
 test/sphinx/subfolder/test.bib               |  12 +
 test/sphinx/test.bib                         | 275 ++++++++++++++++
 test/sphinx/test2.bib                        |  53 +++
 test/sphinx/zbibliography.rst                |  59 ++++
 test/test_bibfile_out_of_date.py             |  54 ++++
 test/test_bibfilenotfound.py                 |  26 ++
 test/test_citationnotfound.py                |  26 ++
 test/test_custom_style.py                    |  28 ++
 test/test_filter.py                          |  73 +++++
 test/test_filter_fix_author_keyerror.py      |  20 ++
 test/test_filter_option_clash.py             |  28 ++
 test/test_filter_syntax_error.py             |  28 ++
 test/test_invalid_cite_option.py             |  26 ++
 test/test_issue1.py                          |  27 ++
 test/test_issue14.py                         |  33 ++
 test/test_issue14_2.py                       |  27 ++
 test/test_issue15.py                         |  29 ++
 test/test_issue17.py                         |  20 ++
 test/test_issue2.py                          |  26 ++
 test/test_issue4.py                          |  25 ++
 test/test_issue61.py                         |  26 ++
 test/test_issue62.py                         |  85 +++++
 test/test_issue77.py                         |  26 ++
 test/test_issue80_parallel.py                |  27 ++
 test/test_issue80_serial.py                  |  19 ++
 test/test_latex_refs.py                      |  26 ++
 test/test_list_bullet.py                     |  32 ++
 test/test_list_citation.py                   |  32 ++
 test/test_list_enumerated.py                 |  44 +++
 test/test_list_invalid.py                    |  28 ++
 test/test_sphinx.py                          |  37 +++
 test/util.py                                 | 251 +++++++++++++++
 184 files changed, 5639 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2e98360
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,27 @@
+language: python
+python:
+  - "3.4"
+  - "3.3"
+  - "2.7"
+  - "pypy"
+branches:
+  only:
+    - develop
+install:
+  - "pip install Tinkerer" # Tinkerer is required for tests
+  - "pip install ."
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install coveralls check-manifest flake8; fi"
+script:
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then check-manifest; fi"
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then flake8; fi"
+  - "pushd doc"
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then make html; fi"
+  - "popd"
+  - "pushd test"
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coverage run --source=sphinxcontrib.bibtex `type -p nosetests`; fi"
+  - "if [[ $TRAVIS_PYTHON_VERSION != '2.7' ]]; then nosetests; fi"
+  - "popd"
+after_success:
+  - "pushd test"
+  - "if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls; fi"
+  - "popd"
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..e3fe33e
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,158 @@
+0.3.2 (20 March 2015)
+---------------------
+
+* Document how to create custom label styles (see issue #77, reported
+  by tino).
+
+* Disable parallel_read_safe for Sphinx 1.3 and later (see issue #80,
+  reported by andreacassioli).
+
+0.3.1 (10 July 2014)
+--------------------
+
+* Fix for ``type_.lower()`` bug: pybtex 0.18 expects type to be a
+  string (this fixes issue #68 reported by jluttine).
+
+0.3.0 (4 May 2014)
+------------------
+
+* **BACKWARD INCOMPATIBLE**
+  The alpha style is now default, so citations are labelled in a way
+  that is more standard for Sphinx. To get the old behaviour back, add
+  ``:style: plain`` to your bibliography directives.
+
+* **BACKWARD INCOMPATIBLE**
+  :meth:`~sphinxcontrib.bibtex.cache.Cache.is_cited` has been removed.
+  Use :meth:`~sphinxcontrib.bibtex.cache.Cache.get_cited_docnames` instead,
+  which will return an empty list for keys that are not cited.
+
+* Improved support for local bibliographies (see issues #52, #62, and
+  #63; test case provided by Boris Kheyfets):
+
+  - New ``docname`` and ``docnames`` filter identifiers.
+
+  - Filter expressions now also support set literals and the operators
+    ``in``, ``not in``, ``&``, and ``|``.
+
+  See documentation for details.
+
+* Multiple comma-separated citation keys per cite command (see issue
+  #61, suggested by Boris Kheyfets).
+
+* Add support for pypy and Python 3.4.
+
+* Drop support for Python 2.6 and Python 3.2.
+
+* Drop 2to3 and instead use six to support both Python 2 and 3 from a
+  single code base.
+
+* Simplify instructions for custom styles.
+
+* Various test suite improvements.
+
+0.2.9 (9 October 2013)
+----------------------
+
+* Upgrade to the latest pybtex-docutils to produce more optimal html output
+  (specifically: no more nested ``<span>``\ s).
+
+* Remove latex codec code, and rely on latexcodec package instead.
+
+* :class:`FilterVisitor` has been removed from the public API.
+  Use :meth:`~sphinxcontrib.bibtex.cache.Cache.get_bibliography_entries`
+  instead.
+
+* Fix upstream Sphinx bug concerning LaTeX citation hyperlinks
+  (contributed by erikb85; see pull request #45).
+
+* Fix most pylint warnings, refactor code.
+
+0.2.8 (7 August 2013)
+---------------------
+
+* Use pybtex-docutils to remove dependency on pybtex.backends.doctree.
+
+0.2.7 (4 August 2013)
+---------------------
+
+* Integrate with coveralls.io, first release with 100% test coverage.
+
+* Minor bug fixes and code improvements.
+
+* Remove ordereddict dependency for Python 2.7 and higher (contributed
+  by Paul Romano, see pull requests #27 and #28).
+
+* New ``:filter:`` option for advanced filtering (contributed by
+  d9pouces, see pull requests #30 and #31).
+
+* Refactor documentation of advanced features.
+
+* Document how to create custom pybtex styles (see issues #25, #29,
+  and #34).
+
+* Code is now mostly pep8 compliant.
+
+0.2.6 (2 March 2013)
+--------------------
+
+* For unsorted styles, citation entries are now sorted in the order
+  they are cited, instead of following the order in the bib file, to
+  reflect more closely the way LaTeX handles unsorted styles
+  (addresses issue #15).
+
+* Skip citation label warnings on Sphinx [source] links (issue #17,
+  contributed by Simon Clift).
+
+0.2.5 (18 October 2012)
+-----------------------
+
+* Duplicate label detection (issue #14).
+
+* New ``:labelprefix:`` option to avoid duplicate labels when having
+  multiple bibliographies with a numerical label style (addresses
+  issue #14).
+
+0.2.4 (24 August 2012)
+----------------------
+
+* New options for the bibliography directive for rendering the
+  bibliography as bullet lists or enumerated lists: ``:list:``,
+  ``:enumtype:``, and ``:start:``.
+
+* Minor latex codec fixes.
+
+* Turn exception into warning when a citation cannot be relabeled
+  (fixes issue #2).
+
+* Document LaTeX encoding, and how to turn it off (issue #4).
+
+* Use pybtex labels (fixes issue #6 and issue #7).
+
+* Cache tracked citation keys and labels, and bibliography enumeration
+  counts (fixes issues with citations in repeated Sphinx runs).
+
+* Bibliography ids are now unique across documents (fixes issue that
+  could cause the wrong bibliography to be inserted).
+
+* The plain style is now the default (addresses issue #9).
+
+0.2.3 (30 July 2012)
+--------------------
+
+* Document workaround for Tinkerer (issue #1).
+
+* Use tox for testing.
+
+* Full 2to3 compatibility.
+
+* Document supported versions of Python (2.6, 2.7, 3.1, and 3.2).
+
+0.2.2 (6 July 2012)
+-------------------
+
+* Documentation and manifest fixes.
+
+0.2.1 (19 June 2012)
+--------------------
+
+* First public release.
diff --git a/INSTALL.rst b/INSTALL.rst
new file mode 100644
index 0000000..5ad7c6f
--- /dev/null
+++ b/INSTALL.rst
@@ -0,0 +1,28 @@
+Install the module with ``pip install sphinxcontrib-bibtex``, or from
+source using ``python setup.py install``. Then add:
+
+.. code-block:: python
+
+   extensions = ['sphinxcontrib.bibtex']
+
+to your project's Sphinx configuration file ``conf.py``.
+
+Minimal Example
+---------------
+
+In your project's documentation, you can then write for instance:
+
+.. code-block:: rest
+
+   See :cite:`1987:nelson` for an introduction to non-standard analysis.
+
+   .. bibliography:: refs.bib
+
+where refs.bib would contain an entry::
+
+   @Book{1987:nelson,
+     author = {Edward Nelson},
+     title = {Radically Elementary Probability Theory},
+     publisher = {Princeton University Press},
+     year = {1987}
+   }
diff --git a/LICENSE.rst b/LICENSE.rst
new file mode 100644
index 0000000..565f57a
--- /dev/null
+++ b/LICENSE.rst
@@ -0,0 +1,26 @@
+| sphinxcontrib-bibtex is a Sphinx extension for BibTeX style citations
+| Copyright (c) 2011-2014 by Matthias C. M. Troffaes
+| 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 binary 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
+OWNER 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.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..08b9f54
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,14 @@
+include VERSION
+include README.rst
+include INSTALL.rst
+include CHANGELOG.rst
+include LICENSE.rst
+include requirements.txt
+recursive-include doc *
+recursive-include test *
+global-exclude *.pyc
+exclude .gitignore
+exclude .travis.yml
+exclude release_checklist.txt
+prune doc/_build
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..40bbb26
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,45 @@
+sphinxcontrib-bibtex
+====================
+
+|travis| |coveralls| |downloads| |version| |license|
+
+A Sphinx extension for BibTeX style citations.
+
+This extension allows `BibTeX <http://www.bibtex.org/>`_
+citations to be inserted into documentation generated by
+`Sphinx <http://sphinx.pocoo.org/>`_, via
+a ``bibliography`` directive, and a ``cite`` role, which
+work similarly to LaTeX's ``thebibliography`` environment
+and ``\cite`` command.
+
+For formatting, the extension relies on
+`pybtex <http://pybtex.sourceforge.net/>`_
+written by Andrey Golovizin.
+The extension is inspired by Matthew Brett's
+`bibstuff.sphinxext.bibref <https://github.com/matthew-brett/bibstuff>`_.
+
+* Download: http://pypi.python.org/pypi/sphinxcontrib-bibtex/#downloads
+
+* Documentation: http://sphinxcontrib-bibtex.readthedocs.org/
+
+* Development: http://github.com/mcmtroffaes/sphinxcontrib-bibtex/
+
+.. |travis| image:: https://travis-ci.org/mcmtroffaes/sphinxcontrib-bibtex.png?branch=develop
+    :target: https://travis-ci.org/mcmtroffaes/sphinxcontrib-bibtex
+    :alt: travis-ci
+
+.. |coveralls| image:: https://coveralls.io/repos/mcmtroffaes/sphinxcontrib-bibtex/badge.png?branch=develop
+    :target: https://coveralls.io/r/mcmtroffaes/sphinxcontrib-bibtex?branch=develop
+    :alt: coveralls.io
+
+.. |downloads| image:: https://pypip.in/d/sphinxcontrib-bibtex/badge.png
+    :target: http://pypi.python.org/pypi/sphinxcontrib-bibtex/
+    :alt: downloads
+
+.. |version| image:: https://pypip.in/v/sphinxcontrib-bibtex/badge.png
+    :target: http://pypi.python.org/pypi/sphinxcontrib-bibtex/
+    :alt: latest version
+
+.. |license| image:: https://pypip.in/license/sphinxcontrib-bibtex/badge.png
+    :target: http://pypi.python.org/pypi/sphinxcontrib-bibtex/
+    :alt: license
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..d15723f
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.3.2
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..6419911
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sphinxcontrib-bibtex.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sphinxcontrib-bibtex.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/sphinxcontrib-bibtex"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sphinxcontrib-bibtex"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/api.rst b/doc/api.rst
new file mode 100644
index 0000000..a6c8861
--- /dev/null
+++ b/doc/api.rst
@@ -0,0 +1,12 @@
+Extension API
+~~~~~~~~~~~~~
+
+.. toctree::
+    :maxdepth: 2
+
+    api/interface
+    api/roles
+    api/nodes
+    api/directives
+    api/transforms
+    api/cache
diff --git a/doc/api/cache.rst b/doc/api/cache.rst
new file mode 100644
index 0000000..cf5673a
--- /dev/null
+++ b/doc/api/cache.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex.cache
diff --git a/doc/api/directives.rst b/doc/api/directives.rst
new file mode 100644
index 0000000..778d5e2
--- /dev/null
+++ b/doc/api/directives.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex.directives
diff --git a/doc/api/interface.rst b/doc/api/interface.rst
new file mode 100644
index 0000000..7f50f05
--- /dev/null
+++ b/doc/api/interface.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex
diff --git a/doc/api/nodes.rst b/doc/api/nodes.rst
new file mode 100644
index 0000000..eb62f79
--- /dev/null
+++ b/doc/api/nodes.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex.nodes
diff --git a/doc/api/roles.rst b/doc/api/roles.rst
new file mode 100644
index 0000000..c601028
--- /dev/null
+++ b/doc/api/roles.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex.roles
diff --git a/doc/api/transforms.rst b/doc/api/transforms.rst
new file mode 100644
index 0000000..8937b3e
--- /dev/null
+++ b/doc/api/transforms.rst
@@ -0,0 +1 @@
+.. automodule:: sphinxcontrib.bibtex.transforms
diff --git a/doc/changes.rst b/doc/changes.rst
new file mode 100644
index 0000000..2eb28cc
--- /dev/null
+++ b/doc/changes.rst
@@ -0,0 +1,7 @@
+:tocdepth: 1
+
+Changes
+=======
+
+.. include:: ../CHANGELOG.rst
+
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..d25ab99
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,248 @@
+# -*- coding: utf-8 -*-
+#
+# sphinxcontrib-bibtex documentation build configuration file, created by
+# sphinx-quickstart on Thu Jun 13 13:56:25 2013.
+#
+# This file is execfile()d with the current directory set to its containing
+# dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# -- General configuration -----------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
+# 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.intersphinx',
+    'sphinx.ext.todo',
+    'sphinx.ext.coverage',
+    'sphinx.ext.pngmath',
+    'sphinx.ext.viewcode']
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'sphinxcontrib-bibtex'
+copyright = u'2011-2014, Matthias C. M. Troffaes'
+
+# 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 full version, including alpha/beta/rc tags.
+with open("../VERSION", "rt") as version_file:
+    release = version_file.read().strip()
+# The short X.Y version.
+version = '.'.join(release.split('.')[:2])
+
+# 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 patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# 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.  See the documentation for
+# a list of builtin themes.
+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
+# "<project> v<release> 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_domain_indices = 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 <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'sphinxcontrib-bibtexdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    # 'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass
+# [howto/manual]).
+latex_documents = [
+    ('index', 'sphinxcontrib-bibtex.tex',
+     u'sphinxcontrib-bibtex Documentation',
+     u'Matthias C. M. Troffaes', '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
+
+# If true, show page references after internal links.
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+# latex_appendices = []
+
+# If false, no module index is generated.
+# latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'sphinxcontrib-bibtex', u'sphinxcontrib-bibtex Documentation',
+     [u'Matthias C. M. Troffaes'], 1)
+]
+
+# If true, show URL addresses after external links.
+# man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    ('index', 'sphinxcontrib-bibtex', u'sphinxcontrib-bibtex Documentation',
+     u'Matthias C. M. Troffaes', 'sphinxcontrib-bibtex',
+     'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+# texinfo_no_detailmenu = False
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {
+    'python': ('http://docs.python.org/', None),
+    'sphinx': ('http://sphinx.pocoo.org/', None),
+}
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..d463c3e
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,26 @@
+Welcome to sphinxcontrib-bibtex's documentation!
+================================================
+
+:Release: |release|
+:Date:    |today|
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 2
+
+   quickstart
+   usage
+   api
+   changes
+   license
+   related
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/doc/license.rst b/doc/license.rst
new file mode 100644
index 0000000..fbf968e
--- /dev/null
+++ b/doc/license.rst
@@ -0,0 +1,5 @@
+License
+=======
+
+.. include:: ../LICENSE.rst
+
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..e8894e4
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,190 @@
+ at ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+	set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  texinfo    to make Texinfo files
+	echo.  gettext    to make PO message catalogs
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\sphinxcontrib-bibtex.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\sphinxcontrib-bibtex.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "texinfo" (
+	%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+	goto end
+)
+
+if "%1" == "gettext" (
+	%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
diff --git a/doc/quickstart.rst b/doc/quickstart.rst
new file mode 100644
index 0000000..d8680a8
--- /dev/null
+++ b/doc/quickstart.rst
@@ -0,0 +1,13 @@
+Getting Started
+===============
+
+Overview
+--------
+
+.. include:: ../README.rst
+   :start-line: 5
+
+Installation
+------------
+
+.. include:: ../INSTALL.rst
diff --git a/doc/related.rst b/doc/related.rst
new file mode 100644
index 0000000..29f4ca1
--- /dev/null
+++ b/doc/related.rst
@@ -0,0 +1,27 @@
+Related Projects
+================
+
+Below is a list of projects which include functionality that is
+similar or related to sphinxcontrib-bibtex.
+If you know of any other, leave a message on the issue tracker.
+
+* Andrey Golovizin's `pybtex <http://pybtex.sourceforge.net/>`_,
+  a general purpose Python library for working with bibtex files.
+  Drives sphinxcontrib-bibtex.
+
+* Matthew Brett's `bibstuff <https://github.com/matthew-brett/bibstuff>`_.
+  Includes a Sphinx extension similar to sphinxcontrib-bibtex,
+  as well as an assorted collection of bibtex tools.
+  This is a fork of Dylan W. Schwilk and Alan G. Isaac's
+  `bibstuff on google code <https://code.google.com/p/bibstuff/>`_
+  which is apparently no longer maintained.
+
+* wnielson's
+  `sphinx-natbib <https://bitbucket.org/wnielson/sphinx-natbib>`_.
+  Similar to sphinxcontrib-bibtex but appears to be stalled in alpha stage.
+  Interestingly, supports natbib-style citations.
+  Apparently no longer maintained.
+
+* Jeff Terrace's Sphinx Thesis Resource
+  `sphinxtr <https://github.com/jterrace/sphinxtr>`_,
+  a fork of Sphinx which includes a fork of sphinx-natbib.
diff --git a/doc/usage.rst b/doc/usage.rst
new file mode 100644
index 0000000..7def6c3
--- /dev/null
+++ b/doc/usage.rst
@@ -0,0 +1,462 @@
+Usage
+=====
+
+Roles and Directives
+--------------------
+
+.. rst:role:: cite
+
+   Create a citation to a bibliographic entry. For example:
+
+   .. code-block:: rest
+
+      See :cite:`1987:nelson` for an introduction to non-standard analysis.
+
+   which would be equivalent to the following LaTeX code:
+
+   .. code-block:: latex
+
+      See \cite{1987:nelson} for an introduction to non-standard analysis.
+
+   Multiple comma-separated keys can be specified at once:
+
+   .. code-block:: rest
+
+      See :cite:`1987:nelson,2001:schechter`.
+
+   .. note::
+
+      Due to a docutils implementation detail, Sphinx's LaTeX backend
+      will not actually generate ``\cite`` commands. Instead, all
+      references, including citation references, are managed using
+      ``\hyperref`` and ``\label`` commands.
+      See https://github.com/mcmtroffaes/sphinxcontrib-bibtex/issues/10
+
+.. rst:directive:: .. bibliography:: refs.bib [...]
+
+   Create bibliography for all cited references. The ``all`` flag
+   forces all references to be included (equivalent to ``\nocite{*}``
+   in LaTeX). The ``notcited`` flag causes all references that were
+   not cited to be included. The ``cited`` flag is recognized as well
+   but is entirely optional. For example:
+
+   .. code-block:: rest
+
+     .. rubric:: References
+
+     .. bibliography:: refs.bib
+        :cited:
+
+   which would be roughly equivalent to the following LaTeX code:
+
+   .. code-block:: latex
+
+      \begin{thebibliography}{1}
+        \bibitem{1987:nelson}
+        Edward~Nelson
+        \newblock {\em Radically Elementary Probability Theory}.
+        \newblock Princeton University Press, 1987.
+      \end{thebibliography}
+
+   Note that, unlike LaTeX, the :rst:dir:`bibliography` directive does
+   not generate a default section title.
+
+   .. warning::
+
+      Sphinx may not be able to create an entry for :rst:role:`cite` keys
+      when your :rst:dir:`bibliography` directive
+      resides in a different document;
+      see :ref:`issue-unresolved-citations`
+      for more information and workarounds.
+
+   You can also pick a bibliography style, using the ``style`` option.
+   The ``alpha`` style is the default.
+   Other supported styles are ``plain``, ``unsrt``, and ``unsrtalpha``.
+
+   .. code-block:: rest
+
+     .. bibliography:: refs.bib
+        :style: unsrt
+
+   .. warning::
+
+      Sphinx will attempt to resolve references to the bibliography
+      across all documents, so you must take care that no citation key
+      is included more than once.
+
+   You can also set the encoding of the bibliography files, using the
+   ``encoding`` option.
+
+   .. code-block:: rest
+
+     .. bibliography:: refs.bib
+        :encoding: latex+latin
+
+   Note that, usually, you want to prepend your encoding with
+   ``latex+``, in order to convert LaTeX control characters to unicode
+   characters (for instance, to convert ``\'e`` into ``é``). The latex
+   codec is invoked by default, for your convenience. Be sure to write
+   ``\%`` when you intend to format a percent sign.
+
+.. XXX not documenting disable-curly-bracket-strip for now; might remove it
+
+   Finally, curly brackets are automatically removed when the bib file
+   is parsed. Usually, this is what you want. If you desire to disable
+   this behaviour, use the ``disable-curly-bracket-strip`` option:
+
+   .. code-block:: rest
+
+     .. bibliography:: refs.bib
+        :disable-curly-bracket-strip:
+
+Advanced Features
+-----------------
+
+Bullet Lists and Enumerated Lists
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 0.2.4
+
+You can change the type of list used for rendering the
+bibliography. By default, a paragraph of standard citations is
+generated. However, instead, you can also generate a bullet list,
+or an enumerated list.
+
+.. code-block:: rest
+
+   .. bibliography:: refs1.bib
+      :list: bullet
+      :all:
+
+   .. bibliography:: refs2.bib
+      :list: enumerated
+      :all:
+
+Note that citations to these types of bibliography lists will not
+be resolved.
+
+For enumerated lists, you can also specify the type (default is
+``arabic``), and the start of the sequence (default is ``1``).
+
+.. code-block:: rest
+
+   .. bibliography:: refs2.bib
+      :list: enumerated
+      :enumtype: upperroman
+      :start: 3
+      :all:
+
+The enumtype can be any of
+``arabic`` (1, 2, 3, ...),
+``loweralpha`` (a, b, c, ...),
+``upperalpha`` (A, B, C, ...),
+``lowerroman`` (i, ii, iii, ...), or
+``upperroman`` (I, II, III, ...).
+
+The start can be any positive integer (1, 2, 3, ...) or
+``continue`` if you wish the enumeration to continue from the last
+:rst:dir:`bibliography` directive.
+This is helpful if you split up your bibliography but
+still want to enumerate the entries continuously.
+
+Label Prefixing
+~~~~~~~~~~~~~~~
+
+.. versionadded:: 0.2.5
+
+If you have multiple bibliographies, and experience duplicate labels,
+use the ``labelprefix`` option.
+
+.. code-block:: rest
+
+   .. rubric:: References
+
+   .. bibliography:: refs.bib
+      :cited:
+      :labelprefix: A
+
+   .. rubric:: Further reading
+
+   .. bibliography:: refs.bib
+      :notcited:
+      :labelprefix: B
+
+Filtering
+~~~~~~~~~
+
+.. versionadded:: 0.2.7
+
+Whilst the ``cited``, ``all``, and ``notcited`` options
+will cover many use cases,
+sometimes more advanced selection of bibliographic entries is desired.
+For this purpose, you can use the ``filter`` option:
+
+.. code-block:: rest
+
+   .. bibliography:: refs.bib
+      :list: bullet
+      :filter: author % "Einstein"
+
+The string specified in the filter option must be a valid Python
+expression.
+
+.. note::
+
+   The expression is parsed using :func:`ast.parse`
+   and then evaluated using an :class:`ast.NodeVisitor`,
+   so it should be reasonably safe against malicious code.
+
+The filter expression supports:
+
+* The boolean operators ``and``, ``or``.
+
+* The unary operator ``not``.
+
+* The comparison operators ``==``, ``<=``, ``<``, ``>=``, and ``>``.
+
+* Regular expression matching using the ``%`` operator, where the left
+  hand side is the string to be matched, and the right hand side is
+  the regular expression. Matching is case insensitive. For example:
+
+    .. code-block:: rest
+
+       .. bibliography:: refs.bib
+          :list: bullet
+          :filter: title % "relativity"
+
+  would include all entries that have the word "relativity" in the title.
+
+  .. note::
+
+     The implementation uses :func:`re.search`.
+
+* Single and double quoted strings, such as ``'hello'`` or ``"world"``.
+
+* Set literals, such has ``{"hello", "world"}``, as well as
+  the set operators ``&``, ``|``, ``in``, and ``not in``.
+
+  .. versionadded:: 0.3.0
+
+* Various identifiers, such as:
+
+  - ``type`` is the entry type, as a lower case string
+    (i.e. ``"inproceedings"``).
+
+  - ``key`` is the entry key, as a lower case string
+    (this is because keys are considered case insensitive).
+
+  - ``cited`` evaluates to ``True`` if the entry was cited in the document,
+    and to ``False`` otherwise.
+
+  - ``docname`` evaluates to the name of the current document.
+
+    .. versionadded:: 0.3.0
+
+  - ``docnames`` evaluates to a set of names from which the entry is cited.
+
+    .. versionadded:: 0.3.0
+
+  - ``True`` and ``False``.
+
+  - ``author`` is the entry string of authors
+    in standard format (last, first), separated by "and".
+
+  - ``editor`` is similar to ``author`` but for editors.
+
+  - Any other (lower case) identifier evaluates to a string
+    containing the value of
+    the correspondingly named field, such as
+    ``title``, ``publisher``, ``year``, and so on.
+    If the item is missing in the entry
+    then it evaluates to the empty string.
+    Here is an example of how one would typically write an expression
+    to filter on an optional field:
+
+    .. code-block:: rest
+
+       .. bibliography:: refs.bib
+          :list: bullet
+          :filter: cited and year and (year <= "2003")
+
+    which would include all cited entries that have a year
+    that is less or equal than 2003; any entries that do not
+    specify a year would be omitted.
+
+Local Bibliographies
+~~~~~~~~~~~~~~~~~~~~
+
+To create a bibliography that includes only citations that were cited
+in the current document, use the following filter:
+
+.. code-block:: rest
+                
+   .. bibliography:: refs.bib
+      :filter: docname in docnames
+
+More generally, you can create bibliographies for
+citations that were cited from specific documents only:
+
+.. code-block:: rest
+
+   .. bibliography:: refs.bib
+      :filter: {"doc1", "doc2"} & docnames
+
+This bibliography will include all citations that were cited from
+:file:`doc1.rst` or :file:`doc2.rst`. Another hypothetical example:
+
+.. code-block:: rest
+
+   .. bibliography:: refs.bib
+      :filter: cited and ({"doc1", "doc2"} >= docnames)
+
+This bibliography will include all citations that were cited
+in :file:`doc1.rst` or :file:`doc2.rst`, but nowhere else.
+
+Custom Formatting, Sorting, and Labelling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:mod:`pybtex` provides a very powerful way to create and register new
+styles, using setuptools entry points,
+as documented here: http://pybtex.sourceforge.net/plugins.html
+
+Simply add the following code to your ``conf.py``:
+
+.. code-block:: python
+
+  from pybtex.style.formatting.unsrt import Style as UnsrtStyle
+  from pybtex.style.template import toplevel # ... and anything else needed
+  from pybtex.plugin import register_plugin
+
+  class MyStyle(UnsrtStyle):
+
+      def format_XXX(self, e):
+          template = toplevel [
+              # etc.
+          ]
+          return template.format_data(e)
+
+  register_plugin('pybtex.style.formatting', 'mystyle', MyStyle)
+
+Now ``mystyle`` will be available to you as a formatting style:
+
+.. code-block:: rest
+
+   .. bibliography:: refs.bib
+      :style: mystyle
+
+An minimal example is available here:
+https://github.com/mcmtroffaes/sphinxcontrib-bibtex/tree/develop/test/custom_style
+
+The formatting code uses a very intuitive template engine.
+The source code for ``unsrt`` provides many great examples:
+http://bazaar.launchpad.net/~pybtex-devs/pybtex/trunk/view/head:/pybtex/style/formatting/unsrt.py
+
+The above example only demonstrates a custom formatting style plugin.
+It is also possible to register custom author/editor naming plugins
+(using the ``pybtex.style.names`` group)
+labelling plugins
+(using the ``pybtex.style.labels`` group),
+and sorting plugins
+(using the ``pybtex.style.sorting`` group).
+A minimal example demonstrating how to create a custom label style
+is available here:
+https://github.com/mcmtroffaes/sphinxcontrib-bibtex/tree/develop/test/issue77
+
+Known Issues and Workarounds
+----------------------------
+
+Tinkerer
+~~~~~~~~
+
+To use the bibtex extension with `Tinkerer <http://www.tinkerer.me/>`_,
+be sure to specify the bibtex extension first in your ``conf.py`` file::
+
+    extensions = ['sphinxcontrib.bibtex', 'tinkerer.ext.blog', 'tinkerer.ext.disqus']
+
+Encoding: Percent Signs
+~~~~~~~~~~~~~~~~~~~~~~~
+
+When using the LaTeX codec (which is by default), be sure to write
+``\%`` for percent signs at all times (unless your file contains a
+genuine comment), otherwise the bibtex lexer will ignore the remainder
+of the line.
+
+If you don't want any LaTeX symbols to be reinterpreted as unicode,
+use the option ``:encoding: utf`` (without the ``latex+`` prefix).
+
+.. _issue-unresolved-citations:
+
+Unresolved Citations Across Documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you cite something that has its bibliography in another document,
+then, at the moment, the extension may, or may not, realise that it
+has to add this citation.
+There are a few ways to work around this problem:
+
+* Use the option ``:all:`` in the :rst:dir:`bibliography`
+  directive (which will simply cause all entries to be included).
+
+* Ensure that the :rst:dir:`bibliography` directive is processed after
+  all :rst:role:`cite`\ s. Sphinx appears to process files in an
+  alphabetical manner. For instance, in case you have only one file
+  containing a :rst:dir:`bibliography` directive, simply name that
+  file :file:`zreferences.rst`.
+
+Hopefully, this limitation can be lifted in a future release.
+
+Duplicate Labels When Using ``:style: plain``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+With ``:style: plain``, labels are numerical,
+restarting at ``[1]`` for each :rst:dir:`bibliography` directive.
+Consequently, when inserting multiple :rst:dir:`bibliography` directives
+with ``:style: plain``,
+you are bound to get duplicate labels for entries.
+There are a few ways to work around this problem:
+
+* Use a single bibliography directive for all your references.
+
+* Use the ``labelprefix`` option, as documented above.
+
+* Use a style that has non-numerical labelling,
+  such as ``:style: alpha``.
+
+Citation Links Broken When Using LaTeX Backend
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a known bug in Sphinx's latex writer,
+which has been fixed upstream:
+
+https://bitbucket.org/birkenfeld/sphinx/pull-request/171
+
+https://bitbucket.org/birkenfeld/sphinx/pull-request/173
+
+Mismatch Between Output of HTML and LaTeX Backends
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sphinx's LaTeX writer currently collects all citations together,
+and puts them on a separate page, with a separate title,
+whereas the html writer puts citations
+at the location where they are defined.
+This issue will occur also if you use regular citations in Sphinx:
+it has nothing to do with sphinxcontrib-bibtex per se.
+
+To get a closer match between the two outputs,
+you can tell Sphinx to generate a rubric title only for html:
+
+.. code-block:: rest
+
+   .. only:: html
+
+      .. rubric:: References
+
+   .. bibliography:: refs.bib
+
+This code could be placed in your :file:`zreferences.rst`.
+
+The current aim is to fix Sphinx's LaTeX writer
+to match the html output more closely.
+The issue is tracked here:
+
+https://github.com/mcmtroffaes/sphinxcontrib-bibtex/issues/48
diff --git a/release_checklist.txt b/release_checklist.txt
new file mode 100644
index 0000000..e25f821
--- /dev/null
+++ b/release_checklist.txt
@@ -0,0 +1,40 @@
+* git checkout -b release/x.x.x
+* VERSION: set final version
+* CHANGELOG.rst:
+  - set release date
+  - all important changes are documented
+* doc:
+  - all new features are properly documented
+  - all new features have versionadded
+  - all workarounds are properly documented
+  - fixed workarounds are removed
+  - git clean -xfd
+  - python setup.py install --user && cd doc && make html
+* make pull request on github
+  - travis build passes
+  - coverage at 100%
+  - on github, merge release/x.x.x into develop and delete the release branch
+  - git remote update --prune && git checkout develop && git merge --ff-only origin/develop
+* create and register source zip
+  - git clean -xfd
+  - python setup.py register
+  - python setup.py sdist bdist_wheel upload
+* test upload
+  - pip uninstall sphinxcontrib-bibtex
+  - pip install --user -U sphinxcontrib-bibtex
+  - cd sphinxcontrib-bibtex/test
+  - nosetests
+* push release
+  - git checkout master && git merge --ff-only develop
+  - git tag -a -m "Tagging version x.x.x" x.x.x
+  - git push origin master
+  - git push --tags
+  - git checkout develop
+  - git branch -d release/x.x.x
+* activate new version on readthedocs.org
+* prep for next cycle
+  - git checkout develop
+  - VERSION: bump to x.x.xa0
+  - CHANGELOG.rst: bump to x.x.x (in development)
+  - git commit -a -m "Version bump. [ci skip]"
+  - git push origin develop
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..212ea41
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+latexcodec>=0.3.0
+pybtex>=0.17
+pybtex-docutils>=0.2.0
+six>=1.4.1
+Sphinx>=1.0
+oset>=0.1.3
+
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..4b28df6
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+[nosetests]
+with-coverage=1
+cover-package=sphinxcontrib.bibtex
+cover-branches=1
+cover-html=1
+
+[wheel]
+universal=1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..44c7b3b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+import io
+from setuptools import setup, find_packages
+import sys
+
+
+def readfile(filename):
+    with io.open(filename, encoding="utf-8") as stream:
+        return stream.read().split("\n")
+
+readme = readfile("README.rst")[5:]  # skip title and badges
+requires = readfile("requirements.txt")
+version = readfile("VERSION")[0].strip()
+
+if sys.version_info < (2, 7):
+    requires.append('ordereddict>=1.1')
+
+setup(
+    name='sphinxcontrib-bibtex',
+    version=version,
+    url='https://github.com/mcmtroffaes/sphinxcontrib-bibtex',
+    download_url='http://pypi.python.org/pypi/sphinxcontrib-bibtex',
+    license='BSD',
+    author='Matthias C. M. Troffaes',
+    author_email='matthias.troffaes at gmail.com',
+    description=readme[0],
+    long_description="\n".join(readme[2:]),
+    zip_safe=False,
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Environment :: Console',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: Implementation :: CPython',
+        'Programming Language :: Python :: Implementation :: PyPy',
+        'Topic :: Documentation',
+        'Topic :: Utilities',
+    ],
+    platforms='any',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=requires,
+    namespace_packages=['sphinxcontrib'],
+)
diff --git a/sphinxcontrib/__init__.py b/sphinxcontrib/__init__.py
new file mode 100644
index 0000000..35d34fc
--- /dev/null
+++ b/sphinxcontrib/__init__.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+"""
+    sphinxcontrib
+    ~~~~~~~~~~~~~
+
+    This package is a namespace package that contains all extensions
+    distributed in the ``sphinx-contrib`` distribution.
+
+    :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+__import__('pkg_resources').declare_namespace(__name__)
diff --git a/sphinxcontrib/bibtex/__init__.py b/sphinxcontrib/bibtex/__init__.py
new file mode 100644
index 0000000..7477236
--- /dev/null
+++ b/sphinxcontrib/bibtex/__init__.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+"""
+    Sphinx Interface
+    ~~~~~~~~~~~~~~~~
+
+    .. autofunction:: setup
+    .. autofunction:: init_bibtex_cache
+    .. autofunction:: purge_bibtex_cache
+    .. autofunction:: process_citations
+    .. autofunction:: process_citation_references
+    .. autofunction:: check_duplicate_labels
+"""
+
+import docutils.nodes
+from sphinxcontrib.bibtex.cache import Cache
+from sphinxcontrib.bibtex.nodes import bibliography
+from sphinxcontrib.bibtex.roles import CiteRole
+from sphinxcontrib.bibtex.directives import BibliographyDirective
+from sphinxcontrib.bibtex.transforms import BibliographyTransform
+import six
+
+
+def init_bibtex_cache(app):
+    """Create ``app.env.bibtex_cache`` if it does not exist yet.
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    """
+    if not hasattr(app.env, "bibtex_cache"):
+        app.env.bibtex_cache = Cache()
+
+
+def purge_bibtex_cache(app, env, docname):
+    """Remove all information related to *docname* from the cache.
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    :param env: The sphinx build environment.
+    :type env: :class:`sphinx.environment.BuildEnvironment`
+    """
+    env.bibtex_cache.purge(docname)
+
+
+def process_citations(app, doctree, docname):
+    """Replace labels of citation nodes by actual labels.
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    :param doctree: The document tree.
+    :type doctree: :class:`docutils.nodes.document`
+    :param docname: The document name.
+    :type docname: :class:`str`
+    """
+    for node in doctree.traverse(docutils.nodes.citation):
+        key = node[0].astext()
+        try:
+            label = app.env.bibtex_cache.get_label_from_key(key)
+        except KeyError:
+            app.warn("could not relabel citation [%s]" % key)
+        else:
+            node[0] = docutils.nodes.label('', label)
+
+
+def process_citation_references(app, doctree, docname):
+    """Replace text of citation reference nodes by actual labels.
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    :param doctree: The document tree.
+    :type doctree: :class:`docutils.nodes.document`
+    :param docname: The document name.
+    :type docname: :class:`str`
+    """
+    # sphinx has already turned citation_reference nodes
+    # into reference nodes, so iterate over reference nodes
+    for node in doctree.traverse(docutils.nodes.reference):
+        # exclude sphinx [source] labels
+        if isinstance(node[0], docutils.nodes.Element):
+            if 'viewcode-link' in node[0]['classes']:
+                continue
+        text = node[0].astext()
+        if text.startswith('[') and text.endswith(']'):
+            key = text[1:-1]
+            try:
+                label = app.env.bibtex_cache.get_label_from_key(key)
+            except KeyError:
+                app.warn("could not relabel citation reference [%s]" % key)
+            else:
+                node[0] = docutils.nodes.Text('[' + label + ']')
+
+
+def check_duplicate_labels(app, env):
+    """Check and warn about duplicate citation labels.
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    :param env: The sphinx build environment.
+    :type env: :class:`sphinx.environment.BuildEnvironment`
+    """
+    label_to_key = {}
+    for info in env.bibtex_cache.get_all_bibliography_caches():
+        for key, label in six.iteritems(info.labels):
+            if label in label_to_key:
+                app.warn(
+                    "duplicate label for keys %s and %s"
+                    % (key, label_to_key[label]))
+            else:
+                label_to_key[label] = key
+
+
+def setup(app):
+    """Set up the bibtex extension:
+
+    * register directives
+    * register nodes
+    * register roles
+    * register transforms
+    * connect events to functions
+
+    :param app: The sphinx application.
+    :type app: :class:`sphinx.application.Sphinx`
+    """
+
+    app.add_directive("bibliography", BibliographyDirective)
+    app.add_role("cite", CiteRole())
+    app.add_node(bibliography)
+    app.add_transform(BibliographyTransform)
+    app.connect("builder-inited", init_bibtex_cache)
+    app.connect("doctree-resolved", process_citations)
+    app.connect("doctree-resolved", process_citation_references)
+    app.connect("env-purge-doc", purge_bibtex_cache)
+    app.connect("env-updated", check_duplicate_labels)
+    # Parallel read is not safe at the moment: in the current design,
+    # the document that contains references must be read last for all
+    # references to be resolved.
+    return {'parallel_read_safe': False}
diff --git a/sphinxcontrib/bibtex/cache.py b/sphinxcontrib/bibtex/cache.py
new file mode 100644
index 0000000..0f1b32a
--- /dev/null
+++ b/sphinxcontrib/bibtex/cache.py
@@ -0,0 +1,393 @@
+# -*- coding: utf-8 -*-
+"""
+    Cached Information
+    ~~~~~~~~~~~~~~~~~~
+
+    Classes and methods to maintain any information that is stored
+    outside the doctree.
+
+    .. autoclass:: Cache
+        :members:
+
+    .. autoclass:: BibfileCache
+        :members:
+
+    .. autoclass:: BibliographyCache
+        :members:
+"""
+
+import sys
+import six
+if sys.version_info < (2, 7):  # pragma: no cover
+    from ordereddict import OrderedDict
+else:                          # pragma: no cover
+    from collections import OrderedDict
+
+import ast
+import collections
+import copy
+from oset import oset
+import re
+
+
+def _raise_invalid_node(node):
+    """Helper method to raise an exception when an invalid node is
+    visited.
+    """
+    raise ValueError("invalid node %s in filter expression" % node)
+
+
+class _FilterVisitor(ast.NodeVisitor):
+
+    """Visit the abstract syntax tree of a parsed filter expression."""
+
+    entry = None
+    """The bibliographic entry to which the filter must be applied."""
+
+    cited_docnames = False
+    """The documents where the entry is cited (empty if not cited)."""
+
+    def __init__(self, entry, docname, cited_docnames):
+        self.entry = entry
+        self.docname = docname
+        self.cited_docnames = cited_docnames
+
+    def visit_Module(self, node):
+        if len(node.body) != 1:
+            raise ValueError(
+                "filter expression cannot contain multiple expressions")
+        return self.visit(node.body[0])
+
+    def visit_Expr(self, node):
+        return self.visit(node.value)
+
+    def visit_BoolOp(self, node):
+        outcomes = (self.visit(value) for value in node.values)
+        if isinstance(node.op, ast.And):
+            return all(outcomes)
+        elif isinstance(node.op, ast.Or):
+            return any(outcomes)
+        else:  # pragma: no cover
+            # there are no other boolean operators
+            # so this code should never execute
+            assert False, "unexpected boolean operator %s" % node.op
+
+    def visit_UnaryOp(self, node):
+        if isinstance(node.op, ast.Not):
+            return not self.visit(node.operand)
+        else:
+            _raise_invalid_node(node)
+
+    def visit_BinOp(self, node):
+        left = self.visit(node.left)
+        op = node.op
+        right = self.visit(node.right)
+        if isinstance(op, ast.Mod):
+            # modulo operator is used for regular expression matching
+            if not isinstance(left, six.string_types):
+                raise ValueError(
+                    "expected a string on left side of %s" % node.op)
+            if not isinstance(right, six.string_types):
+                raise ValueError(
+                    "expected a string on right side of %s" % node.op)
+            return re.search(right, left, re.IGNORECASE)
+        elif isinstance(op, ast.BitOr):
+            return left | right
+        elif isinstance(op, ast.BitAnd):
+            return left & right
+        else:
+            _raise_invalid_node(node)
+
+    def visit_Compare(self, node):
+        # keep it simple: binary comparators only
+        if len(node.ops) != 1:
+            raise ValueError("syntax for multiple comparators not supported")
+        left = self.visit(node.left)
+        op = node.ops[0]
+        right = self.visit(node.comparators[0])
+        if isinstance(op, ast.Eq):
+            return left == right
+        elif isinstance(op, ast.NotEq):
+            return left != right
+        elif isinstance(op, ast.Lt):
+            return left < right
+        elif isinstance(op, ast.LtE):
+            return left <= right
+        elif isinstance(op, ast.Gt):
+            return left > right
+        elif isinstance(op, ast.GtE):
+            return left >= right
+        elif isinstance(op, ast.In):
+            return left in right
+        elif isinstance(op, ast.NotIn):
+            return left not in right
+        else:
+            # not used currently: ast.Is | ast.IsNot
+            _raise_invalid_node(op)
+
+    def visit_Name(self, node):
+        """Calculate the value of the given identifier."""
+        id_ = node.id
+        if id_ == 'type':
+            return self.entry.type.lower()
+        elif id_ == 'key':
+            return self.entry.key.lower()
+        elif id_ == 'cited':
+            return bool(self.cited_docnames)
+        elif id_ == 'docname':
+            return self.docname
+        elif id_ == 'docnames':
+            return self.cited_docnames
+        elif id_ == 'True':
+            return True
+        elif id_ == 'False':
+            return False
+        elif id_ == 'author' or id_ == 'editor':
+            if id_ in self.entry.persons:
+                return u' and '.join(
+                    six.text_type(person)  # XXX needs fix in pybtex?
+                    for person in self.entry.persons[id_])
+            else:
+                return u''
+        else:
+            return self.entry.fields.get(id_, "")
+
+    def visit_Set(self, node):
+        return frozenset(self.visit(elt) for elt in node.elts)
+
+    def visit_Str(self, node):
+        return node.s
+
+    # NameConstant is Python 3.4 only so do not insist on coverage
+    def visit_NameConstant(self, node):  # pragma: no cover
+        return node.value
+
+    def generic_visit(self, node):
+        _raise_invalid_node(node)
+
+
+class Cache:
+
+    """Global bibtex extension information cache. Stored in
+    ``app.env.bibtex_cache``, so must be picklable.
+    """
+
+    bibfiles = None
+    """A :class:`dict` mapping .bib file names (relative to the top
+    source folder) to :class:`BibfileCache` instances.
+    """
+
+    _bibliographies = None
+    """Each bibliography directive is assigned an id of the form
+    bibtex-bibliography-xxx. This :class:`dict` maps each docname
+    to another :class:`dict` which maps each id
+    to information about the bibliography directive,
+    :class:`BibliographyCache`. We need to store this extra
+    information separately because it cannot be stored in the
+    :class:`~sphinxcontrib.bibtex.nodes.bibliography` nodes
+    themselves.
+    """
+
+    _cited = None
+    """A :class:`dict` mapping each docname to a :class:`set` of
+    citation keys.
+    """
+
+    _enum_count = None
+    """A :class:`dict` mapping each docname to an :class:`int`
+    representing the current bibliography enumeration counter.
+    """
+
+    def __init__(self):
+
+        self.bibfiles = {}
+        self._bibliographies = collections.defaultdict(dict)
+        self._cited = collections.defaultdict(oset)
+        self._enum_count = {}
+
+    def purge(self, docname):
+        """Remove  all information related to *docname*.
+
+        :param docname: The document name.
+        :type docname: :class:`str`
+        """
+        self._bibliographies.pop(docname, None)
+        self._cited.pop(docname, None)
+        self._enum_count.pop(docname, None)
+
+    def inc_enum_count(self, docname):
+        """Increment enumeration list counter for document *docname*."""
+        self._enum_count[docname] += 1
+
+    def set_enum_count(self, docname, value):
+        """Set enumeration list counter for document *docname* to *value*."""
+        self._enum_count[docname] = value
+
+    def get_enum_count(self, docname):
+        """Get enumeration list counter for document *docname*."""
+        return self._enum_count[docname]
+
+    def add_cited(self, key, docname):
+        """Add the given *key* to the set of cited keys for
+        *docname*.
+
+        :param key: The citation key.
+        :type key: :class:`str`
+        :param docname: The document name.
+        :type docname: :class:`str`
+        """
+        self._cited[docname].add(key)
+
+    def get_cited_docnames(self, key):
+        """Return the *docnames* from which the given *key* is cited.
+
+        :param key: The citation key.
+        :type key: :class:`str`
+        """
+        return frozenset([
+            docname for docname, keys in six.iteritems(self._cited)
+            if key in keys])
+
+    def get_label_from_key(self, key):
+        """Return label for the given key."""
+        for bibcache in self.get_all_bibliography_caches():
+            if key in bibcache.labels:
+                return bibcache.labels[key]
+        else:
+            raise KeyError("%s not found" % key)
+
+    def get_all_cited_keys(self):
+        """Yield all citation keys, sorted first by document
+        (alphabetical), then by citation order in the document.
+        """
+        for docname in sorted(self._cited):
+            for key in self._cited[docname]:
+                yield key
+
+    def set_bibliography_cache(self, docname, id_, bibcache):
+        """Register *bibcache* (:class:`BibliographyCache`)
+        with id *id_* for document *docname*.
+        """
+        assert id_ not in self._bibliographies[docname]
+        self._bibliographies[docname][id_] = bibcache
+
+    def get_bibliography_cache(self, docname, id_):
+        """Return :class:`BibliographyCache` with id *id_* in
+        document *docname*.
+        """
+        return self._bibliographies[docname][id_]
+
+    def get_all_bibliography_caches(self):
+        """Return all bibliography caches."""
+        for bibcaches in six.itervalues(self._bibliographies):
+            for bibcache in six.itervalues(bibcaches):
+                yield bibcache
+
+    def _get_bibliography_entries(self, docname, id_, warn):
+        """Return filtered bibliography entries, sorted by occurence
+        in the bib file.
+        """
+        # get the information of this bibliography node
+        bibcache = self.get_bibliography_cache(docname=docname, id_=id_)
+        # generate entries
+        for bibfile in bibcache.bibfiles:
+            data = self.bibfiles[bibfile].data
+            for entry in six.itervalues(data.entries):
+                cited_docnames = self.get_cited_docnames(entry.key)
+                visitor = _FilterVisitor(
+                    entry=entry,
+                    docname=docname,
+                    cited_docnames=cited_docnames)
+                try:
+                    success = visitor.visit(bibcache.filter_)
+                except ValueError as err:
+                    warn("syntax error in :filter: expression; %s" % err)
+                    # recover by falling back to the default
+                    success = bool(cited_docnames)
+                if success:
+                    # entries are modified in an unpickable way
+                    # when formatting, so fetch a deep copy
+                    yield copy.deepcopy(entry)
+
+    def get_bibliography_entries(self, docname, id_, warn):
+        """Return filtered bibliography entries, sorted by citation order."""
+        # get entries, ordered by bib file occurrence
+        entries = OrderedDict(
+            (entry.key, entry) for entry in
+            self._get_bibliography_entries(
+                docname=docname, id_=id_, warn=warn))
+        # order entries according to which were cited first
+        # first, we add all keys that were cited
+        # then, we add all remaining keys
+        sorted_entries = []
+        for key in self.get_all_cited_keys():
+            try:
+                entry = entries.pop(key)
+            except KeyError:
+                pass
+            else:
+                sorted_entries.append(entry)
+        sorted_entries += six.itervalues(entries)
+        return sorted_entries
+
+
+class BibfileCache(collections.namedtuple('BibfileCache', 'mtime data')):
+
+    """Contains information about a parsed .bib file.
+
+    .. attribute:: mtime
+
+        A :class:`float` representing the modification time of the .bib
+        file when it was last parsed.
+
+    .. attribute:: data
+
+        A :class:`pybtex.database.BibliographyData` containing the
+        parsed .bib file.
+
+    """
+
+
+class BibliographyCache(collections.namedtuple(
+    'BibliographyCache',
+    """bibfiles style encoding
+list_ enumtype start labels labelprefix
+filter_ curly_bracket_strip
+""")):
+
+    """Contains information about a bibliography directive.
+
+    .. attribute:: bibfiles
+
+        A :class:`list` of :class:`str`\\ s containing the .bib file
+        names (relative to the top source folder) that contain the
+        references.
+
+    .. attribute:: style
+
+        The bibtex style.
+
+    .. attribute:: list_
+
+        The list type.
+
+    .. attribute:: enumtype
+
+        The sequence type (only used for enumerated lists).
+
+    .. attribute:: start
+
+        The first ordinal of the sequence (only used for enumerated lists).
+
+    .. attribute:: labels
+
+        Maps citation keys to their final labels.
+
+    .. attribute:: labelprefix
+
+        This bibliography's string prefix for pybtex generated labels.
+
+    .. attribute:: filter_
+
+        An :class:`ast.AST` node, containing the parsed filter expression.
+    """
diff --git a/sphinxcontrib/bibtex/directives.py b/sphinxcontrib/bibtex/directives.py
new file mode 100644
index 0000000..8d6927d
--- /dev/null
+++ b/sphinxcontrib/bibtex/directives.py
@@ -0,0 +1,218 @@
+"""
+    New Doctree Directives
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    .. autoclass:: BibliographyDirective
+
+        .. automethod:: run
+        .. automethod:: process_bibfile
+        .. automethod:: update_bibfile_cache
+        .. automethod:: parse_bibfile
+
+    .. autofunction:: process_start_option
+"""
+
+import ast  # parse(), used for filter
+import os.path  # getmtime()
+
+from docutils.parsers.rst import directives  # for Directive.option_spec
+from sphinx.util.compat import Directive
+from sphinx.util.console import bold, standout
+
+from pybtex.database.input import bibtex
+from pybtex.database import BibliographyData
+
+from sphinxcontrib.bibtex.cache import BibliographyCache, BibfileCache
+from sphinxcontrib.bibtex.nodes import bibliography
+
+# register the latex codec
+import latexcodec  # noqa
+
+
+def process_start_option(value):
+    """Process and validate the start option value
+    of a :rst:dir:`bibliography` directive.
+    If *value* is ``continue`` then this function returns -1,
+    otherwise *value* is converted into a positive integer.
+    """
+    if value == "continue":
+        return -1
+    else:
+        return directives.positive_int(value)
+
+
+class BibliographyDirective(Directive):
+
+    """Class for processing the :rst:dir:`bibliography` directive.
+
+    Parses the bibliography files, and produces a
+    :class:`~sphinxcontrib.bibtex.nodes.bibliography` node.
+
+    .. seealso::
+
+       Further processing of the resulting
+       :class:`~sphinxcontrib.bibtex.nodes.bibliography` node is done
+       by
+       :class:`~sphinxcontrib.bibtex.transforms.BibliographyTransform`.
+    """
+
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+    has_content = False
+    option_spec = {
+        'cited': directives.flag,
+        'notcited': directives.flag,
+        'all': directives.flag,
+        'filter': directives.unchanged,
+        'style': directives.unchanged,
+        'list': directives.unchanged,
+        'enumtype': directives.unchanged,
+        'start': process_start_option,
+        'encoding': directives.encoding,
+        'disable-curly-bracket-strip': directives.flag,
+        'labelprefix': directives.unchanged,
+    }
+
+    def run(self):
+        """Process .bib files, set file dependencies, and create a
+        node that is to be transformed to the entries of the
+        bibliography.
+        """
+        env = self.state.document.settings.env
+        # create id and cache for this node
+        # this id will be stored with the node
+        # and is used to look up additional data in env.bibtex_cache
+        # (implementation note: new_serialno only guarantees unique
+        # ids within a single document, but we need the id to be
+        # unique across all documents, so we also include the docname
+        # in the id)
+        id_ = 'bibtex-bibliography-%s-%s' % (
+            env.docname, env.new_serialno('bibtex'))
+        if "filter" in self.options:
+            if "all" in self.options:
+                env.app.warn(standout(":filter: overrides :all:"))
+            if "notcited" in self.options:
+                env.app.warn(standout(":filter: overrides :notcited:"))
+            if "cited" in self.options:
+                env.app.warn(standout(":filter: overrides :cited:"))
+            try:
+                filter_ = ast.parse(self.options["filter"])
+            except SyntaxError:
+                env.app.warn(
+                    standout("syntax error in :filter: expression")
+                    + " (" + self.options["filter"] + "); "
+                    "the option will be ignored"
+                )
+                filter_ = ast.parse("cited")
+        elif "all" in self.options:
+            filter_ = ast.parse("True")
+        elif "notcited" in self.options:
+            filter_ = ast.parse("not cited")
+        else:
+            # the default filter: include only cited entries
+            filter_ = ast.parse("cited")
+        bibcache = BibliographyCache(
+            list_=self.options.get("list", "citation"),
+            enumtype=self.options.get("enumtype", "arabic"),
+            start=self.options.get("start", 1),
+            style=self.options.get("style", "alpha"),
+            filter_=filter_,
+            encoding=self.options.get(
+                'encoding',
+                'latex+' + self.state.document.settings.input_encoding),
+            curly_bracket_strip=(
+                'disable-curly-bracket-strip' not in self.options),
+            labelprefix=self.options.get("labelprefix", ""),
+            labels={},
+            bibfiles=[],
+        )
+        if (bibcache.list_ not in set(["bullet", "enumerated", "citation"])):
+            env.app.warn(
+                "unknown bibliography list type '{0}'.".format(bibcache.list_))
+        for bibfile in self.arguments[0].split():
+            # convert to normalized absolute path to ensure that the same file
+            # only occurs once in the cache
+            bibfile = os.path.normpath(env.relfn2path(bibfile.strip())[1])
+            self.process_bibfile(bibfile, bibcache.encoding)
+            env.note_dependency(bibfile)
+            bibcache.bibfiles.append(bibfile)
+        env.bibtex_cache.set_bibliography_cache(env.docname, id_, bibcache)
+        return [bibliography('', ids=[id_])]
+
+    def parse_bibfile(self, bibfile, encoding):
+        """Parse *bibfile*, and return parsed data.
+
+        :param bibfile: The bib file name.
+        :type bibfile: ``str``
+        :return: The parsed bibliography data.
+        :rtype: :class:`pybtex.database.BibliographyData`
+        """
+        app = self.state.document.settings.env.app
+        parser = bibtex.Parser(encoding)
+        app.info(
+            bold("parsing bibtex file {0}... ".format(bibfile)), nonl=True)
+        parser.parse_file(bibfile)
+        app.info("parsed {0} entries"
+                 .format(len(parser.data.entries)))
+        return parser.data
+
+    def update_bibfile_cache(self, bibfile, mtime, encoding):
+        """Parse *bibfile* (see :meth:`parse_bibfile`), and store the
+        parsed data, along with modification time *mtime*, in the
+        bibtex cache.
+
+        :param bibfile: The bib file name.
+        :type bibfile: ``str``
+        :param mtime: The bib file's modification time.
+        :type mtime: ``float``
+        :return: The parsed bibliography data.
+        :rtype: :class:`pybtex.database.BibliographyData`
+        """
+        data = self.parse_bibfile(bibfile, encoding)
+        env = self.state.document.settings.env
+        env.bibtex_cache.bibfiles[bibfile] = BibfileCache(
+            mtime=mtime,
+            data=data)
+        return data
+
+    def process_bibfile(self, bibfile, encoding):
+        """Check if ``env.bibtex_cache.bibfiles[bibfile]`` is still
+        up to date. If not, parse the *bibfile* (see
+        :meth:`update_bibfile_cache`), and store parsed data in the
+        bibtex cache.
+
+        :param bibfile: The bib file name.
+        :type bibfile: ``str``
+        :return: The parsed bibliography data.
+        :rtype: :class:`pybtex.database.BibliographyData`
+        """
+        env = self.state.document.settings.env
+        cache = env.bibtex_cache.bibfiles
+        # get modification time of bibfile
+        try:
+            mtime = os.path.getmtime(bibfile)
+        except OSError:
+            env.app.warn(
+                standout("could not open bibtex file {0}.".format(bibfile)))
+            cache[bibfile] = BibfileCache(  # dummy cache
+                mtime=-float("inf"), data=BibliographyData())
+            return cache[bibfile].data
+        # get cache and check if it is still up to date
+        # if it is not up to date, parse the bibtex file
+        # and store it in the cache
+        env.app.info(
+            bold("checking for {0} in bibtex cache... ".format(bibfile)),
+            nonl=True)
+        try:
+            bibfile_cache = cache[bibfile]
+        except KeyError:
+            env.app.info("not found")
+            self.update_bibfile_cache(bibfile, mtime, encoding)
+        else:
+            if mtime != bibfile_cache.mtime:
+                env.app.info("out of date")
+                self.update_bibfile_cache(bibfile, mtime, encoding)
+            else:
+                env.app.info('up to date')
+        return cache[bibfile].data
diff --git a/sphinxcontrib/bibtex/nodes.py b/sphinxcontrib/bibtex/nodes.py
new file mode 100644
index 0000000..426aed9
--- /dev/null
+++ b/sphinxcontrib/bibtex/nodes.py
@@ -0,0 +1,17 @@
+"""
+    New Doctree Nodes
+    ~~~~~~~~~~~~~~~~~
+
+    .. autoclass:: bibliography
+"""
+
+from docutils import nodes
+
+
+class bibliography(nodes.General, nodes.Element):
+
+    """Node for representing a bibliography. Replaced by a list of
+    citations by
+    :class:`~sphinxcontrib.bibtex.transforms.BibliographyTransform`.
+    """
+    pass
diff --git a/sphinxcontrib/bibtex/roles.py b/sphinxcontrib/bibtex/roles.py
new file mode 100644
index 0000000..bbbd1f0
--- /dev/null
+++ b/sphinxcontrib/bibtex/roles.py
@@ -0,0 +1,43 @@
+"""
+    New Doctree Roles
+    ~~~~~~~~~~~~~~~~~
+
+    .. autoclass:: CiteRole
+        :show-inheritance:
+
+        .. automethod:: result_nodes
+"""
+
+from pybtex.plugin import find_plugin
+import pybtex.database
+from sphinx.roles import XRefRole  # for :cite:
+
+
+class CiteRole(XRefRole):
+
+    """Class for processing the :rst:role:`cite` role."""
+    backend = find_plugin('pybtex.backends', 'docutils')()
+
+    def result_nodes(self, document, env, node, is_ref):
+        """Transform reference node into a citation reference,
+        and note that the reference was cited.
+        """
+        keys = node['reftarget'].split(',')
+        # Note that at this point, usually, env.bibtex_cache.bibfiles
+        # is still empty because the bibliography directive may not
+        # have been processed yet, so we cannot get the actual entry.
+        # Instead, we simply fake an entry with the desired key, and
+        # fix the label at doctree-resolved time. This happens in
+        # process_citation_references.
+        refnodes = [
+            self.backend.citation_reference(_fake_entry(key), document)
+            for key in keys]
+        for key in keys:
+            env.bibtex_cache.add_cited(key, env.docname)
+        return refnodes, []
+
+
+def _fake_entry(key):
+    entry = pybtex.database.Entry(type_="")
+    entry.key = key
+    return entry
diff --git a/sphinxcontrib/bibtex/transforms.py b/sphinxcontrib/bibtex/transforms.py
new file mode 100644
index 0000000..8e4cdcb
--- /dev/null
+++ b/sphinxcontrib/bibtex/transforms.py
@@ -0,0 +1,127 @@
+"""
+    New Doctree Transforms
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    .. autoclass:: BibliographyTransform
+        :show-inheritance:
+
+        .. autoattribute:: default_priority
+        .. automethod:: apply
+
+    .. autofunction:: node_text_transform
+
+    .. autofunction:: transform_curly_bracket_strip
+
+    .. autofunction:: transform_url_command
+"""
+
+import docutils.nodes
+import docutils.transforms
+
+from pybtex.plugin import find_plugin
+
+from sphinxcontrib.bibtex.nodes import bibliography
+
+
+def node_text_transform(node, transform):
+    """Apply transformation to all Text nodes within node."""
+    for child in node.children:
+        if isinstance(child, docutils.nodes.Text):
+            node.replace(child, transform(child))
+        else:
+            node_text_transform(child, transform)
+
+
+def transform_curly_bracket_strip(textnode):
+    """Strip curly brackets from text."""
+    text = textnode.astext()
+    if '{' in text or '}' in text:
+        text = text.replace('{', '').replace('}', '')
+        return docutils.nodes.Text(text)
+    else:
+        return textnode
+
+
+def transform_url_command(textnode):
+    """Convert '\\\\url{...}' into a proper docutils hyperlink."""
+    text = textnode.astext()
+    if '\\url' in text:
+        text1, _, text = text.partition('\\url')
+        text2, _, text3 = text.partition('}')
+        text2 = text2.lstrip(' {')
+        ref = docutils.nodes.reference(refuri=text2)
+        ref += docutils.nodes.Text(text2)
+        node = docutils.nodes.inline()
+        node += transform_url_command(docutils.nodes.Text(text1))
+        node += ref
+        node += transform_url_command(docutils.nodes.Text(text3))
+        return node
+    else:
+        return textnode
+
+
+class BibliographyTransform(docutils.transforms.Transform):
+
+    """A docutils transform to generate citation entries for
+    bibliography nodes.
+    """
+
+    # transform must be applied before references are resolved
+    default_priority = 10
+    """Priority of the transform. See
+    http://docutils.sourceforge.net/docs/ref/transforms.html
+    """
+
+    def apply(self):
+        """Transform each
+        :class:`~sphinxcontrib.bibtex.nodes.bibliography` node into a
+        list of citations.
+        """
+        env = self.document.settings.env
+        docname = env.docname
+        for bibnode in self.document.traverse(bibliography):
+            id_ = bibnode['ids'][0]
+            bibcache = env.bibtex_cache.get_bibliography_cache(
+                docname=docname, id_=id_)
+            entries = env.bibtex_cache.get_bibliography_entries(
+                docname=docname, id_=id_, warn=env.app.warn)
+            # locate and instantiate style and backend plugins
+            style = find_plugin('pybtex.style.formatting', bibcache.style)()
+            backend = find_plugin('pybtex.backends', 'docutils')()
+            # create citation nodes for all references
+            if bibcache.list_ == "enumerated":
+                nodes = docutils.nodes.enumerated_list()
+                nodes['enumtype'] = bibcache.enumtype
+                if bibcache.start >= 1:
+                    nodes['start'] = bibcache.start
+                    env.bibtex_cache.set_enum_count(
+                        env.docname, bibcache.start)
+                else:
+                    nodes['start'] = env.bibtex_cache.get_enum_count(
+                        env.docname)
+            elif bibcache.list_ == "bullet":
+                nodes = docutils.nodes.bullet_list()
+            else:  # "citation"
+                nodes = docutils.nodes.paragraph()
+            # remind: style.format_entries modifies entries in unpickable way
+            for entry in style.format_entries(entries):
+                if bibcache.list_ in ["enumerated", "bullet"]:
+                    citation = docutils.nodes.list_item()
+                    citation += backend.paragraph(entry)
+                else:  # "citation"
+                    citation = backend.citation(entry, self.document)
+                    # backend.citation(...) uses entry.key as citation label
+                    # we change it to entry.label later onwards
+                    # but we must note the entry.label now;
+                    # at this point, we also already prefix the label
+                    key = citation[0].astext()
+                    bibcache.labels[key] = bibcache.labelprefix + entry.label
+                node_text_transform(citation, transform_url_command)
+                if bibcache.curly_bracket_strip:
+                    node_text_transform(
+                        citation,
+                        transform_curly_bracket_strip)
+                nodes += citation
+                if bibcache.list_ == "enumerated":
+                    env.bibtex_cache.inc_enum_count(env.docname)
+            bibnode.replace_self(nodes)
diff --git a/test/bibfile_out_of_date/conf.py b/test/bibfile_out_of_date/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/bibfile_out_of_date/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/bibfile_out_of_date/contents.rst b/test/bibfile_out_of_date/contents.rst
new file mode 100644
index 0000000..f14410d
--- /dev/null
+++ b/test/bibfile_out_of_date/contents.rst
@@ -0,0 +1,3 @@
+.. bibliography:: test.bib
+   :style: plain
+   :all:
diff --git a/test/bibfile_out_of_date/test_new.bib b/test/bibfile_out_of_date/test_new.bib
new file mode 100644
index 0000000..2994674
--- /dev/null
+++ b/test/bibfile_out_of_date/test_new.bib
@@ -0,0 +1,16 @@
+ at Misc{test1,
+  author =    {Mr. Test Eminence},
+  title =     {Test 1},
+}
+ at Misc{test2,
+  author =    {Mr. Test Frater},
+  title =     {Test 2},
+}
+ at Misc{test3,
+  author =    {Mr. Test Giggles},
+  title =     {Test 3},
+}
+ at Misc{test4,
+  author =    {Mr. Test Handy},
+  title =     {Test 4},
+}
diff --git a/test/bibfile_out_of_date/test_old.bib b/test/bibfile_out_of_date/test_old.bib
new file mode 100644
index 0000000..6f1930a
--- /dev/null
+++ b/test/bibfile_out_of_date/test_old.bib
@@ -0,0 +1,16 @@
+ at Misc{test1,
+  author =    {Mr. Test Akkerdju},
+  title =     {Test 1},
+}
+ at Misc{test2,
+  author =    {Mr. Test Bro},
+  title =     {Test 2},
+}
+ at Misc{test3,
+  author =    {Mr. Test Chap},
+  title =     {Test 3},
+}
+ at Misc{test4,
+  author =    {Mr. Test Dude},
+  title =     {Test 4},
+}
diff --git a/test/bibfilenotfound/conf.py b/test/bibfilenotfound/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/bibfilenotfound/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/bibfilenotfound/contents.rst b/test/bibfilenotfound/contents.rst
new file mode 100644
index 0000000..5c1f74e
--- /dev/null
+++ b/test/bibfilenotfound/contents.rst
@@ -0,0 +1 @@
+.. bibliography:: unknown.bib
diff --git a/test/citationnotfound/conf.py b/test/citationnotfound/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/citationnotfound/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/citationnotfound/contents.rst b/test/citationnotfound/contents.rst
new file mode 100644
index 0000000..1185dbe
--- /dev/null
+++ b/test/citationnotfound/contents.rst
@@ -0,0 +1,3 @@
+:cite:`nosuchkey`
+
+.. bibliography:: test.bib
diff --git a/test/citationnotfound/test.bib b/test/citationnotfound/test.bib
new file mode 100644
index 0000000..e69de29
diff --git a/test/custom_style/conf.py b/test/custom_style/conf.py
new file mode 100644
index 0000000..f519ef7
--- /dev/null
+++ b/test/custom_style/conf.py
@@ -0,0 +1,17 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
+
+# create and register pybtex plugins
+
+from pybtex.style.formatting.unsrt import Style as UnsrtStyle
+from pybtex.style.template import words
+from pybtex.plugin import register_plugin
+
+
+class NoWebRefStyle(UnsrtStyle):
+
+    def format_web_refs(self, e):
+        # the following is just one simple way to return an empty node
+        return words['']
+
+register_plugin('pybtex.style.formatting', 'nowebref', NoWebRefStyle)
diff --git a/test/custom_style/contents.rst b/test/custom_style/contents.rst
new file mode 100644
index 0000000..daeff61
--- /dev/null
+++ b/test/custom_style/contents.rst
@@ -0,0 +1,4 @@
+.. bibliography:: test.bib
+   :style: nowebref
+   :all:
+   :list: bullet
diff --git a/test/custom_style/test.bib b/test/custom_style/test.bib
new file mode 100644
index 0000000..f77e079
--- /dev/null
+++ b/test/custom_style/test.bib
@@ -0,0 +1,27 @@
+ at Misc{2009:mandel,
+author = {Jan Mandel},
+title = {A Brief Tutorial on the Ensemble {K}alman Filter},
+howpublished = {arXiv:0901.3725v1 [physics.ao-ph]},
+month =     jan,
+year =      {2009},
+OPTnote =      {},
+OPTannote =    {},
+archivePrefix = {arXiv},
+eprint        = {0901.3725},
+primaryClass  = {physics.ao-ph}
+}
+
+ at Article{2003:evensen,
+  author =       {Geir Evensen},
+  title =        {The Ensemble {K}alman Filter: theoretical formulation and practical implementation},
+  journal =      {Ocean Dynamics},
+  year =         {2003},
+  OPTkey =       {},
+  volume =    {53},
+  number =    {4},
+  pages =     {343--367},
+  OPTmonth =     {},
+  OPTnote =      {},
+  OPTannote =    {},
+  doi = {10.1007/s10236-003-0036-9}
+}
diff --git a/test/filter/bitand.rst b/test/filter/bitand.rst
new file mode 100644
index 0000000..1bf2ae4
--- /dev/null
+++ b/test/filter/bitand.rst
@@ -0,0 +1,6 @@
+Set
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: {"doc1", "doc2"} & docnames
diff --git a/test/filter/bitor.rst b/test/filter/bitor.rst
new file mode 100644
index 0000000..15439a5
--- /dev/null
+++ b/test/filter/bitor.rst
@@ -0,0 +1,6 @@
+Set
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: {"doc1", "doc2"} | docnames
diff --git a/test/filter/conf.py b/test/filter/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/filter/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/filter/contents.rst b/test/filter/contents.rst
new file mode 100644
index 0000000..7284c0a
--- /dev/null
+++ b/test/filter/contents.rst
@@ -0,0 +1,20 @@
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: author % "Second" and type == "misc"
+
+.. toctree::
+
+   or
+   noteq
+   lt
+   lte
+   gt
+   gte
+   key
+   false
+   title
+   in
+   notin
+   set
+   bitand
+   bitor
diff --git a/test/filter/false.rst b/test/filter/false.rst
new file mode 100644
index 0000000..eb3d078
--- /dev/null
+++ b/test/filter/false.rst
@@ -0,0 +1,6 @@
+False
+-----
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: False
diff --git a/test/filter/gt.rst b/test/filter/gt.rst
new file mode 100644
index 0000000..0448fd2
--- /dev/null
+++ b/test/filter/gt.rst
@@ -0,0 +1,6 @@
+Gt
+--
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: year > "2011"
diff --git a/test/filter/gte.rst b/test/filter/gte.rst
new file mode 100644
index 0000000..49f61a9
--- /dev/null
+++ b/test/filter/gte.rst
@@ -0,0 +1,6 @@
+Gte
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: year >= "2011"
diff --git a/test/filter/in.rst b/test/filter/in.rst
new file mode 100644
index 0000000..4cdcae3
--- /dev/null
+++ b/test/filter/in.rst
@@ -0,0 +1,6 @@
+In
+--
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: "bla" in docnames
diff --git a/test/filter/key.rst b/test/filter/key.rst
new file mode 100644
index 0000000..4f5662a
--- /dev/null
+++ b/test/filter/key.rst
@@ -0,0 +1,6 @@
+Key
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: key == "third"
diff --git a/test/filter/lt.rst b/test/filter/lt.rst
new file mode 100644
index 0000000..ae91df7
--- /dev/null
+++ b/test/filter/lt.rst
@@ -0,0 +1,6 @@
+Lt
+--
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: year < "2011"
diff --git a/test/filter/lte.rst b/test/filter/lte.rst
new file mode 100644
index 0000000..7ff7638
--- /dev/null
+++ b/test/filter/lte.rst
@@ -0,0 +1,6 @@
+Lte
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: year <= "2011"
diff --git a/test/filter/noteq.rst b/test/filter/noteq.rst
new file mode 100644
index 0000000..bb30aa8
--- /dev/null
+++ b/test/filter/noteq.rst
@@ -0,0 +1,6 @@
+NotEq
+-----
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: year != "2011"
diff --git a/test/filter/notin.rst b/test/filter/notin.rst
new file mode 100644
index 0000000..ebf49c4
--- /dev/null
+++ b/test/filter/notin.rst
@@ -0,0 +1,6 @@
+Not In
+------
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: "bla" not in docnames
diff --git a/test/filter/or.rst b/test/filter/or.rst
new file mode 100644
index 0000000..12ac9c0
--- /dev/null
+++ b/test/filter/or.rst
@@ -0,0 +1,6 @@
+Or
+--
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: author % "First" or type == "article"
diff --git a/test/filter/set.rst b/test/filter/set.rst
new file mode 100644
index 0000000..1a01051
--- /dev/null
+++ b/test/filter/set.rst
@@ -0,0 +1,6 @@
+Set
+---
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: {"doc1", "doc2"} <= docnames
diff --git a/test/filter/test.bib b/test/filter/test.bib
new file mode 100644
index 0000000..5e44ead
--- /dev/null
+++ b/test/filter/test.bib
@@ -0,0 +1,18 @@
+ at Misc{second,
+  author =    {B. Second},
+  title =     {Tralalala},
+  year =      {2010}
+}
+
+ at Article{third,
+  author =       {B. Second},
+  title =        {Heb je een ideetje},
+  journal =      {Journal of Kaatje},
+  year =         {2012}
+}
+
+ at Misc{first,
+  author =    {A. First},
+  title =     {Jakkamakka},
+  year =      {2011}
+}
diff --git a/test/filter/title.rst b/test/filter/title.rst
new file mode 100644
index 0000000..13fbeec
--- /dev/null
+++ b/test/filter/title.rst
@@ -0,0 +1,6 @@
+Title
+-----
+
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: title and title % "jakka"
diff --git a/test/filter_fix_author_keyerror/conf.py b/test/filter_fix_author_keyerror/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/filter_fix_author_keyerror/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/filter_fix_author_keyerror/contents.rst b/test/filter_fix_author_keyerror/contents.rst
new file mode 100644
index 0000000..1246cac
--- /dev/null
+++ b/test/filter_fix_author_keyerror/contents.rst
@@ -0,0 +1,3 @@
+.. bibliography:: test.bib
+   :list: bullet
+   :filter: author % "Test"
diff --git a/test/filter_fix_author_keyerror/test.bib b/test/filter_fix_author_keyerror/test.bib
new file mode 100644
index 0000000..ea85e60
--- /dev/null
+++ b/test/filter_fix_author_keyerror/test.bib
@@ -0,0 +1,4 @@
+ at Misc{second,
+  title =     {Tralalala},
+  year =      {2010}
+}
diff --git a/test/filter_option_clash/conf.py b/test/filter_option_clash/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/filter_option_clash/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/filter_option_clash/contents.rst b/test/filter_option_clash/contents.rst
new file mode 100644
index 0000000..a8622eb
--- /dev/null
+++ b/test/filter_option_clash/contents.rst
@@ -0,0 +1,5 @@
+.. bibliography:: test.bib
+   :all:
+   :cited:
+   :notcited:
+   :filter: author % "Troffaes"
diff --git a/test/filter_option_clash/test.bib b/test/filter_option_clash/test.bib
new file mode 100644
index 0000000..e69de29
diff --git a/test/filter_syntax_error/conf.py b/test/filter_syntax_error/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/filter_syntax_error/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/filter_syntax_error/contents.rst b/test/filter_syntax_error/contents.rst
new file mode 100644
index 0000000..381eb77
--- /dev/null
+++ b/test/filter_syntax_error/contents.rst
@@ -0,0 +1,26 @@
+.. bibliography:: test.bib
+   :filter: $
+
+.. bibliography:: test.bib
+   :filter: yield author
+
+.. bibliography:: test.bib
+   :filter: author is title
+
+.. bibliography:: test.bib
+   :filter: False % title
+
+.. bibliography:: test.bib
+   :filter: title % False
+
+.. bibliography:: test.bib
+   :filter: ~title
+
+.. bibliography:: test.bib
+   :filter: "2000" <= year <= "2005"
+
+.. bibliography:: test.bib
+   :filter: author + title
+
+.. bibliography:: test.bib
+   :filter: author; title
diff --git a/test/filter_syntax_error/test.bib b/test/filter_syntax_error/test.bib
new file mode 100644
index 0000000..10773f8
--- /dev/null
+++ b/test/filter_syntax_error/test.bib
@@ -0,0 +1,5 @@
+ at misc{test,
+  author = {Mr. Tee},
+  title = {Baracuda},
+  year = {1553}
+}
\ No newline at end of file
diff --git a/test/invalid_cite_option/conf.py b/test/invalid_cite_option/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/invalid_cite_option/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/invalid_cite_option/contents.rst b/test/invalid_cite_option/contents.rst
new file mode 100644
index 0000000..fba257c
--- /dev/null
+++ b/test/invalid_cite_option/contents.rst
@@ -0,0 +1,2 @@
+.. bibliography:: test.bib
+   :thisisintentionallyinvalid:
diff --git a/test/invalid_cite_option/test.bib b/test/invalid_cite_option/test.bib
new file mode 100644
index 0000000..e69de29
diff --git a/test/issue1/2012/07/24/hello_world_.rst b/test/issue1/2012/07/24/hello_world_.rst
new file mode 100644
index 0000000..f02134c
--- /dev/null
+++ b/test/issue1/2012/07/24/hello_world_.rst
@@ -0,0 +1,11 @@
+Hello World!
+============
+
+:cite:`2011:BabikerIPv6`
+
+.. bibliography:: ../../../refs.bib
+
+.. author:: default
+.. categories:: none
+.. tags:: none
+.. comments::
diff --git a/test/issue1/conf.py b/test/issue1/conf.py
new file mode 100644
index 0000000..6d93857
--- /dev/null
+++ b/test/issue1/conf.py
@@ -0,0 +1,28 @@
+import tinkerer
+import tinkerer.paths
+project = 'My blog'
+tagline = 'Add intelligent tagline here'
+author = 'Mr Test'
+website = 'http://127.0.0.1/blog/html/'
+html_theme = "modern5"
+posts_per_page = 2
+
+extensions = [
+    'sphinxcontrib.bibtex',
+    'tinkerer.ext.blog',
+    'tinkerer.ext.disqus']
+
+html_static_path = [tinkerer.paths.static]
+html_theme_path = [tinkerer.paths.themes]
+exclude_patterns = ["drafts/*"]
+
+# **************************************************************
+# Do not modify below lines as the values are required by
+# Tinkerer to play nice with Sphinx
+# **************************************************************
+
+master_doc = tinkerer.master_doc
+html_title = project
+html_use_index = False
+html_show_sourcelink = False
+html_add_permalinks = ""
diff --git a/test/issue1/master.rst b/test/issue1/master.rst
new file mode 100644
index 0000000..125c9e1
--- /dev/null
+++ b/test/issue1/master.rst
@@ -0,0 +1,8 @@
+Sitemap
+=======
+
+.. toctree::
+   :maxdepth: 1
+
+   2012/07/24/hello_world_
+
diff --git a/test/issue1/refs.bib b/test/issue1/refs.bib
new file mode 100644
index 0000000..9ba43fd
--- /dev/null
+++ b/test/issue1/refs.bib
@@ -0,0 +1,6 @@
+ at InProceedings{2011:BabikerIPv6,
+  author =       {H. Babiker and I. Nikolova and K. Chittimaneni},
+  title =        {Deploying IPv6 in the Google Enterprise Network.  Lessons learned.},
+  booktitle = {USENIX LISA 2011},
+  year =         2011,
+  note = {\url{http://static.usenix.org/events/lisa11/tech/full_papers/Babiker.pdf}} }
diff --git a/test/issue14/conf.py b/test/issue14/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue14/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue14/contents.rst b/test/issue14/contents.rst
new file mode 100644
index 0000000..8ec72f2
--- /dev/null
+++ b/test/issue14/contents.rst
@@ -0,0 +1,7 @@
+Contents
+========
+
+.. toctree::
+
+   doc1
+   doc2
diff --git a/test/issue14/doc1.rst b/test/issue14/doc1.rst
new file mode 100644
index 0000000..84b39d7
--- /dev/null
+++ b/test/issue14/doc1.rst
@@ -0,0 +1,6 @@
+Doc1
+====
+
+.. bibliography:: test1.bib
+   :style: plain
+   :all:
diff --git a/test/issue14/doc2.rst b/test/issue14/doc2.rst
new file mode 100644
index 0000000..33edfbc
--- /dev/null
+++ b/test/issue14/doc2.rst
@@ -0,0 +1,6 @@
+Doc2
+====
+
+.. bibliography:: test2.bib
+   :style: plain
+   :all:
diff --git a/test/issue14/test1.bib b/test/issue14/test1.bib
new file mode 100644
index 0000000..729a0f5
--- /dev/null
+++ b/test/issue14/test1.bib
@@ -0,0 +1,4 @@
+ at Misc{Test,
+  author =    {Mr. Test},
+  title =     {Test},
+}
diff --git a/test/issue14/test2.bib b/test/issue14/test2.bib
new file mode 100644
index 0000000..5517b78
--- /dev/null
+++ b/test/issue14/test2.bib
@@ -0,0 +1,4 @@
+ at Misc{Test2,
+  author =    {Mr. Other Test},
+  title =     {Another Test},
+}
diff --git a/test/issue14_2/conf.py b/test/issue14_2/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue14_2/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue14_2/contents.rst b/test/issue14_2/contents.rst
new file mode 100644
index 0000000..8ec72f2
--- /dev/null
+++ b/test/issue14_2/contents.rst
@@ -0,0 +1,7 @@
+Contents
+========
+
+.. toctree::
+
+   doc1
+   doc2
diff --git a/test/issue14_2/doc1.rst b/test/issue14_2/doc1.rst
new file mode 100644
index 0000000..3bb0de7
--- /dev/null
+++ b/test/issue14_2/doc1.rst
@@ -0,0 +1,7 @@
+Doc1
+====
+
+.. bibliography:: test1.bib
+   :all:
+   :style: plain
+   :labelprefix: A
diff --git a/test/issue14_2/doc2.rst b/test/issue14_2/doc2.rst
new file mode 100644
index 0000000..f3547f4
--- /dev/null
+++ b/test/issue14_2/doc2.rst
@@ -0,0 +1,7 @@
+Doc2
+====
+
+.. bibliography:: test2.bib
+   :all:
+   :style: plain
+   :labelprefix: B
diff --git a/test/issue14_2/test1.bib b/test/issue14_2/test1.bib
new file mode 100644
index 0000000..729a0f5
--- /dev/null
+++ b/test/issue14_2/test1.bib
@@ -0,0 +1,4 @@
+ at Misc{Test,
+  author =    {Mr. Test},
+  title =     {Test},
+}
diff --git a/test/issue14_2/test2.bib b/test/issue14_2/test2.bib
new file mode 100644
index 0000000..5517b78
--- /dev/null
+++ b/test/issue14_2/test2.bib
@@ -0,0 +1,4 @@
+ at Misc{Test2,
+  author =    {Mr. Other Test},
+  title =     {Another Test},
+}
diff --git a/test/issue15/conf.py b/test/issue15/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue15/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue15/contents.rst b/test/issue15/contents.rst
new file mode 100644
index 0000000..c7427b8
--- /dev/null
+++ b/test/issue15/contents.rst
@@ -0,0 +1,5 @@
+:cite:`first`
+:cite:`second`
+
+.. bibliography:: test.bib
+   :style: unsrt
diff --git a/test/issue15/test.bib b/test/issue15/test.bib
new file mode 100644
index 0000000..fba6fec
--- /dev/null
+++ b/test/issue15/test.bib
@@ -0,0 +1,8 @@
+ at Misc{second,
+  author =    {B. Second},
+  title =     {Test 2},
+}
+ at Misc{first,
+  author =    {A. First},
+  title =     {Test 1},
+}
diff --git a/test/issue17/conf.py b/test/issue17/conf.py
new file mode 100644
index 0000000..8a1f142
--- /dev/null
+++ b/test/issue17/conf.py
@@ -0,0 +1,11 @@
+import sys
+import os
+# viewcode extension specifically needed for this test
+extensions = [
+    'sphinxcontrib.bibtex',
+    'sphinx.ext.viewcode',
+    'sphinx.ext.autodoc']
+# make sure we find the module
+sys.path.insert(0, os.path.abspath('.'))
+
+exclude_patterns = ['_build']
diff --git a/test/issue17/contents.rst b/test/issue17/contents.rst
new file mode 100644
index 0000000..e670b9a
--- /dev/null
+++ b/test/issue17/contents.rst
@@ -0,0 +1,2 @@
+.. automodule:: somemodule
+   :members:
diff --git a/test/issue17/somemodule.py b/test/issue17/somemodule.py
new file mode 100644
index 0000000..a221873
--- /dev/null
+++ b/test/issue17/somemodule.py
@@ -0,0 +1,6 @@
+"""Some module."""
+
+
+def somefunction():
+    """Some function."""
+    pass
diff --git a/test/issue2/adoc1.rst b/test/issue2/adoc1.rst
new file mode 100644
index 0000000..881a7a8
--- /dev/null
+++ b/test/issue2/adoc1.rst
@@ -0,0 +1,4 @@
+Doc1
+====
+
+:cite:`Test`
diff --git a/test/issue2/adoc2.rst b/test/issue2/adoc2.rst
new file mode 100644
index 0000000..5cf4a8d
--- /dev/null
+++ b/test/issue2/adoc2.rst
@@ -0,0 +1,4 @@
+Doc2
+====
+
+[Test]_
diff --git a/test/issue2/conf.py b/test/issue2/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue2/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue2/contents.rst b/test/issue2/contents.rst
new file mode 100644
index 0000000..7bc4158
--- /dev/null
+++ b/test/issue2/contents.rst
@@ -0,0 +1,10 @@
+Contents
+========
+
+.. toctree::
+
+   adoc1
+   adoc2
+
+.. bibliography:: test.bib
+   :style: plain
diff --git a/test/issue2/test.bib b/test/issue2/test.bib
new file mode 100644
index 0000000..729a0f5
--- /dev/null
+++ b/test/issue2/test.bib
@@ -0,0 +1,4 @@
+ at Misc{Test,
+  author =    {Mr. Test},
+  title =     {Test},
+}
diff --git a/test/issue4/conf.py b/test/issue4/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue4/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue4/contents.rst b/test/issue4/contents.rst
new file mode 100644
index 0000000..bdceca8
--- /dev/null
+++ b/test/issue4/contents.rst
@@ -0,0 +1,3 @@
+.. bibliography:: test.bib
+   :all:
+   :encoding: latex+utf
diff --git a/test/issue4/test.bib b/test/issue4/test.bib
new file mode 100644
index 0000000..ccd6cd4
--- /dev/null
+++ b/test/issue4/test.bib
@@ -0,0 +1,4 @@
+ at Misc{Test,
+  author =    {Mr. T\'est☺},
+  title =     {Test},
+}
diff --git a/test/issue61/conf.py b/test/issue61/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue61/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue61/contents.rst b/test/issue61/contents.rst
new file mode 100644
index 0000000..1afc37a
--- /dev/null
+++ b/test/issue61/contents.rst
@@ -0,0 +1,6 @@
+Contents
+========
+
+:cite:`testone,testtwo`
+
+.. bibliography:: refs.bib
diff --git a/test/issue61/refs.bib b/test/issue61/refs.bib
new file mode 100644
index 0000000..a04e473
--- /dev/null
+++ b/test/issue61/refs.bib
@@ -0,0 +1,9 @@
+ at Misc{testone,
+  author =    {Mr. TestOne},
+  title =     {TestOne},
+}
+
+ at Misc{testtwo,
+  author =    {Mr. TestTwo},
+  title =     {TestTwo},
+}
diff --git a/test/issue62/conf.py b/test/issue62/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue62/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue62/contents.rst b/test/issue62/contents.rst
new file mode 100644
index 0000000..9b02c4b
--- /dev/null
+++ b/test/issue62/contents.rst
@@ -0,0 +1,9 @@
+Contents
+========
+
+.. toctree::
+
+   doc1
+   doc2
+   summary
+
diff --git a/test/issue62/doc1.rst b/test/issue62/doc1.rst
new file mode 100644
index 0000000..5e7fc44
--- /dev/null
+++ b/test/issue62/doc1.rst
@@ -0,0 +1,56 @@
+2014-Feb-20
+###########
+
+JACS paper
+**********
+
+:cite:`fuhrmans_molecular_2012`
+
+
+Abstract
+========
+
+We present molecular dynamics simulations investigating the effect of
+a particular fusion peptide, the **influenza hemagglutinin fusion
+peptide** and some of its mutants, on the lipid phase diagram.
+
+We detect a systematic shift toward phases with more positive mean
+curvature in the presence of the peptides, as well as an occurrence of
+bicontinuous cubic phases, which indicates a stabilization of Gaussian
+curvature.
+
+To study the ability of the HA fusion peptide to modulate the lipid
+phase diagram, we focus on DOPE (dioleoylphosphatidylethanolamine) and
+DOPC (dioleoylphosphatidylcholine) lipids. These lipids were chosen as
+they display a broad range of phases, ranging from predominantly
+lamellar states for pure DOPC to inverted-hexagonal for pure DOPE, as
+well as the so-called rhombohedral phase ("stalk" phase) observed for
+mixed PC/PE systems at low hydration. The inverted phases and stalk
+phase.
+
+To construct the phase diagram, we performed self-assembly simulations
+of systems composed of 256 lipids and four peptides, corresponding to
+a mole fraction of peptides of almost 2%. The ratio of PC/PE,
+hydration level, and temperature were systematically varied. At each
+state point, multiple simulations were performed starting from a
+randomized initial distribution of the components. Each simulation was
+run for an effective time of 12 μs, which proved to be long enough for
+the system to adopt a stable phase.
+
+
+Calorimetry experiments:
+
+* :cite:`blume_apparent_1983`    
+* :cite:`grabitz_relaxation_2002`
+
+Atomistic Monte-Carlo experiments:
+
+* :cite:`wustner_atomistic_2014`
+
+
+Bibliography
+************
+
+.. bibliography:: refs.bib
+   :labelprefix: A
+   :filter: docname in docnames
diff --git a/test/issue62/doc2.rst b/test/issue62/doc2.rst
new file mode 100644
index 0000000..88dce56
--- /dev/null
+++ b/test/issue62/doc2.rst
@@ -0,0 +1,46 @@
+2014-Mar-08
+###########
+
+
+How to test an ensemble
+***********************
+
+These are notes on :cite:`shirts_simple_2013`.
+
+
+Abstract
+========
+
+It is often difficult to quantitatively determine if a new molecular
+simulation algorithm or software properly implements sampling of the
+desired thermodynamic ensemble.
+
+We present some simple statistical analysis procedures to allow
+sensitive determination of whether the desired thermodynamic ensemble
+is properly sampled.
+
+These procedures use paired simulations to cancel out system dependent
+densities of state and directly test the extent to which the Boltzmann
+distribution associated with the ensemble (usually canonical,
+isobaric−isothermal, or grand canonical) is satisfied.
+
+
+Introduction
+============
+
+Molecular simulations, including both molecular dynamics (MD) and
+Monte Carlo (MC) techniques, are powerful tools used to study the
+properties of complex molecular systems.
+
+When used to specifically study thermodynamics of such systems, rather
+than dynamics, the primary goal of molecular simulation is to generate
+uncorrelated samples from the appropriate ensemble as efficiently as
+possible.
+
+
+Bibliography
+============
+
+.. bibliography:: refs.bib
+   :labelprefix: B
+   :filter: docname in docnames
diff --git a/test/issue62/refs.bib b/test/issue62/refs.bib
new file mode 100644
index 0000000..30cd9a2
--- /dev/null
+++ b/test/issue62/refs.bib
@@ -0,0 +1,128 @@
+ at article{grabitz_relaxation_2002,
+	title = {Relaxation kinetics of lipid membranes and its relation to the heat capacity.},
+	volume = {82},
+	number = {1},
+	journal = {Biophysical Journal},
+	author = {Grabitz, Peter and Ivanova, Vesselka P and Heimburg, Thomas},
+	month = jan,
+	year = {2002},
+	pages = {299--309}
+}
+
+ at article{blume_apparent_1983,
+	title = {Apparent molar heat capacities of phospholipids in aqueous dispersion. Effects of chain length and head group structure},
+	volume = {22},
+	doi = {10.1021/bi00292a027},
+	number = {23},
+	journal = {Biochemistry},
+	author = {Blume, Alfred},
+	month = nov,
+	year = {1983},
+	pages = {5436--5442}
+}
+
+ at article{wustner_atomistic_2014,
+	title = {Atomistic Monte Carlo Simulation of Lipid Membranes},
+	volume = {15},
+	copyright = {http://creativecommons.org/licenses/by/3.0/},
+	doi = {10.3390/ijms15021767},
+	number = {2},
+	journal = {International Journal of Molecular Sciences},
+	author = {Wüstner, Daniel and Sklenar, Heinz},
+	month = jan,
+	year = {2014},
+	pages = {1767--1803}
+}
+
+ at article{fuhrmans_molecular_2012,
+	title = {Molecular View of the Role of Fusion Peptides in Promoting Positive Membrane Curvature},
+	volume = {134},
+	doi = {10.1021/ja207290b},
+	number = {3},
+	journal = {Journal of the American Chemical Society},
+	author = {Fuhrmans, Marc and Marrink, Siewert J.},
+	month = jan,
+	year = {2012},
+	pages = {1543--1552}
+}
+
+ at article{shirts_simple_2013,
+	title = {Simple Quantitative Tests to Validate Sampling from Thermodynamic Ensembles},
+	volume = {9},
+	doi = {10.1021/ct300688p},
+	number = {2},
+	journal = {Journal of Chemical Theory and Computation},
+	author = {Shirts, Michael R.},
+	month = feb,
+	year = {2013},
+	pages = {909--926}
+}
+
+ at article{mcmahon_membrane_2010,
+	title = {Membrane Curvature in Synaptic Vesicle Fusion and Beyond},
+	volume = {140},
+	doi = {10.1016/j.cell.2010.02.017},
+	number = {5},
+	journal = {Cell},
+	author = {{McMahon}, Harvey T. and Kozlov, Michael M. and Martens, Sascha},
+	month = mar,
+	year = {2010},
+	pages = {601--605}
+}
+
+ at article{hu_gaussian_2013,
+	title = {Gaussian curvature elasticity determined from global shape transformations and local stress distributions: a comparative study using the {MARTINI} model},
+	volume = {161},
+	journal = {Faraday discussions},
+	author = {Hu, Mingyang and de Jong, Djurre H and Marrink, Siewert J and Deserno, Markus},
+	year = {2013},
+	pages = {365--382}
+}
+
+ at article{baoukina_molecular_2012,
+	title = {Molecular structure of membrane tethers},
+	volume = {102},
+	doi = {10.1016/j.bpj.2012.03.048},
+	number = {8},
+	journal = {Biophysical journal},
+	author = {Baoukina, Svetlana and Marrink, Siewert J and Tieleman, D Peter},
+	month = apr,
+	year = {2012},
+	pages = {1866--1871}
+}
+
+ at article{risselada_curvature-dependent_2011,
+	title = {Curvature-Dependent Elastic Properties of Liquid-Ordered Domains Result in Inverted Domain Sorting on Uniaxially Compressed Vesicles},
+	volume = {106},
+	doi = {10.1103/PhysRevLett.106.148102},
+	number = {14},
+	journal = {Physical Review Letters},
+	author = {Risselada, H. Jelger and Marrink, Siewert Jan and Müller, Marcus},
+	month = apr,
+	year = {2011},
+	pages = {148102}
+}
+
+ at article{risselada_curvature_2009,
+	title = {Curvature effects on lipid packing and dynamics in liposomes revealed by coarse grained molecular dynamics simulations},
+	volume = {11},
+	doi = {10.1039/b818782g},
+	number = {12},
+	journal = {Physical chemistry chemical physics: {PCCP}},
+	author = {Risselada, H Jelger and Marrink, Siewert J},
+	month = mar,
+	year = {2009},
+	pages = {2056--2067}
+}
+
+ at article{marrink_mechanism_2003,
+	title = {The Mechanism of Vesicle Fusion as Revealed by Molecular Dynamics Simulations},
+	volume = {125},
+	doi = {10.1021/ja036138+},
+	number = {37},
+	journal = {Journal of the American Chemical Society},
+	author = {Marrink, Siewert J. and Mark, Alan E.},
+	month = sep,
+	year = {2003},
+	pages = {11144--11145}
+}
diff --git a/test/issue62/summary.rst b/test/issue62/summary.rst
new file mode 100644
index 0000000..d1a224b
--- /dev/null
+++ b/test/issue62/summary.rst
@@ -0,0 +1,47 @@
+Summary
+#######
+
+Постановка задачи
+*****************
+
+:cite:`mcmahon_membrane_2010`: Рис. 1, C, D, E, F.
+
+
+Утверждение
+***********
+
+Выпуклость/вогнутось в центре круга белков с положительной кривизной —
+это локальный минимум энергии.
+
+
+
+Метод
+*****
+
+Крупно-зернистая молекулярная динамика для симуляции большой
+мембраны. Martini используется для упругих расчётов
+:cite:`hu_gaussian_2013`,
+:cite:`fuhrmans_molecular_2012`,
+:cite:`risselada_curvature-dependent_2011`,
+:cite:`risselada_curvature_2009`,
+:cite:`marrink_mechanism_2003`.
+
+
+Аргумент
+********
+
+
+
+
+Проверка ансамбля
+*****************
+
+Не сделано.
+
+
+Библиография
+************
+
+.. bibliography:: refs.bib
+   :labelprefix: C
+   :filter: docname in docnames and key != "fuhrmans_molecular_2012"
diff --git a/test/issue77/conf.py b/test/issue77/conf.py
new file mode 100644
index 0000000..22ad95d
--- /dev/null
+++ b/test/issue77/conf.py
@@ -0,0 +1,21 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
+
+# create and register pybtex plugins
+
+from pybtex.style.formatting.unsrt import Style as UnsrtStyle
+from pybtex.style.labels.alpha import LabelStyle as AlphaLabelStyle
+from pybtex.plugin import register_plugin
+
+
+class ApaLabelStyle(AlphaLabelStyle):
+    def format_label(self, entry):
+        return "APA"
+
+
+class ApaStyle(UnsrtStyle):
+    default_label_style = 'apa'
+
+
+register_plugin('pybtex.style.labels', 'apa', ApaLabelStyle)
+register_plugin('pybtex.style.formatting', 'apastyle', ApaStyle)
diff --git a/test/issue77/contents.rst b/test/issue77/contents.rst
new file mode 100644
index 0000000..ed3cf21
--- /dev/null
+++ b/test/issue77/contents.rst
@@ -0,0 +1,5 @@
+:cite:`2009:mandel`
+:cite:`2003:evensen`
+
+.. bibliography:: test.bib
+   :style: apastyle
diff --git a/test/issue77/test.bib b/test/issue77/test.bib
new file mode 100644
index 0000000..f77e079
--- /dev/null
+++ b/test/issue77/test.bib
@@ -0,0 +1,27 @@
+ at Misc{2009:mandel,
+author = {Jan Mandel},
+title = {A Brief Tutorial on the Ensemble {K}alman Filter},
+howpublished = {arXiv:0901.3725v1 [physics.ao-ph]},
+month =     jan,
+year =      {2009},
+OPTnote =      {},
+OPTannote =    {},
+archivePrefix = {arXiv},
+eprint        = {0901.3725},
+primaryClass  = {physics.ao-ph}
+}
+
+ at Article{2003:evensen,
+  author =       {Geir Evensen},
+  title =        {The Ensemble {K}alman Filter: theoretical formulation and practical implementation},
+  journal =      {Ocean Dynamics},
+  year =         {2003},
+  OPTkey =       {},
+  volume =    {53},
+  number =    {4},
+  pages =     {343--367},
+  OPTmonth =     {},
+  OPTnote =      {},
+  OPTannote =    {},
+  doi = {10.1007/s10236-003-0036-9}
+}
diff --git a/test/issue80/conf.py b/test/issue80/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/issue80/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/issue80/contents.rst b/test/issue80/contents.rst
new file mode 100644
index 0000000..cd46d34
--- /dev/null
+++ b/test/issue80/contents.rst
@@ -0,0 +1,15 @@
+Contents
+========
+
+.. toctree::
+
+   doc0
+   doc1
+   doc2
+   doc3
+   doc4
+   doc5
+   doc6
+   doc7
+   doc8
+   doc9
diff --git a/test/issue80/doc0.rst b/test/issue80/doc0.rst
new file mode 100644
index 0000000..9926c87
--- /dev/null
+++ b/test/issue80/doc0.rst
@@ -0,0 +1,2 @@
+doc0
+----
diff --git a/test/issue80/doc1.rst b/test/issue80/doc1.rst
new file mode 100644
index 0000000..0da9d50
--- /dev/null
+++ b/test/issue80/doc1.rst
@@ -0,0 +1,4 @@
+doc1
+----
+
+:cite:`1979-shafer`
diff --git a/test/issue80/doc2.rst b/test/issue80/doc2.rst
new file mode 100644
index 0000000..0cad0c1
--- /dev/null
+++ b/test/issue80/doc2.rst
@@ -0,0 +1,4 @@
+doc2
+----
+
+:cite:`1977-morris`
diff --git a/test/issue80/doc3.rst b/test/issue80/doc3.rst
new file mode 100644
index 0000000..99b8560
--- /dev/null
+++ b/test/issue80/doc3.rst
@@ -0,0 +1,4 @@
+doc3
+----
+
+:cite:`1972-savage`
diff --git a/test/issue80/doc4.rst b/test/issue80/doc4.rst
new file mode 100644
index 0000000..d37145f
--- /dev/null
+++ b/test/issue80/doc4.rst
@@ -0,0 +1,4 @@
+doc4
+----
+
+:cite:`rockafellar-1970`
diff --git a/test/issue80/doc5.rst b/test/issue80/doc5.rst
new file mode 100644
index 0000000..baa9ca2
--- /dev/null
+++ b/test/issue80/doc5.rst
@@ -0,0 +1,4 @@
+doc5
+----
+
+:cite:`1966-arrow`
diff --git a/test/issue80/doc6.rst b/test/issue80/doc6.rst
new file mode 100644
index 0000000..200ee96
--- /dev/null
+++ b/test/issue80/doc6.rst
@@ -0,0 +1,4 @@
+doc6
+----
+
+:cite:`1934-hildebrandt`
diff --git a/test/issue80/doc7.rst b/test/issue80/doc7.rst
new file mode 100644
index 0000000..d5a019a
--- /dev/null
+++ b/test/issue80/doc7.rst
@@ -0,0 +1,4 @@
+doc7
+----
+
+:cite:`1986-genest-zidek-combining-probability-distributions`
diff --git a/test/issue80/doc8.rst b/test/issue80/doc8.rst
new file mode 100644
index 0000000..ec7fff0
--- /dev/null
+++ b/test/issue80/doc8.rst
@@ -0,0 +1,4 @@
+doc8
+----
+
+:cite:`2001-kennedy-calibration`
diff --git a/test/issue80/doc9.rst b/test/issue80/doc9.rst
new file mode 100644
index 0000000..37e7f24
--- /dev/null
+++ b/test/issue80/doc9.rst
@@ -0,0 +1,4 @@
+doc9
+----
+
+.. bibliography:: refs.bib
diff --git a/test/issue80/refs.bib b/test/issue80/refs.bib
new file mode 100644
index 0000000..251e7a1
--- /dev/null
+++ b/test/issue80/refs.bib
@@ -0,0 +1,85 @@
+ at article{1979-shafer,
+  author = {Glenn Shafer},
+  title = {Allocations of Probability},
+  journal = {The Annals of Probability},
+  year = {1979},
+  volume = {7},
+  number = {5},
+  pages = {827--839}
+}
+
+ at article{1977-morris,
+  author = {Peter A. Morris},
+  title = {Combining expert judgments: a {B}ayesian approach},
+  journal = {Management Science},
+  year = {1977},
+  volume = {23},
+  number = {7},
+  pages = {679--693}
+}
+
+ at book{1972-savage,
+  author = {Leonard J. Savage},
+  title = {The Foundations of Statistics},
+  publisher = {Dover},
+  year = {1972},
+  address = {New York}
+}
+
+ at book{rockafellar-1970,
+  author = {R. Tyrrell Rockafellar},
+  title = {Convex Analysis},
+  publisher = {Princeton University Press},
+  year = {1970},
+  address = {Princeton}
+}
+
+ at article{1966-arrow,
+  author = {Arrow, K.},
+  title = {Exposition of the theory of choice under uncertainty},
+  journal = {Synthese},
+  year = {1966},
+  volume = {16},
+  number = {3--4},
+  pages = {253--269}
+}
+
+ at article{1951-ville,
+  author = {Jean Ville and P. K. Newman},
+  title = {The Existence-Conditions of a Total Utility Function },
+  journal = {The Review of Economic Studies},
+  year = {1951},
+  volume = {19},
+  number = {2},
+  pages = {123--128}
+}
+
+ at article{1934-hildebrandt,
+  author = {T. H. Hildebrandt},
+  title = {On Bounded Functional Operations},
+  journal = {Transactions of the American Mathematical Society},
+  year = {1934},
+  volume = {36},
+  number = {4},
+  pages = {868--875}
+}
+
+ at article{1986-genest-zidek-combining-probability-distributions,
+  author = {Christian Genest and James V. Zidek},
+  title = {Combining Probability Distributions: A Critique and an Annotated Bibliography},
+  journal = {Statistical Science},
+  year = {1986},
+  volume = {1},
+  number = {1},
+  pages = {114--148}
+}
+
+ at article{2001-kennedy-calibration,
+  author = {Marc C. Kennedy and Anthony O'Hagan},
+  title = {Bayesian Calibration of Computer Models},
+  journal = {Journal of the Royal Statistical Society, Series B},
+  year = {2001},
+  volume = {63},
+  number = {3},
+  pages = {425--464}
+}
diff --git a/test/latex_refs/conf.py b/test/latex_refs/conf.py
new file mode 100644
index 0000000..95dbf72
--- /dev/null
+++ b/test/latex_refs/conf.py
@@ -0,0 +1,7 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
+latex_documents = [
+    ('contents', 'test.tex',
+     u'Test',
+     u'Mr. Test', 'manual'),
+]
diff --git a/test/latex_refs/contents.rst b/test/latex_refs/contents.rst
new file mode 100644
index 0000000..7fa6ac6
--- /dev/null
+++ b/test/latex_refs/contents.rst
@@ -0,0 +1,7 @@
+Test
+====
+
+:cite:`1657:huygens`
+
+.. bibliography:: test.bib
+   :all:
diff --git a/test/latex_refs/test.bib b/test/latex_refs/test.bib
new file mode 100644
index 0000000..2bcab4a
--- /dev/null
+++ b/test/latex_refs/test.bib
@@ -0,0 +1,10 @@
+ at InCollection{1657:huygens,
+  author = 	 {Christiaan Huygens},
+  title = 	 {De Ratiociniis in Ludo Ale{\ae}},
+  booktitle = 	 {Exercitationum Mathematicarum Libri Quinque: Quibus accedit {C}hristiani {H}ugenii Tractatus de Ratiociniis in Ale{\ae} Ludo},
+  pages = 	 {517--524},
+  publisher = {Ex officina Johannis Elsevirii},
+  year = 	 {1657},
+  editor = 	 {Schooten, Franciscus {\'a}},
+  address = 	 {Lugd. Batav.},
+}
diff --git a/test/list_bullet/conf.py b/test/list_bullet/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/list_bullet/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/list_bullet/contents.rst b/test/list_bullet/contents.rst
new file mode 100644
index 0000000..43d4669
--- /dev/null
+++ b/test/list_bullet/contents.rst
@@ -0,0 +1,3 @@
+.. bibliography:: test.bib
+   :list: bullet
+   :all:
diff --git a/test/list_bullet/test.bib b/test/list_bullet/test.bib
new file mode 100644
index 0000000..e404f01
--- /dev/null
+++ b/test/list_bullet/test.bib
@@ -0,0 +1,16 @@
+ at Misc{test1,
+  author =    {Mr. Test Akkerdju},
+  title =     {Test 1},
+}
+ at Misc{test2,
+  author =    {Mr. Test Bro},
+  title =     {Test 2},
+}
+ at Misc{test3,
+  author =    {Mr. Test Chap},
+  title =     {Test 1},
+}
+ at Misc{test4,
+  author =    {Mr. Test Dude},
+  title =     {Test 4},
+}
diff --git a/test/list_citation/conf.py b/test/list_citation/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/list_citation/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/list_citation/contents.rst b/test/list_citation/contents.rst
new file mode 100644
index 0000000..4360507
--- /dev/null
+++ b/test/list_citation/contents.rst
@@ -0,0 +1,4 @@
+.. bibliography:: test.bib
+   :style: plain
+   :list: citation
+   :all:
diff --git a/test/list_citation/test.bib b/test/list_citation/test.bib
new file mode 100644
index 0000000..e404f01
--- /dev/null
+++ b/test/list_citation/test.bib
@@ -0,0 +1,16 @@
+ at Misc{test1,
+  author =    {Mr. Test Akkerdju},
+  title =     {Test 1},
+}
+ at Misc{test2,
+  author =    {Mr. Test Bro},
+  title =     {Test 2},
+}
+ at Misc{test3,
+  author =    {Mr. Test Chap},
+  title =     {Test 1},
+}
+ at Misc{test4,
+  author =    {Mr. Test Dude},
+  title =     {Test 4},
+}
diff --git a/test/list_enumerated/conf.py b/test/list_enumerated/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/list_enumerated/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/list_enumerated/contents.rst b/test/list_enumerated/contents.rst
new file mode 100644
index 0000000..604fa2f
--- /dev/null
+++ b/test/list_enumerated/contents.rst
@@ -0,0 +1,14 @@
+.. bibliography:: test.bib
+   :list: enumerated
+   :all:
+
+.. bibliography:: test2.bib
+   :list: enumerated
+   :start: continue
+   :all:
+
+.. bibliography:: test3.bib
+   :list: enumerated
+   :start: 23
+   :all:
+
diff --git a/test/list_enumerated/test.bib b/test/list_enumerated/test.bib
new file mode 100644
index 0000000..e404f01
--- /dev/null
+++ b/test/list_enumerated/test.bib
@@ -0,0 +1,16 @@
+ at Misc{test1,
+  author =    {Mr. Test Akkerdju},
+  title =     {Test 1},
+}
+ at Misc{test2,
+  author =    {Mr. Test Bro},
+  title =     {Test 2},
+}
+ at Misc{test3,
+  author =    {Mr. Test Chap},
+  title =     {Test 1},
+}
+ at Misc{test4,
+  author =    {Mr. Test Dude},
+  title =     {Test 4},
+}
diff --git a/test/list_enumerated/test2.bib b/test/list_enumerated/test2.bib
new file mode 100644
index 0000000..216f76b
--- /dev/null
+++ b/test/list_enumerated/test2.bib
@@ -0,0 +1,16 @@
+ at Misc{test5,
+  author =    {Mr. Test Eminence},
+  title =     {Test 5},
+}
+ at Misc{test6,
+  author =    {Mr. Test Frater},
+  title =     {Test 6},
+}
+ at Misc{test7,
+  author =    {Mr. Test Giggles},
+  title =     {Test 7},
+}
+ at Misc{test8,
+  author =    {Mr. Test Handy},
+  title =     {Test 8},
+}
diff --git a/test/list_enumerated/test3.bib b/test/list_enumerated/test3.bib
new file mode 100644
index 0000000..2d8ed38
--- /dev/null
+++ b/test/list_enumerated/test3.bib
@@ -0,0 +1,16 @@
+ at Misc{test9,
+  author =    {Mr. Test Iedereen},
+  title =     {Test 9},
+}
+ at Misc{test10,
+  author =    {Mr. Test Joke},
+  title =     {Test 10},
+}
+ at Misc{test11,
+  author =    {Mr. Test Klopgeest},
+  title =     {Test 11},
+}
+ at Misc{test12,
+  author =    {Mr. Test Laterfanter},
+  title =     {Test 12},
+}
diff --git a/test/list_invalid/conf.py b/test/list_invalid/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/list_invalid/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/list_invalid/contents.rst b/test/list_invalid/contents.rst
new file mode 100644
index 0000000..ba36d67
--- /dev/null
+++ b/test/list_invalid/contents.rst
@@ -0,0 +1,2 @@
+.. bibliography:: test.bib
+   :list: thisisintentionallyinvalid
diff --git a/test/list_invalid/test.bib b/test/list_invalid/test.bib
new file mode 100644
index 0000000..e69de29
diff --git a/test/path.py b/test/path.py
new file mode 100644
index 0000000..0b947e3
--- /dev/null
+++ b/test/path.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+# coding: utf-8
+"""
+    path
+    ~~~~
+
+    :copyright: Copyright 2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+import os
+import sys
+import shutil
+from codecs import open
+from six.moves import map
+
+
+FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding()
+
+
+class path(str):
+
+    """
+    Represents a path which behaves like a string.
+    """
+    if sys.version_info < (3, 0):
+        def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'):
+            if isinstance(s, unicode):
+                s = s.encode(encoding, errors=errors)
+                return str.__new__(cls, s)
+            return str.__new__(cls, s)
+
+    @property
+    def parent(self):
+        """
+        The name of the directory the file or directory is in.
+        """
+        return self.__class__(os.path.dirname(self))
+
+    def abspath(self):
+        """
+        Returns the absolute path.
+        """
+        return self.__class__(os.path.abspath(self))
+
+    def isabs(self):
+        """
+        Returns ``True`` if the path is absolute.
+        """
+        return os.path.isabs(self)
+
+    def isdir(self):
+        """
+        Returns ``True`` if the path is a directory.
+        """
+        return os.path.isdir(self)
+
+    def isfile(self):
+        """
+        Returns ``True`` if the path is a file.
+        """
+        return os.path.isfile(self)
+
+    def islink(self):
+        """
+        Returns ``True`` if the path is a symbolic link.
+        """
+        return os.path.islink(self)
+
+    def ismount(self):
+        """
+        Returns ``True`` if the path is a mount point.
+        """
+        return os.path.ismount(self)
+
+    def rmtree(self, ignore_errors=False, onerror=None):
+        """
+        Removes the file or directory and any files or directories it may
+        contain.
+
+        :param ignore_errors:
+            If ``True`` errors are silently ignored, otherwise an exception
+            is raised in case an error occurs.
+
+        :param onerror:
+            A callback which gets called with the arguments `func`, `path` and
+            `exc_info`. `func` is one of :func:`os.listdir`, :func:`os.remove`
+            or :func:`os.rmdir`. `path` is the argument to the function which
+            caused it to fail and `exc_info` is a tuple as returned by
+            :func:`sys.exc_info`.
+        """
+        shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror)
+
+    def copytree(self, destination, symlinks=False):
+        """
+        Recursively copy a directory to the given `destination`. If the given
+        `destination` does not exist it will be created.
+
+        :param symlinks:
+            If ``True`` symbolic links in the source tree result in symbolic
+            links in the destination tree otherwise the contents of the files
+            pointed to by the symbolic links are copied.
+        """
+        shutil.copytree(self, destination, symlinks=symlinks)
+
+    def movetree(self, destination):
+        """
+        Recursively move the file or directory to the given `destination`
+        similar to the  Unix "mv" command.
+
+        If the `destination` is a file it may be overwritten depending on the
+        :func:`os.rename` semantics.
+        """
+        shutil.move(self, destination)
+
+    move = movetree
+
+    def unlink(self):
+        """
+        Removes a file.
+        """
+        os.unlink(self)
+
+    def write_text(self, text, **kwargs):
+        """
+        Writes the given `text` to the file.
+        """
+        f = open(self, 'w', **kwargs)
+        try:
+            f.write(text)
+        finally:
+            f.close()
+
+    def text(self, **kwargs):
+        """
+        Returns the text in the file.
+        """
+        f = open(self, mode='U', **kwargs)
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def bytes(self):
+        """
+        Returns the bytes in the file.
+        """
+        f = open(self, mode='rb')
+        try:
+            return f.read()
+        finally:
+            f.close()
+
+    def write_bytes(self, bytes, append=False):
+        """
+        Writes the given `bytes` to the file.
+
+        :param append:
+            If ``True`` given `bytes` are added at the end of the file.
+        """
+        if append:
+            mode = 'ab'
+        else:
+            mode = 'wb'
+        f = open(self, mode=mode)
+        try:
+            f.write(bytes)
+        finally:
+            f.close()
+
+    def exists(self):
+        """
+        Returns ``True`` if the path exist.
+        """
+        return os.path.exists(self)
+
+    def lexists(self):
+        """
+        Returns ``True`` if the path exists unless it is a broken symbolic
+        link.
+        """
+        return os.path.lexists(self)
+
+    def makedirs(self, mode=0o777):
+        """
+        Recursively create directories.
+        """
+        os.makedirs(self, mode)
+
+    def joinpath(self, *args):
+        """
+        Joins the path with the argument given and returns the result.
+        """
+        return self.__class__(os.path.join(self, *map(self.__class__, args)))
+
+    __div__ = __truediv__ = joinpath
+
+    def __repr__(self):
+        return '%s(%s)' % (self.__class__.__name__, str.__repr__(self))
diff --git a/test/sphinx/Makefile b/test/sphinx/Makefile
new file mode 100644
index 0000000..9c6eac1
--- /dev/null
+++ b/test/sphinx/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Sphinxbibtexextensiontest.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Sphinxbibtexextensiontest.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/Sphinxbibtexextensiontest"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Sphinxbibtexextensiontest"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	make -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/test/sphinx/conf.py b/test/sphinx/conf.py
new file mode 100644
index 0000000..1a3d301
--- /dev/null
+++ b/test/sphinx/conf.py
@@ -0,0 +1,2 @@
+extensions = ['sphinxcontrib.bibtex']
+exclude_patterns = ['_build']
diff --git a/test/sphinx/contents.rst b/test/sphinx/contents.rst
new file mode 100644
index 0000000..f3cd998
--- /dev/null
+++ b/test/sphinx/contents.rst
@@ -0,0 +1,25 @@
+.. Sphinx bibtex extension test documentation master file, created by
+   sphinx-quickstart on Mon Mar 21 14:37:33 2011.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to Sphinx bibtex extension test's documentation!
+========================================================
+
+Citation :cite:`1996:fukuda` :cite:`dreze:2000` to other document.
+Regular citation test [Test01]_ to other document.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   zbibliography
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/test/sphinx/make.bat b/test/sphinx/make.bat
new file mode 100644
index 0000000..a94891a
--- /dev/null
+++ b/test/sphinx/make.bat
@@ -0,0 +1,170 @@
+ at ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Sphinxbibtexextensiontest.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Sphinxbibtexextensiontest.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end
diff --git a/test/sphinx/subfolder/test.bib b/test/sphinx/subfolder/test.bib
new file mode 100644
index 0000000..baaf61e
--- /dev/null
+++ b/test/sphinx/subfolder/test.bib
@@ -0,0 +1,12 @@
+ at TechReport{dreze:2000,
+  author={Dr{\'e}ze, Jacques H. and Rustichini, Aldo},
+  title={State-dependent utility and decision theory},
+  year=2000,
+  month=feb,
+  institution={Universit{\'e} catholique de Louvain, Center for Operations Research and Econometrics (CORE)},
+  type={CORE Discussion Papers},
+  url={http://ideas.repec.org/p/cor/louvco/2000007.html},
+  number={2000007},
+  OPTabstract={},
+  OPTkeywords={}
+}
diff --git a/test/sphinx/test.bib b/test/sphinx/test.bib
new file mode 100644
index 0000000..628e66c
--- /dev/null
+++ b/test/sphinx/test.bib
@@ -0,0 +1,275 @@
+ at InCollection{1657:huygens,
+  author = 	 {Christiaan Huygens},
+  title = 	 {De Ratiociniis in Ludo Ale{\ae}},
+  booktitle = 	 {Exercitationum Mathematicarum Libri Quinque: Quibus accedit {C}hristiani {H}ugenii Tractatus de Ratiociniis in Ale{\ae} Ludo},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {517--524},
+  publisher = {Ex officina Johannis Elsevirii},
+  year = 	 {1657},
+  editor = 	 {Schooten, Franciscus {\'a}},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTchapter = 	 {},
+  address = 	 {Lugd. Batav.},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+ at Book{joyce:1999,
+  author = 	 {Joyce, James},
+  ALTeditor = 	 {},
+  title = 		 {The Foundations of Causal Decision Theory},
+  publisher = 	 {Cambridge University Press},
+  year = 		 {1999},
+  OPTkey = 		 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+ at Unpublished{2011:troffaes:isipta:natext,
+  author =       {Matthias C. M. Troffaes and Robert Hable},
+  title =        {Robustness of Natural Extension},
+  OPTcrossref =  {},
+  OPTkey =       {},
+  OPTbooktitle = {},
+  OPTpages =     {},
+  year =      {2011},
+  OPTeditor =    {},
+  OPTvolume =    {},
+  OPTnumber =    {},
+  OPTseries =    {},
+  OPTaddress =   {},
+  OPTmonth =     {},
+  OPTorganization = {},
+  OPTpublisher = {},
+  note =      {Submitted to ISIPTA'11},
+  OPTannote =    {}
+}
+
+%@Proceedings{2010:coolen:oberguggenberger:troffaes::jrr,
+%  title =        {Proceedings of the Institution of Mechanical Engineers, Part O: Journal of Risk and Reliability},
+%  year =         {2010},
+%  OPTkey =       {},
+%  OPTbooktitle = {},
+%  editor =    {Frank P. A. Coolen and Michael Oberguggenberger and Matthias C. M. Troffaes},
+%  volume =    {224},
+%  number =    {4},
+%  OPTseries =    {},
+%  OPTaddress =   {},
+%  OPTmonth =     {},
+%  OPTorganization = {},
+%  OPTpublisher = {},
+%  note =      {Special Issue on Uncertainty in Engineering and Risk Reliability},
+%  OPTannote =    {}
+%}
+
+ at Article{1996:fukuda,
+  author =       {K. Fukuda and A. Prodon},
+  title =        {Double description method revisited},
+  journal =      {Combinatorics and Computer Science},
+  year =         {1996},
+  OPTkey =       {},
+  volume =    {1120},
+  OPTnumber =    {},
+  pages =     {91--111},
+  OPTmonth =     {},
+  OPTnote =      {},
+  OPTannote =    {},
+  note={\url{http://www.ifor.math.ethz.ch/~fukuda/cdd_home/}}
+}
+
+ at Misc{2009:defra:animal:health,
+  author =       {Defra},
+  title =        {Impact assessment of an independent body for animal health in {E}ngland},
+  year =         {2009},
+  note =      {\url{http://www.defra.gov.uk/corporate/consult/newindependent-body-ah/impact-assessment.pdf}},
+}
+
+ at Misc{test:url,
+  OPTkey =       {},
+  author =    {Mr. Test},
+  title =     {Testing the url command in references},
+  OPThowpublished = {},
+  OPTmonth =     {},
+  OPTyear =      {},
+  note =      {\url{http://www.google.com} and \url{http://www.yahoo.com}},
+  OPTannote =    {}
+}
+
+ at MASTERSTHESIS{2000:troffaes:msthesis,
+  AUTHOR = {Matthias C. M. Troffaes},
+  TITLE = {Quantum algorithmes: theoretische aspecten en toepassingen},
+  SCHOOL = {Universiteit Gent},
+  YEAR = {2000},
+  OPTKEY = {},
+  OPTTYPE = {},
+  OPTADDRESS = {Gent},
+  MONTH = {May},
+  OPTNOTE = {},
+  OPTANNOTE = {}
+}
+
+ at PhdThesis{2008:hable:thesis,
+  author =       {Robert Hable},
+  title =        {Data-Based Decisions under Complex Uncertainty},
+  school =       {Ludwig-Maximilians-Universit{\"a}t M{\"u}nchen},
+  year =         {2008},
+  OPTkey =       {},
+  OPTtype =      {},
+  OPTaddress =   {},
+  OPTmonth =     {},
+  OPTnote =      {},
+  OPTannote =    {}
+}
+
+ at BOOKLET{Sherwood,
+author="D.A. Sherwood",
+title="Phosphorus Loads Entering Long Pond, A Small Embayment of Lake {O}ntario near {R}ochester, {N}ew {Y}ork",
+howpublished="USGS Fact Sheet 128-99",
+pages=4,
+month="November",
+year=1999,
+}
+
+ at InProceedings{2005:cormack,
+  author = 	 {Cormack, G. V. and Lynam, T. R.},
+  title = 	 {Spam Corpus Creation for TREC},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {Proceedings of the Second Conference on Email and Anti-Spam},
+  OPTpages = 	 {},
+  year = 	 {2005},
+  OPTeditor = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Palo Alto},
+  month = 	 {Jul},
+  OPTorganization = {},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+ at MANUAL{RSI,
+author="RSI",
+title="ENVI User's Guide",
+publisher="Reasearch Systems Incorporated",
+organization="Research Systems Incorporated",
+howpublished="PDF File",
+address="Boulder, CO",
+month="September",
+year=2001,
+}
+
+ at InBook{Kristensen83,
+  author = 	 {B. B. Kristensen and Ole L. Madsen and B. M{\o}ller-Pedersen and K. Nygaard},
+  editor = 	 {P. Degano and E. Sandewall},   
+  title = 	 {Integrated Interactive Computing Systems},
+  chapter = 	 {Syntax-directed program modularization},
+  publisher = 	 {North-Holland, Amsterdam},
+  year = 	 {1983},
+  pages = 	 {207-219}
+}
+
+ at InCollection{2004:seidenfeld::rubinesque,
+  author = 	 {J. B. Kadane and Mark J. Schervish and Teddy Seidenfeld},
+  title = 	 {A {R}ubinesque theory of decision},
+  booktitle = 	 {A festschrift for {H}erman {R}ubin},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {45--55},
+  publisher = {Inst. Math. Statist.},
+  year = 	 {2004},
+  OPTeditor = 	 {},
+  volume = 	 {45},
+  OPTnumber = 	 {},
+  series = 	 {IMS Lecture Notes -- Monograph Series},
+  OPTtype = 	 {},
+  OPTchapter = 	 {},
+  address = 	 {Beachwood, Ohio},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+%%% taken from Jason K. Moore's thesis; it is a good complex long entry for testing
+ at ARTICLE{Astrom2005,
+  author = {{\AA}str{\"o}m, Karl J. and Klein, Richard E. and Lennartsson, Anders},
+  title = {Bicycle Dynamics and Control},
+  journal = {IEEE Control Systems Magazine},
+  year = {2005},
+  volume = {25},
+  pages = {26--47},
+  number = {4},
+  month = {August},
+  abstract = {This article analyzes the dynamics of bicycles from the perspective
+	of control. Models of different complexity are presented, starting
+	with simple ones and ending with more realistic models generated
+	from multibody software. We consider models that capture essential
+	behavior such as self-stabilization as well as models that demonstrate
+	difficulties with rear wheel steering. We relate our experiences
+	using bicycles in control education along with suggestions for fun
+	and thought-provoking experiments with proven student attraction.
+	Finally, we describe bicycles and clinical programs designed for
+	children with disabilities.},
+  bib = {bibtex-keys#Astrom2005},
+  bibpr = {private-bibtex-keys#Astrom2005},
+  doi = {10.1109/MCS.2005.1499389},
+  file = {Astrom2005.pdf:Astrom2005.pdf:PDF},
+  keywords = {bicycles, control engineering computing, control engineering education,design,
+	handicapped aids, nonlinear control systems, nonlinear dynamicalsystems,
+	position control, stability bicycle control, bicycle dynamics, clinical
+	programs, computer simulation, control education, disabled children,
+	dynamic behavior, inverted pendulum, modelling, multibody software,
+	nonminimum phase steering behavior, rear wheel steering difficulties,
+	self-stabilization},
+  owner = {moorepants},
+  review = {Shows a steer torque measurement system constructed for the UCSB instrumented
+	bicycle but with little extra information. They use a linear force
+	transducer of some sort mounted on the handlebars.
+	
+	
+	They first show the point mass model like Karnopp's 2004 model (older
+	ones are referenced in Meijaard2007). They stablize the steer angel
+	to roll angle transfer function with a negative feedback gain which
+	has dependence on the forward velocity.
+	
+	
+	He adds a basic model of the front fork geometry to the point mass
+	model, giving a relationship between steer torque input and steer
+	angle which is speed dependent. The roll angle to steer angle now
+	has a builtin negative feedback law due to the front fork geometry
+	and if the k2 gain is large enough (with steer torque = 0) the system
+	is stable. He uses this to calculat a critical velocity for stability.
+	
+	
+	Klein says you should grip the handlebars lightly to take advantage
+	of the bicycle self stability. This corresponds to the differences
+	in the Whipple model and one with arms.
+	
+	
+	Cites Wier1972 as giving 0.1s and 0.3s of nueromuscular delay in steer
+	torque and upper body lean, respectively.
+	
+	
+	The gyroscopic effects give rise to derivative feedback.
+	
+	
+	Claims that riders use variation in forward speed as an additional
+	control variable.},
+  timestamp = {2008.10.16},
+  webpdf = {references-folder/Astrom2005.pdf}
+}
diff --git a/test/sphinx/test2.bib b/test/sphinx/test2.bib
new file mode 100644
index 0000000..aed4e0f
--- /dev/null
+++ b/test/sphinx/test2.bib
@@ -0,0 +1,53 @@
+ at ARTICLE{1979:shafer,
+  AUTHOR = {Glenn Shafer},
+  TITLE = {Allocations of Probability},
+  JOURNAL = {The Annals of Probability},
+  YEAR = {1979},
+  OPTKEY = {},
+  VOLUME = {7},
+  NUMBER = {5},
+  PAGES = {827--839},
+  MONTH = OCT,
+  OPTNOTE = {},
+  OPTANNOTE = {}
+}
+
+ at ARTICLE{1977:morris,
+  AUTHOR = {Peter A. Morris},
+  TITLE = {Combining expert judgments: a {B}ayesian approach},
+  JOURNAL = {Management Science},
+  YEAR = {1977},
+  OPTKEY = {},
+  VOLUME = {23},
+  NUMBER = {7},
+  PAGES = {679--693},
+  MONTH = {March},
+  OPTNOTE = {},
+  OPTANNOTE = {}
+}
+
+ at BOOK{1972:savage,
+  AUTHOR = {Leonard J. Savage},
+  ALTEDITOR = {},
+  TITLE = {The Foundations of Statistics},
+  PUBLISHER = {Dover},
+  YEAR = {1972},
+  OPTKEY = {},
+  OPTVOLUME = {},
+  OPTNUMBER = {},
+  OPTSERIES = {},
+  ADDRESS = {New York},
+  OPTEDITION = {},
+  OPTMONTH = {},
+  NOTE = {Second revised edition},
+  OPTANNOTE = {}
+}
+
+ at BOOK{rockafellar:1970,
+  AUTHOR = {R. Tyrrell Rockafellar},
+  ALTEDITOR = {},
+  TITLE = {Convex Analysis},
+  PUBLISHER = {Princeton University Press},
+  YEAR = {1970},
+  ADDRESS = {Princeton}
+}
diff --git a/test/sphinx/zbibliography.rst b/test/sphinx/zbibliography.rst
new file mode 100644
index 0000000..7cb9e88
--- /dev/null
+++ b/test/sphinx/zbibliography.rst
@@ -0,0 +1,59 @@
+Testing the bibliography directive
+==================================
+
+Text
+----
+
+Huyghens :cite:`1657:huygens` wrote one of the first books on
+probability theory.
+
+Mix with a footnote [#note]_ and a regular citation [Test01]_.
+
+Another citation :cite:`dreze:2000`.
+
+Another reference to footnotes [#note]_ and [#note2]_.
+More regular citations [Test01]_ and [Test02]_.
+
+Extra reference to a footnote [#footnote-walley2004]_.
+
+Extra reference to a citation [Wa04]_.
+
+Another few citations: :cite:`rockafellar:1970,1972:savage`.
+
+More citations: 
+
+.. rubric:: References
+
+.. bibliography:: test.bib subfolder/test.bib
+   :all:
+   :labelprefix: A
+
+.. rubric:: References (Cited Test)
+
+.. bibliography:: test2.bib
+   :cited:
+   :labelprefix: B
+
+.. rubric:: References (Not Cited Test)
+
+.. bibliography:: test2.bib
+   :notcited:
+   :labelprefix: C
+
+.. rubric:: Footnotes
+
+.. [#note] A footnote.
+.. [#note2] Another footnote.
+.. [#footnote-walley2004]
+
+    Peter Walley, Renato Pelessoni, and Paolo Vicig. Journal of
+    Statistical Planning and Inference, 126(1):119-151, November 2004.
+
+.. rubric:: Citations
+
+.. [Test01] A regular citation.
+.. [Test02] Another regular citation.
+.. [Wa04]
+
+    Peter Walley, Renato Pelessoni, and Paolo Vicig. Journal of
+    Statistical Planning and Inference, 126(1):119-151, November 2004.
diff --git a/test/test_bibfile_out_of_date.py b/test/test_bibfile_out_of_date.py
new file mode 100644
index 0000000..01f1fb7
--- /dev/null
+++ b/test/test_bibfile_out_of_date.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+"""
+    test_bibfile_out_of_date
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test that updates to the bibfile generate the correct result when
+    Sphinx is run again.
+"""
+
+import os.path
+import shutil
+import re
+import time
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('bibfile_out_of_date').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+    os.remove(srcdir / 'test.bib')
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_encoding(app):
+    shutil.copyfile(
+        os.path.join(srcdir, 'test_old.bib'),
+        os.path.join(srcdir, 'test.bib'))
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<p id="bibtex-bibliography-contents-0">'
+            '.*<tr><td class="label">\\[1\\]</td><td>.*Akkerdju.*</td></tr>'
+            '.*<tr><td class="label">\\[2\\]</td><td>.*Bro.*</td></tr>'
+            '.*<tr><td class="label">\\[3\\]</td><td>.*Chap.*</td></tr>'
+            '.*<tr><td class="label">\\[4\\]</td><td>.*Dude.*</td></tr>'
+            '.*</p>',
+            stream.read(), re.MULTILINE | re.DOTALL)
+    # wait to ensure different timestamp
+    time.sleep(0.1)
+    shutil.copyfile(
+        os.path.join(srcdir, 'test_new.bib'),
+        os.path.join(srcdir, 'test.bib'))
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<p id="bibtex-bibliography-contents-0">'
+            '.*<tr><td class="label">\\[1\\]</td><td>.*Eminence.*</td></tr>'
+            '.*<tr><td class="label">\\[2\\]</td><td>.*Frater.*</td></tr>'
+            '.*<tr><td class="label">\\[3\\]</td><td>.*Giggles.*</td></tr>'
+            '.*<tr><td class="label">\\[4\\]</td><td>.*Handy.*</td></tr>'
+            '.*</p>',
+            stream.read(), re.MULTILINE | re.DOTALL)
diff --git a/test/test_bibfilenotfound.py b/test/test_bibfilenotfound.py
new file mode 100644
index 0000000..05d977f
--- /dev/null
+++ b/test/test_bibfilenotfound.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_bibfilenotfound
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Bib file not found check.
+"""
+
+import re
+from six import StringIO
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('bibfilenotfound').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_bibfilenotfound(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search('could not open bibtex file .*unknown[.]bib', warnings)
diff --git a/test/test_citationnotfound.py b/test/test_citationnotfound.py
new file mode 100644
index 0000000..58b81ed
--- /dev/null
+++ b/test/test_citationnotfound.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_citationnotfound
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Citation not found check.
+"""
+
+import re
+from six import StringIO
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('citationnotfound').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_citationnotfound(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search('citation not found: nosuchkey', warnings)
diff --git a/test/test_custom_style.py b/test/test_custom_style.py
new file mode 100644
index 0000000..2876940
--- /dev/null
+++ b/test/test_custom_style.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+    test_custom_style
+    ~~~~~~~~~~~~~~~~~
+
+    Test a custom style.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('custom_style').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_custom_style(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        output = stream.read()
+        # the custom style suppresses web links
+        assert not re.search('http://arxiv.org', output)
+        assert not re.search('http://dx.doi.org', output)
diff --git a/test/test_filter.py b/test/test_filter.py
new file mode 100644
index 0000000..7350bca
--- /dev/null
+++ b/test/test_filter.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""
+    test_filter
+    ~~~~~~~~~~~
+
+    Test filter option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('filter').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_filter(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        output = stream.read()
+        assert re.search('Tralalala', output)
+        assert not re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "or.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert re.search('ideetje', output)
+        assert re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "noteq.html")) as stream:
+        output = stream.read()
+        assert re.search('Tralalala', output)
+        assert re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "lt.html")) as stream:
+        output = stream.read()
+        assert re.search('Tralalala', output)
+        assert not re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "lte.html")) as stream:
+        output = stream.read()
+        assert re.search('Tralalala', output)
+        assert not re.search('ideetje', output)
+        assert re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "gt.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "gte.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert re.search('ideetje', output)
+        assert re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "key.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "false.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert not re.search('ideetje', output)
+        assert not re.search('Jakkamakka', output)
+    with open(os.path.join(app.outdir, "title.html")) as stream:
+        output = stream.read()
+        assert not re.search('Tralalala', output)
+        assert not re.search('ideetje', output)
+        assert re.search('Jakkamakka', output)
diff --git a/test/test_filter_fix_author_keyerror.py b/test/test_filter_fix_author_keyerror.py
new file mode 100644
index 0000000..9063276
--- /dev/null
+++ b/test/test_filter_fix_author_keyerror.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+"""
+    test_filter_fix_author_keyerror
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test for a bug in the filter option.
+"""
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('filter_fix_author_keyerror').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_filter_fix_author_keyerror(app):
+    app.builder.build_all()
diff --git a/test/test_filter_option_clash.py b/test/test_filter_option_clash.py
new file mode 100644
index 0000000..55921dd
--- /dev/null
+++ b/test/test_filter_option_clash.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+    test_filter_option_clash
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test filter option clash with all, cited, and notcited.
+"""
+
+from six import StringIO
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('filter_option_clash').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_filter_option_clash(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search(':filter: overrides :all:', warnings)
+    assert re.search(':filter: overrides :cited:', warnings)
+    assert re.search(':filter: overrides :notcited:', warnings)
diff --git a/test/test_filter_syntax_error.py b/test/test_filter_syntax_error.py
new file mode 100644
index 0000000..0c640ce
--- /dev/null
+++ b/test/test_filter_syntax_error.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+    test_filter_syntax_error
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test response on syntax errors in filter.
+"""
+
+import nose.tools
+from six import StringIO
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('filter_syntax_error').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_filter_syntax_error(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    nose.tools.assert_equal(
+        len(re.findall('syntax error in :filter: expression', warnings)), 9)
diff --git a/test/test_invalid_cite_option.py b/test/test_invalid_cite_option.py
new file mode 100644
index 0000000..536f0d9
--- /dev/null
+++ b/test/test_invalid_cite_option.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_invalid_cite_option
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Test behaviour when invalid cite option is given.
+"""
+
+import re
+from six import StringIO
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('invalid_cite_option').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_invalid_cite_option(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search('unknown option: "thisisintentionallyinvalid"', warnings)
diff --git a/test/test_issue1.py b/test/test_issue1.py
new file mode 100644
index 0000000..c0fe51a
--- /dev/null
+++ b/test/test_issue1.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue1
+    ~~~~~~~~~~~
+
+    Test Tinkerer and check output.
+"""
+
+import nose.tools
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue1').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_tinker(app):
+    app.builder.build_all()
+    nose.tools.assert_equal(
+        app.env.bibtex_cache.get_cited_docnames(u"2011:BabikerIPv6"),
+        {u"2012/07/24/hello_world_"})
+    nose.tools.assert_equal(
+        app.env.bibtex_cache.get_label_from_key(u"2011:BabikerIPv6"), u"BNC11")
diff --git a/test/test_issue14.py b/test/test_issue14.py
new file mode 100644
index 0000000..1dbf440
--- /dev/null
+++ b/test/test_issue14.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue14
+    ~~~~~~~~~~~~
+
+    Test duplicate label issue.
+"""
+
+from six import StringIO
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue14').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_duplicate_label(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search(
+        'duplicate label for keys (Test and Test2)|(Test2 and Test)',
+        warnings)
+    with open(os.path.join(app.outdir, "doc1.html")) as stream:
+        assert re.search('<td class="label">\\[1\\]</td>', stream.read())
+    with open(os.path.join(app.outdir, "doc2.html")) as stream:
+        assert re.search('<td class="label">\\[1\\]</td>', stream.read())
diff --git a/test/test_issue14_2.py b/test/test_issue14_2.py
new file mode 100644
index 0000000..8d1eb40
--- /dev/null
+++ b/test/test_issue14_2.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue14_2
+    ~~~~~~~~~~~~~~
+
+    Test labelprefix option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue14_2').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_label_prefix(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "doc1.html")) as stream:
+        assert re.search('<td class="label">\\[A1\\]</td>', stream.read())
+    with open(os.path.join(app.outdir, "doc2.html")) as stream:
+        assert re.search('<td class="label">\\[B1\\]</td>', stream.read())
diff --git a/test/test_issue15.py b/test/test_issue15.py
new file mode 100644
index 0000000..6f80832
--- /dev/null
+++ b/test/test_issue15.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue15
+    ~~~~~~~~~~~~
+
+    Test order of bibliography entries when using an unsorted style.
+"""
+
+from six import StringIO
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue15').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_duplicate_label(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<tr>.*Test 1.*</tr>.*<tr>.*Test 2.*</tr>',
+            stream.read(), re.DOTALL)
diff --git a/test/test_issue17.py b/test/test_issue17.py
new file mode 100644
index 0000000..9a64cd7
--- /dev/null
+++ b/test/test_issue17.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue17
+    ~~~~~~~~~~~~
+
+    Test that sphinx [source] links do not generate a warning.
+"""
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue17').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_sphinx_source_no_warning(app):
+    app.builder.build_all()
diff --git a/test/test_issue2.py b/test/test_issue2.py
new file mode 100644
index 0000000..675bb3a
--- /dev/null
+++ b/test/test_issue2.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue2
+    ~~~~~~~~~~~
+
+    Test mixing of ``:cite:`` and ``[]_``.
+"""
+
+import nose.tools
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue2').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_mixing_citation_styles(app):
+    app.builder.build_all()
+    nose.tools.assert_equal(
+        app.env.bibtex_cache.get_cited_docnames(u"Test"), {u"adoc1"})
+    nose.tools.assert_equal(
+        app.env.bibtex_cache.get_label_from_key(u"Test"), u"1")
diff --git a/test/test_issue4.py b/test/test_issue4.py
new file mode 100644
index 0000000..60cf279
--- /dev/null
+++ b/test/test_issue4.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue4
+    ~~~~~~~~~~~
+
+    Test the ``:encoding:`` option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue4').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_encoding(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search("Tést☺", stream.read())
diff --git a/test/test_issue61.py b/test/test_issue61.py
new file mode 100644
index 0000000..1e57313
--- /dev/null
+++ b/test/test_issue61.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue61
+    ~~~~~~~~~~~~
+
+    Test multiple keys in a single cite.
+"""
+
+import os
+import re
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue61').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_multiple_keys(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        code = stream.read()
+        assert re.search('class="reference internal" href="#testone"', code)
+        assert re.search('class="reference internal" href="#testtwo"', code)
diff --git a/test/test_issue62.py b/test/test_issue62.py
new file mode 100644
index 0000000..897f30f
--- /dev/null
+++ b/test/test_issue62.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+"""
+    test_issue62
+    ~~~~~~~~~~~~
+
+    Test local bibliographies.
+"""
+
+import os
+import re
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue62').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+def extract_references(code):
+    return frozenset(re.findall(
+        '<a class="reference internal" href="([^"]+)"', code))
+
+
+def extract_citations(code):
+    return frozenset(re.findall(
+        '<table class="docutils citation" frame="void" id="([^"]+)"', code))
+
+
+def check_code(code, refs, cites, otherrefs, othercites):
+    code_refs = extract_references(code)
+    code_cites = extract_citations(code)
+    # use <= here because refs contains all internal references, not
+    # just citation references
+    assert refs <= code_refs
+    assert cites == code_cites
+    assert not(otherrefs & code_refs)
+    assert not(othercites & code_cites)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_local_bibliographies(app):
+    doc1_refs = frozenset([
+        '#wustner-atomistic-2014',
+        '#fuhrmans-molecular-2012',
+        '#blume-apparent-1983',
+        '#grabitz-relaxation-2002',
+        ])
+    doc1_cites = frozenset([
+        'blume-apparent-1983',
+        'wustner-atomistic-2014',
+        'fuhrmans-molecular-2012',
+        'grabitz-relaxation-2002'
+        ])
+    doc2_refs = frozenset([
+        '#shirts-simple-2013'
+        ])
+    doc2_cites = frozenset([
+        'shirts-simple-2013'
+        ])
+    sum_refs = frozenset([
+        "#mcmahon-membrane-2010",
+        "#hu-gaussian-2013",
+        "doc1.html#fuhrmans-molecular-2012",
+        "#risselada-curvature-dependent-2011",
+        "#risselada-curvature-2009",
+        "#marrink-mechanism-2003",
+        ])
+    sum_cites = frozenset([
+        'hu-gaussian-2013',
+        'marrink-mechanism-2003',
+        'risselada-curvature-2009',
+        'risselada-curvature-dependent-2011',
+        'mcmahon-membrane-2010',
+        ])
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "doc1.html")) as stream:
+        check_code(stream.read(), doc1_refs, doc1_cites,
+                   doc2_refs | sum_refs, doc2_cites | sum_cites)
+    with open(os.path.join(app.outdir, "doc2.html")) as stream:
+        check_code(stream.read(), doc2_refs, doc2_cites,
+                   doc1_refs | sum_refs, doc1_cites | sum_cites)
+    with open(os.path.join(app.outdir, "summary.html")) as stream:
+        check_code(stream.read(), sum_refs, sum_cites,
+                   doc1_refs | doc2_refs, doc1_cites | doc2_cites)
diff --git a/test/test_issue77.py b/test/test_issue77.py
new file mode 100644
index 0000000..ff86f87
--- /dev/null
+++ b/test/test_issue77.py
@@ -0,0 +1,26 @@
+"""
+    test_issue77
+    ~~~~~~~~~~~~
+
+    Test label style.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue77').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_issue77(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        output = stream.read()
+        assert len(re.findall('\\[APAa\\]', output)) == 2
+        assert len(re.findall('\\[APAb\\]', output)) == 2
diff --git a/test/test_issue80_parallel.py b/test/test_issue80_parallel.py
new file mode 100644
index 0000000..db368cd
--- /dev/null
+++ b/test/test_issue80_parallel.py
@@ -0,0 +1,27 @@
+"""
+    test_issue80
+    ~~~~~~~~~~~~
+
+    Test parallel build.
+"""
+
+import re
+from six import StringIO
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue80').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile, parallel=8)
+def test_issue80_parallel(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search(
+        'the sphinxcontrib.bibtex extension is not safe for parallel '
+        'reading, doing serial read', warnings)
diff --git a/test/test_issue80_serial.py b/test/test_issue80_serial.py
new file mode 100644
index 0000000..ad8aec0
--- /dev/null
+++ b/test/test_issue80_serial.py
@@ -0,0 +1,19 @@
+"""
+    test_issue80
+    ~~~~~~~~~~~~
+
+    Test parallel build.
+"""
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('issue80').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True, parallel=0)
+def test_issue80_serial(app):
+    app.builder.build_all()
diff --git a/test/test_latex_refs.py b/test/test_latex_refs.py
new file mode 100644
index 0000000..0c322e9
--- /dev/null
+++ b/test/test_latex_refs.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+"""
+    test_latex_refs
+    ~~~~~~~~~~~~~~~
+
+    Check that LaTeX backend produces correct references.
+"""
+
+import os
+import re
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('latex_refs').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True, buildername='latex')
+def test_latex_refs(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "test.tex")) as stream:
+        code = stream.read()
+        assert re.search('\\hyperref\[contents:huygens\]', code)
+        assert re.search('\\label{contents:huygens}', code)
diff --git a/test/test_list_bullet.py b/test/test_list_bullet.py
new file mode 100644
index 0000000..5747409
--- /dev/null
+++ b/test/test_list_bullet.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+"""
+    test_list_bullet
+    ~~~~~~~~~~~~~~~~
+
+    Test the ``:list: bullet`` option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('list_bullet').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_list_bullet(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<ul .* id="bibtex-bibliography-contents-0">'
+            '.*<li>.*Akkerdju.*</li>'
+            '.*<li>.*Bro.*</li>'
+            '.*<li>.*Chap.*</li>'
+            '.*<li>.*Dude.*</li>'
+            '.*</ul>',
+            stream.read(), re.MULTILINE | re.DOTALL)
diff --git a/test/test_list_citation.py b/test/test_list_citation.py
new file mode 100644
index 0000000..3cf89fe
--- /dev/null
+++ b/test/test_list_citation.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+"""
+    test_list_citation
+    ~~~~~~~~~~~~~~~~~~
+
+    Test the ``:list: citation`` option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('list_citation').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_list_citation(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<p id="bibtex-bibliography-contents-0">'
+            '.*<tr><td class="label">\\[1\\]</td><td>.*Akkerdju.*</td></tr>'
+            '.*<tr><td class="label">\\[2\\]</td><td>.*Bro.*</td></tr>'
+            '.*<tr><td class="label">\\[3\\]</td><td>.*Chap.*</td></tr>'
+            '.*<tr><td class="label">\\[4\\]</td><td>.*Dude.*</td></tr>'
+            '.*</p>',
+            stream.read(), re.MULTILINE | re.DOTALL)
diff --git a/test/test_list_enumerated.py b/test/test_list_enumerated.py
new file mode 100644
index 0000000..fa557d2
--- /dev/null
+++ b/test/test_list_enumerated.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+"""
+    test_list_enumerated
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Test the ``:list: enumerated`` option.
+"""
+
+import os.path
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('list_enumerated').abspath()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warningiserror=True)
+def test_list_enumerated(app):
+    app.builder.build_all()
+    with open(os.path.join(app.outdir, "contents.html")) as stream:
+        assert re.search(
+            '<ol .*id="bibtex-bibliography-contents-0".* start="1".*>'
+            '.*<li>.*Akkerdju.*</li>'
+            '.*<li>.*Bro.*</li>'
+            '.*<li>.*Chap.*</li>'
+            '.*<li>.*Dude.*</li>'
+            '.*</ol>'
+            '.*<ol .*id="bibtex-bibliography-contents-1".* start="5".*>'
+            '.*<li>.*Eminence.*</li>'
+            '.*<li>.*Frater.*</li>'
+            '.*<li>.*Giggles.*</li>'
+            '.*<li>.*Handy.*</li>'
+            '.*</ol>'
+            '.*<ol .*id="bibtex-bibliography-contents-2".* start="23".*>'
+            '.*<li>.*Iedereen.*</li>'
+            '.*<li>.*Joke.*</li>'
+            '.*<li>.*Klopgeest.*</li>'
+            '.*<li>.*Laterfanter.*</li>'
+            '.*</ol>',
+            stream.read(), re.MULTILINE | re.DOTALL)
diff --git a/test/test_list_invalid.py b/test/test_list_invalid.py
new file mode 100644
index 0000000..cb63499
--- /dev/null
+++ b/test/test_list_invalid.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+    test_list_invalid
+    ~~~~~~~~~~~~~~~~~
+
+    Test invalid ``:list:`` option.
+"""
+
+from six import StringIO
+import re
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('list_invalid').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_list_invalid(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search(
+        "unknown bibliography list type 'thisisintentionallyinvalid'",
+        warnings)
diff --git a/test/test_sphinx.py b/test/test_sphinx.py
new file mode 100644
index 0000000..1d0ed1c
--- /dev/null
+++ b/test/test_sphinx.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+"""
+    test_sphinx
+    ~~~~~~~~~~~
+
+    General Sphinx test and check output.
+"""
+
+import re
+from six import StringIO
+
+from util import path, with_app
+
+srcdir = path(__file__).parent.joinpath('sphinx').abspath()
+warnfile = StringIO()
+
+
+def teardown_module():
+    (srcdir / '_build').rmtree(True)
+
+
+ at with_app(srcdir=srcdir, warning=warnfile)
+def test_sphinx(app):
+    app.builder.build_all()
+    warnings = warnfile.getvalue()
+    assert re.search(u'could not relabel citation \\[Test01\\]', warnings)
+    assert re.search(u'could not relabel citation \\[Test02\\]', warnings)
+    assert re.search(u'could not relabel citation \\[Wa04\\]', warnings)
+    assert re.search(
+        u'could not relabel citation reference \\[Test01\\]',
+        warnings)
+    assert re.search(
+        u'could not relabel citation reference \\[Test02\\]',
+        warnings)
+    assert re.search(
+        u'could not relabel citation reference \\[Wa04\\]',
+        warnings)
diff --git a/test/util.py b/test/util.py
new file mode 100644
index 0000000..2196d62
--- /dev/null
+++ b/test/util.py
@@ -0,0 +1,251 @@
+# -*- coding: utf-8 -*-
+"""
+    Sphinx test suite utilities
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import sys
+import tempfile
+import shutil
+import re
+from codecs import open
+from six import StringIO
+from six.moves import map
+
+try:
+    from functools import wraps
+except ImportError:
+    # functools is new in 2.4
+    wraps = lambda f: (lambda w: w)
+
+from sphinx import application
+from sphinx.ext.autodoc import AutoDirective
+
+from path import path
+
+from nose import tools, SkipTest
+
+
+__all__ = [
+    'test_root', 'raises', 'raises_msg',
+    'skip_if', 'skip_unless', 'skip_unless_importable', 'Struct',
+    'ListOutput', 'TestApp', 'with_app', 'gen_with_app',
+    'path', 'with_tempdir', 'write_file',
+    'sprint', 'remove_unicode_literals',
+]
+
+
+test_root = path(__file__).parent.joinpath('root').abspath()
+
+
+def _excstr(exc):
+    if isinstance(exc, tuple):
+        return str(tuple(map(_excstr, exc)))
+    return exc.__name__
+
+
+def raises(exc, func, *args, **kwds):
+    """
+    Raise :exc:`AssertionError` if ``func(*args, **kwds)`` does not
+    raise *exc*.
+    """
+    try:
+        func(*args, **kwds)
+    except exc:
+        pass
+    else:
+        raise AssertionError('%s did not raise %s' %
+                             (func.__name__, _excstr(exc)))
+
+
+def raises_msg(exc, msg, func, *args, **kwds):
+    """
+    Raise :exc:`AssertionError` if ``func(*args, **kwds)`` does not
+    raise *exc*, and check if the message contains *msg*.
+    """
+    try:
+        func(*args, **kwds)
+    except exc as err:
+        assert msg in str(err), "\"%s\" not in \"%s\"" % (msg, err)
+    else:
+        raise AssertionError('%s did not raise %s' %
+                             (func.__name__, _excstr(exc)))
+
+
+def skip_if(condition, msg=None):
+    """Decorator to skip test if condition is true."""
+    def deco(test):
+        @tools.make_decorator(test)
+        def skipper(*args, **kwds):
+            if condition:
+                raise SkipTest(msg or 'conditional skip')
+            return test(*args, **kwds)
+        return skipper
+    return deco
+
+
+def skip_unless(condition, msg=None):
+    """Decorator to skip test if condition is false."""
+    return skip_if(not condition, msg)
+
+
+def skip_unless_importable(module, msg=None):
+    """Decorator to skip test if module is not importable."""
+    try:
+        __import__(module)
+    except ImportError:
+        return skip_if(True, msg)
+    else:
+        return skip_if(False, msg)
+
+
+class Struct(object):
+
+    def __init__(self, **kwds):
+        self.__dict__.update(kwds)
+
+
+class ListOutput(object):
+
+    """
+    File-like object that collects written text in a list.
+    """
+
+    def __init__(self, name):
+        self.name = name
+        self.content = []
+
+    def reset(self):
+        del self.content[:]
+
+    def write(self, text):
+        self.content.append(text)
+
+
+class TestApp(application.Sphinx):
+
+    """
+    A subclass of :class:`Sphinx` that runs on the test root, with some
+    better default values for the initialization parameters.
+    """
+
+    def __init__(self, srcdir=None, confdir=None, outdir=None, doctreedir=None,
+                 buildername='html', confoverrides=None,
+                 status=None, warning=None, freshenv=None,
+                 warningiserror=None, tags=None,
+                 confname='conf.py', cleanenv=False, verbosity=0, parallel=0):
+
+        application.CONFIG_FILENAME = confname
+
+        self.cleanup_trees = [test_root / 'generated']
+
+        if srcdir is None:
+            srcdir = test_root
+        if srcdir == '(temp)':
+            tempdir = path(tempfile.mkdtemp())
+            self.cleanup_trees.append(tempdir)
+            temproot = tempdir / 'root'
+            test_root.copytree(temproot)
+            srcdir = temproot
+        else:
+            srcdir = path(srcdir)
+        self.builddir = srcdir.joinpath('_build')
+        if confdir is None:
+            confdir = srcdir
+        if outdir is None:
+            outdir = srcdir.joinpath(self.builddir, buildername)
+            if not outdir.isdir():
+                outdir.makedirs()
+            self.cleanup_trees.insert(0, outdir)
+        if doctreedir is None:
+            doctreedir = srcdir.joinpath(srcdir, self.builddir, 'doctrees')
+            if cleanenv:
+                self.cleanup_trees.insert(0, doctreedir)
+        if confoverrides is None:
+            confoverrides = {}
+        if status is None:
+            status = StringIO()
+        if warning is None:
+            warning = ListOutput('stderr')
+        if freshenv is None:
+            freshenv = False
+        if warningiserror is None:
+            warningiserror = False
+
+        application.Sphinx.__init__(self, srcdir, confdir, outdir, doctreedir,
+                                    buildername, confoverrides, status,
+                                    warning,
+                                    freshenv, warningiserror, tags,
+                                    verbosity, parallel)
+
+    def cleanup(self, doctrees=False):
+        AutoDirective._registry.clear()
+        for tree in self.cleanup_trees:
+            shutil.rmtree(tree, True)
+
+
+def with_app(*args, **kwargs):
+    """
+    Make a TestApp with args and kwargs, pass it to the test and clean up
+    properly.
+    """
+    def generator(func):
+        @wraps(func)
+        def deco(*args2, **kwargs2):
+            app = TestApp(*args, **kwargs)
+            func(app, *args2, **kwargs2)
+            # don't execute cleanup if test failed
+            app.cleanup()
+        return deco
+    return generator
+
+
+def gen_with_app(*args, **kwargs):
+    """
+    Decorate a test generator to pass a TestApp as the first argument to the
+    test generator when it's executed.
+    """
+    def generator(func):
+        @wraps(func)
+        def deco(*args2, **kwargs2):
+            app = TestApp(*args, **kwargs)
+            for item in func(app, *args2, **kwargs2):
+                yield item
+            # don't execute cleanup if test failed
+            app.cleanup()
+        return deco
+    return generator
+
+
+def with_tempdir(func):
+    def new_func(*args, **kwds):
+        tempdir = path(tempfile.mkdtemp())
+        func(tempdir, *args, **kwds)
+        tempdir.rmtree()
+    new_func.__name__ = func.__name__
+    return new_func
+
+
+def write_file(name, contents, encoding=None):
+    if encoding is None:
+        mode = 'wb'
+        if isinstance(contents, unicode):
+            contents = contents.encode('ascii')
+    else:
+        mode = 'w'
+    f = open(str(name), mode, encoding=encoding)
+    f.write(contents)
+    f.close()
+
+
+def sprint(*args):
+    sys.stderr.write(' '.join(map(str, args)) + '\n')
+
+_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
+
+
+def remove_unicode_literals(s):
+    return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/sphinxcontrib-bibtex.git



More information about the debian-med-commit mailing list