Commits

David Jean Louis  committed 62dd61c

Initial import of "doc-and-unittests-refactoring" branch that will be merged on the next release

  • Participants
  • Parent commits 84820a0
  • Branches doc-and-unittests-refactoring

Comments (0)

Files changed (14)

+syntax: glob
+*.egg-info
+*.pyc
+*.*~
+*.orig
+*.old
+.*.swp
+build
+dist
+MANIFEST
+_build
+_static
+.project
+.pydevproject
+.settings
+.DS_Store
+.svn
+.coverage
-.. _readme:
-
+=====
 polib
 =====
 
-Introduction
-------------
-
 polib is a library to manipulate, create, modify gettext files (pot, po and mo
 files). You can load existing files, iterate through it's entries, add, modify
 entries, comments or metadata, etc... or create new po files from scratch.
 polib is pretty stable now and is used by many 
 `opensource projects <http://bitbucket.org/izi/polib/wiki/ProjectsUsingPolib>`_.
 
+The project code and bugtracker is hosted on 
+`Bitbucket <http://bitbucket.org/izi/polib/>`_. 
 
-Installation
-------------
+polib is generously documented, you can `browse the documentation online 
+<http://packages.python.org/polib/>`_, a good start is to read 
+`the quickstart guide  <http://packages.python.org/polib/quickstart.html>`_.
 
-Note: chances are that polib is already packaged for your linux/bsd system, if
-so, we recommend you use your OS package system, if not then choose a method below:
-
-Installing latest polib version with setuptools
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
-$ easy_install polib
-
-Installing latest polib version with pip
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
-$ pip install polib
-
-Installing latest polib version from source tarball
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`Download latest version <http://bitbucket.org/izi/polib/downloads/>`_
-
-::
-
-$ tar xzfv polib-x.y.z.tar.gz
-$ cd polib-x.y.z
-$ python setup build
-$ sudo python setup.py install
-
-Installing the polib development version
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Note: this is **not recommended** in a production environment.
-
-::
-
-$ hg clone http://bitbucket.org/izi/polib/
-$ cd polib
-$ python setup build
-$ sudo python setup.py install
-
-Basic usage example
--------------------
-
-::
-
->>> import polib
->>> # load an existing po file
->>> po = polib.pofile('tests/test_utf8.po')
->>> for entry in po: print entry.msgid, entry.msgstr
->>> # add an entry
->>> entry = polib.POEntry(msgid='Welcome', msgstr='Bienvenue')
->>> entry.occurrences = [('welcome.py', '12'), ('anotherfile.py', '34')]
->>> po.append(entry)
->>> # save our modified po file
->>> po.save()
->>> # compile mo file
->>> po.save_as_mofile('tests/test_utf8.mo')
-
-Documentation
--------------
-
-`A tutorial <http://bitbucket.org/izi/polib/wiki/Tutorial>`_ is available and
-you can also browse the `complete api documentation <http://www.izimobil.org/polib/api/>`_.
-
-Development
------------
-
-Bugtracker, wiki and mercurial repository can be found at the `project's page <http://bitbucket.org/izi/polib/>`_.
-New releases are also published at the `cheeseshop <http://cheeseshop.python.org/pypi/polib/>`_.
-
-
-Credits
--------
-
-**Author:** `David Jean Louis <izimobil@gmail.com>`_.
-
-References
-----------
-
-* `Gettext Manual <http://www.gnu.org/software/gettext/manual/>`_
-* `PO file format <http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html>`_
-* `MO file format <http://www.gnu.org/software/gettext/manual/html_node/gettext_136.html>`_
-
+Thanks for downloading polib !

File docs/Makefile

+# 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/polib.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/polib.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/polib"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/polib"
+	@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."

File docs/api.rst

+.. _api:
+
+polib API
+=========
+
+The ``pofile`` function
+-----------------------
+
+.. autofunction:: polib.pofile
+
+
+The ``mofile`` function
+-----------------------
+
+.. autofunction:: polib.mofile
+
+
+The ``detect_encoding`` function
+--------------------------------
+
+.. autofunction:: polib.detect_encoding
+
+
+The ``escape`` function
+-----------------------
+
+.. autofunction:: polib.escape
+
+
+The ``unescape`` function
+-------------------------
+
+.. autofunction:: polib.unescape
+
+
+The ``POFile`` class
+--------------------
+
+.. autoclass:: polib.POFile
+    :members:
+
+
+The ``MOFile`` class
+--------------------
+
+.. autoclass:: polib.MOFile
+    :members:
+
+
+The ``POEntry`` class
+---------------------
+
+.. autoclass:: polib.POEntry
+    :members:
+
+
+The ``MOEntry`` class
+---------------------
+
+.. autoclass:: polib.MOEntry
+    :members:
+

File docs/conf.py

+# -*- coding: utf-8 -*-
+#
+# polib documentation build configuration file, created by
+# sphinx-quickstart on Sat Jan  1 16:45:49 2011.
+#
+# 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.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('..'))
+
+# -- 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.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'polib'
+copyright = u'2011, David Jean Louis <izimobil@gmail.com>'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.6.0'
+# The full version, including alpha/beta/rc tags.
+release = '0.6.0'
+
+# 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 = 'polibdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'polib.tex', u'polib Documentation',
+   u'David Jean Louis \\textless{}izimobil@gmail.com\\textgreater{}', '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
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_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', 'polib', u'polib Documentation',
+     [u'David Jean Louis <izimobil@gmail.com>'], 1)
+]

File docs/contributing.rst

+.. _installation:
+
+Contributing to polib
+=====================
+
+You are very welcome to contribute to the project!
+The bugtracker, wiki and mercurial repository can be found at the 
+`project's page <http://bitbucket.org/izi/polib/>`_.
+
+New releases are also published at the 
+`cheeseshop <http://cheeseshop.python.org/pypi/polib/>`_.
+
+How to contribute
+~~~~~~~~~~~~~~~~~
+
+There are various possibilities to get involved, for example you can:
+
+* `Report bugs http://www.bitbucket.org/izi/polib/issues/new/>`
+  preferably with patches if you can;
+* Enhance this `documentation
+  http://www.bitbucket.org/izi/polib/src/tip/docs/>`;
+* `Fork the code http://www.bitbucket.org/izi/polib/>`,
+  implement new features, test and send a pull request.
+
+Running the test suite
+~~~~~~~~~~~~~~~~~~~~~~
+
+To run the tests, just type the following on a terminal::
+    $ cd /path/to/polib/
+    $ ./runtests.sh

File docs/index.rst

+.. polib documentation master file
+
+Welcome to polib's documentation!
+=================================
+
+This documentation covers the latest release of polib.
+
+polib is a library to manipulate, create, modify gettext files (pot, po and mo
+files). You can load existing files, iterate through it's entries, add, modify
+entries, comments or metadata, etc. or create new po files from scratch.
+
+polib is pretty stable now and is used by many 
+`opensource projects <http://bitbucket.org/izi/polib/wiki/ProjectsUsingPolib>`_.
+
+polib is completely free and opensource, the license used is `the MIT license
+http://www.opensource.org/licenses/mit-license.php>`.
+It was developed back in 2006 by `David Jean Louis <izimobil@gmail.com>`_
+and it is still actively maintained.
+
+To get up and running quickly, consult the :ref:`quick-start guide
+<quickstart>`, which describes all the necessary steps to install and use
+polib.
+For more detailed information about how to install and how to use polib,
+read through the documentation listed below.
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   quickstart
+   installation
+   api
+   contributing

File docs/installation.rst

+.. _installation:
+
+Installation guide
+==================
+
+Requirements
+------------
+
+polib requires python 2.5 or higher.
+
+
+Installing polib
+----------------
+
+There are several ways to install polib:
+
+* Automatically, via a package manager.
+* Manually, by downloading a copy of the release package and
+  installing it yourself.
+* Manually, by performing a Mercurial checkout of the latest code.
+
+
+Automatic installation via a package manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Several automatic package-installation tools are available for Python;
+the most popular are `pip <http://pip.openplans.org/>`_ and `easy_install
+<http://peak.telecommunity.com/DevCenter/EasyInstall>`_  .
+Either can be used to install polib.
+
+Using ``pip``, type::
+
+    pip install polib
+
+Using ``easy_install``, type::
+
+    easy_install polib
+
+It is also possible that your operating system distributor provides a
+packaged version of polib. Consult your operating system's package list for
+details, but be aware that third-party distributions may be providing older
+versions of polib, and so you should consult the documentation which comes
+with your operating system's package.
+
+
+Manual installation from a downloaded package
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you prefer not to use an automated package installer, you can download a
+copy of polib and install it manually. The latest release package can be
+downloaded from `polib's page on the Python Package Index
+<http://pypi.python.org/pypi/polib/>`_.
+
+Once you've downloaded the package, unpack it, this will create the directory
+``polib-X-Y-Z``, which contains the ``setup.py`` installation script.
+From a command line in that directory, type::
+
+    python setup.py install
+
+.. note::
+    On some systems you may need to execute this with administrative 
+    privileges (e.g., ``sudo python setup.py install``).
+
+
+Manual installation from a Mercurial checkout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you'd like to try out the latest in-development code, you can obtain it
+from the polib repository, which is hosted at
+`Bitbucket <http://bitbucket.org/>`_ and uses `Mercurial
+<http://www.selenic.com/mercurial/wiki/>`_ for version control.
+
+To obtain the latest code and documentation, you'll need to have Mercurial
+installed, at which point you can type::
+
+    hg clone http://bitbucket.org/izi/polib/
+
+This will create a copy of the polib Mercurial repository on your computer;
+you can then add the ``polib.py`` file to your Python import path, or use the
+``setup.py`` script to install as a package.
+

File docs/make.bat

+@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\polib.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\polib.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

File docs/quickstart.rst

+.. _quickstart:
+
+Quick start guide
+=================
+
+Installing polib
+----------------
+
+polib requires python 2.5 or superior.
+
+There are several ways to install polib, this is explained 
+in :ref:`the installation section <installation>`.
+
+For the impatient, the easiest method is to install polib via
+`pip <http://pip.openplans.org/>`_, just type:: 
+
+    pip install polib
+
+
+Some basics about gettext catalogs
+----------------------------------
+
+A gettext catalog is made up of many entries, each entry holding the relation
+between an original untranslated string and its corresponding translation. 
+
+All entries in a given catalog usually pertain to a single project, and all
+translations are expressed in a single target language. One PO file entry has
+the following schematic structure::
+
+    #  translator-comments
+    #. extracted-comments
+    #: reference...
+    #, flag...
+    msgid untranslated-string
+    msgstr translated-string
+
+A simple entry can look like this::
+
+    #: lib/error.c:116
+    msgid "Unknown system error"
+    msgstr "Error desconegut del sistema"
+
+polib has two main entry points for working with gettext catalogs:
+
+* the :func:`~polib.pofile` and :func:`~polib.mofile` functions to **load**
+  existing po or mo files,
+* the :class:`~polib.POFile` and :class:`~polib.MOFile` classes to **create**
+  new po or mo files.
+
+References
+* `Gettext Manual <http://www.gnu.org/software/gettext/manual/>`_
+* `PO file format <http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html>`_
+* `MO file format <http://www.gnu.org/software/gettext/manual/html_node/gettext_136.html>`_
+
+
+Loading existing catalogs
+-------------------------
+
+Loading a catalog and detecting its encoding
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here the encoding of the po file is auto-detected by polib (polib detects it by
+parsing the charset in the header of the pofile)::
+
+    import polib
+    po = polib.pofile('path/to/catalog.po')
+
+
+Loading a catalog and specifying explicitly the encoding
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For some reason you may want to specify the file encoding explicitely (because
+the charset is not specified in the po file header for example), to do so::
+
+    import polib
+    po = polib.pofile(
+        'path/to/catalog.po',
+        autodetect_encoding=False,
+        encoding='iso-8859-15'
+    )
+
+Loading an mo file
+~~~~~~~~~~~~~~~~~~
+
+In some cases you can be forced to load an mo file (because the po file is not
+available for example), polib handles this case::
+
+    import polib
+    mo = polib.mofile('path/to/catalog.mo')
+    print mo
+
+As for po files, mofile also allows to specify the encoding explicitely.
+
+
+Creating po catalogs from scratch
+---------------------------------
+
+polib allows you to create catalog from scratch, this can be done with the
+POFile class, for exemple to create a simple catalog you could do::
+
+    import polib
+
+    po = polib.POFile()
+    po.metadata = {
+        'Project-Id-Version': '1.0',
+        'Report-Msgid-Bugs-To': 'you@example.com',
+        'POT-Creation-Date': '2007-10-18 14:00+0100',
+        'PO-Revision-Date': '2007-10-18 14:00+0100',
+        'Last-Translator': 'you <you@example.com>',
+        'Language-Team': 'English <yourteam@example.com>',
+        'MIME-Version': '1.0',
+        'Content-Type': 'text/plain; charset=utf-8',
+        'Content-Transfer-Encoding': '8bit',
+    }
+
+This snippet creates an empty pofile, with its metadata, and now you can add
+you entries to the po file like this::
+
+    entry = polib.POEntry(
+        msgid=u'Welcome',
+        msgstr=u'Bienvenue',
+        occurrences=[('welcome.py', '12'), ('anotherfile.py', '34')]
+    )
+    po.append(entry)
+
+To save your file to the disk you would just do::
+
+    po.save('/path/to/newfile.po')
+
+And to compile the corresponding mo file::
+
+    po.save_as_mofile('/path/to/newfile.mo')
+
+
+More examples
+-------------
+
+Iterating over entries
+~~~~~~~~~~~~~~~~~~~~~~
+
+Iterating over **all** entries (by default POFiles contains all catalog
+entries, even obsolete and fuzzy entries)::
+
+    import polib
+
+    po = polib.pofile('path/to/catalog.po')
+    for entry in po:
+        print entry.msgid, entry.msgstr
+
+Iterating over **all** entries except obsolete entries::
+
+    import polib
+
+    po = polib.pofile('path/to/catalog.po')
+    valid_entries = [e for e in po if not e.obsolete]
+    for entry in valid_entries:
+        print entry.msgid, entry.msgstr
+
+Iterating over translated entries only::
+
+    import polib
+
+    po = polib.pofile('path/to/catalog.po')
+    for entry in po.translated_entries():
+        print entry.msgid, entry.msgstr
+
+And so on... 
+You could also iterate over the list of POEntry objects returned by the 
+following POFile methods:
+
+* :meth:`~polib.POFile.untranslated_entries`
+* :meth:`~polib.POFile.fuzzy_entries`
+
+
+Getting the percent of translated entries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    import polib
+
+    po = polib.pofile('path/to/catalog.po')
+    print po.percent_translated()
+
+
+Compiling po to mo files and reversing mo files to po files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Compiling a po file::
+
+    import polib
+
+    po = polib.pofile('path/to/catalog.po')
+    # to get the binary representation in a variable:
+    modata = po.to_binary()
+    # or to save the po file as an mo file
+    po.save_as_mofile('path/to/catalog.mo')
+
+
+Reverse a mo file to a po file::
+
+    mo = polib.mofile('path/to/catalog.mo')
+    # to get the unicode representation in a variable, just do:
+    podata = unicode(mo)
+    # or to save the mo file as an po file
+    mo.save_as_pofile('path/to/catalog.po')
+
-#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
 # License: MIT (see LICENSE file provided)
 # vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
 
 """
-**polib** allows you to manipulate, create, modify gettext files (pot, po
-and mo files).  You can load existing files, iterate through it's entries,
-add, modify entries, comments or metadata, etc... or create new po files
-from scratch.
+**polib** allows you to manipulate, create, modify gettext files (pot, po and
+mo files).  You can load existing files, iterate through it's entries, add,
+modify entries, comments or metadata, etc. or create new po files from scratch.
 
-**polib** provides a simple and pythonic API, exporting only three
-convenience functions (*pofile*, *mofile* and *detect_encoding*), and the
-four core classes, *POFile*, *MOFile*, *POEntry* and *MOEntry* for creating
-new files/entries.
-
-**Basic example**:
-
->>> import polib
->>> # load an existing po file
->>> po = polib.pofile('tests/test_utf8.po')
->>> for entry in po:
-...     # do something with entry...
-...     pass
->>> # add an entry
->>> entry = polib.POEntry(msgid='Welcome', msgstr='Bienvenue')
->>> entry.occurrences = [('welcome.py', '12'), ('anotherfile.py', '34')]
->>> po.append(entry)
->>> # to save our modified po file:
->>> # po.save()
->>> # or you may want to compile the po file
->>> # po.save_as_mofile('tests/test_utf8.mo')
+**polib** provides a simple and pythonic API via the :func:`~polib.pofile` and
+:func:`~polib.mofile` convenience functions.
 """
 
-__author__    = 'David JEAN LOUIS <izimobil@gmail.com>'
-__version__   = '0.5.5'
+__author__    = 'David Jean Louis <izimobil@gmail.com>'
+__version__   = '1.0.0-RC1'
 __all__       = ['pofile', 'POFile', 'POEntry', 'mofile', 'MOFile', 'MOEntry',
                  'detect_encoding', 'escape', 'unescape', 'detect_encoding',]
 
 import textwrap
 import types
 
+
+# the default encoding to use when autodetect_encoding is disabled
 default_encoding = 'utf-8'
 
-# function pofile() {{{
+# _pofile_or_mofile {{{
 
-def pofile(pofile, **kwargs):
+def _pofile_or_mofile(f, type, **kwargs):
     """
-    Convenience function that parse the po/pot file *pofile* and return
-    a POFile instance.
+    Internal function used by :func:`polib.pofile` and :func:`polib.mofile` to
+    honor the DRY concept.
+    """
+    if not os.path.exists(f):
+        raise OSError("No such file or directory: '%s'" % f)
 
-    **Keyword arguments**:
-      - *pofile*: string, full or relative path to the po/pot file or its 
-        content to parse
-      - *wrapwidth*: integer, the wrap width, only useful when -w option was
-        passed to xgettext (optional, default to 78)
-      - *autodetect_encoding*: boolean, if set to False the function will
-        not try to detect the po file encoding (optional, default to True)
-      - *encoding*: string, an encoding, only relevant if autodetect_encoding
-        is set to False
-      - *check_for_duplicates*: whether to check for duplicate entries when
-        adding entries to the file, default: False (optional)
-
-    **Example**:
-
-    >>> import polib
-    >>> po = polib.pofile('tests/test_weird_occurrences.po',
-    ...     check_for_duplicates=True)
-    >>> po #doctest: +ELLIPSIS
-    <POFile instance at ...>
-    >>> import os, tempfile
-    >>> all_attrs = ('msgctxt', 'msgid', 'msgstr', 'msgid_plural', 
-    ...              'msgstr_plural', 'obsolete', 'comment', 'tcomment', 
-    ...              'occurrences', 'flags', 'previous_msgctxt', 
-    ...              'previous_msgid', 'previous_msgid_plural')
-    >>> for fname in ['test_iso-8859-15.po', 'test_utf8.po']:
-    ...     orig_po = polib.pofile('tests/'+fname)
-    ...     tmpf = tempfile.NamedTemporaryFile().name
-    ...     orig_po.save(tmpf)
-    ...     try:
-    ...         new_po = polib.pofile(tmpf)
-    ...         for old, new in zip(orig_po, new_po):
-    ...             for attr in all_attrs:
-    ...                 if getattr(old, attr) != getattr(new, attr):
-    ...                     getattr(old, attr)
-    ...                     getattr(new, attr)
-    ...     finally:
-    ...         os.unlink(tmpf)
-    >>> po_file = polib.pofile('tests/test_save_as_mofile.po')
-    >>> tmpf = tempfile.NamedTemporaryFile().name
-    >>> po_file.save_as_mofile(tmpf)
-    >>> try:
-    ...     mo_file = polib.mofile(tmpf)
-    ...     for old, new in zip(po_file, mo_file):
-    ...         if po_file._encode(old.msgid) != mo_file._encode(new.msgid):
-    ...             'OLD: ', po_file._encode(old.msgid)
-    ...             'NEW: ', mo_file._encode(new.msgid)
-    ...         if po_file._encode(old.msgstr) != mo_file._encode(new.msgstr):
-    ...             'OLD: ', po_file._encode(old.msgstr)
-    ...             'NEW: ', mo_file._encode(new.msgstr)
-    ...             print new.msgstr
-    ... finally:
-    ...     os.unlink(tmpf)
-    >>> po = polib.pofile('tests/test_merge.pot')
-    >>> po_content = polib.pofile(open('tests/test_merge.pot','r').read())
-    >>> po[0].msgid == po_content[0].msgid
-    True
-    >>> po.encoding == po_content.encoding
-    True
-    >>> po = polib.pofile('tests/test_utf8.po')
-    >>> entry = po.find("Ensure this value has at least %(min)d characters (it has %(length)d).")
-    >>> entry.msgstr = entry.msgid + '**'
-    >>> '**' in entry.msgstr
-    True
-    >>> '**' in entry.__str__()
-    True
-    """
+    # get the file encoding
     if kwargs.get('autodetect_encoding', True):
-        enc = detect_encoding(pofile)
+        enc = detect_encoding(f, type == 'mofile')
     else:
         enc = kwargs.get('encoding', default_encoding)
-    check_for_duplicates = kwargs.get('check_for_duplicates', False)
-    parser = _POFileParser(
-        pofile,
+
+    # parse the file
+    kls = type == 'pofile' and _POFileParser or _MOFileParser
+    parser = kls(
+        f,
         encoding=enc,
         check_for_duplicates=kwargs.get('check_for_duplicates', False)
     )
     return instance
 
 # }}}
+# function pofile() {{{
+
+def pofile(pofile, **kwargs):
+    """
+    Convenience function that parses the po or pot file ``pofile`` and returns
+    a :class:`~polib.POFile` instance.
+
+    Arguments:
+
+    ``pofile``
+        string, full or relative path to the po/pot file or its content to
+        parse.
+
+    ``wrapwidth``
+        integer, the wrap width, only useful when the ``-w`` option was passed
+        to xgettext (optional, default: ``78``).
+
+    ``autodetect_encoding``
+        boolean, if set to ``False`` the function will not try to detect the
+        po file encoding and will use either the value of the ``encoding``
+        argument or the ``default_encoding`` (optional, default: ``True``).
+
+    ``encoding``
+        string, the encoding to use (e.g. "utf-8"), only relevant if
+        ``autodetect_encoding`` is set to ``False``.
+
+    ``check_for_duplicates``
+        whether to check for duplicate entries when adding entries to the
+        file (optional, default: ``False``).
+    """
+    return _pofile_or_mofile(pofile, 'pofile', **kwargs)
+
+# }}}
 # function mofile() {{{
 
-def mofile(fpath, **kwargs):
+def mofile(mofile, **kwargs):
     """
-    Convenience function that parse the mo file *fpath* and return
-    a MOFile instance.
+    Convenience function that parses the mo file ``mofile`` and returns a
+    :class:`~polib.MOFile` instance.
 
-    **Keyword arguments**:
-      - *fpath*: string, full or relative path to the mo file to parse
-      - *wrapwidth*: integer, the wrap width, only useful when -w option was
-        passed to xgettext to generate the po file that was used to format
-        the mo file (optional, default to 78)
-      - *autodetect_encoding*: boolean, if set to False the function will
-        not try to detect the po file encoding (optional, default to True)
-      - *encoding*: string, an encoding, only relevant if autodetect_encoding
-        is set to False
-      - *check_for_duplicates*: whether to check for duplicate entries when
-        adding entries to the file, default: False (optional)
+    Arguments:
 
-    **Example**:
+    ``mofile``
+        string, full or relative path to the mo file to parse.
 
-    >>> import polib
-    >>> mo = polib.mofile('tests/test_utf8.mo', check_for_duplicates=True)
-    >>> mo #doctest: +ELLIPSIS
-    <MOFile instance at ...>
-    >>> import os, tempfile
-    >>> for fname in ['test_iso-8859-15.mo', 'test_utf8.mo']:
-    ...     orig_mo = polib.mofile('tests/'+fname)
-    ...     tmpf = tempfile.NamedTemporaryFile().name
-    ...     orig_mo.save(tmpf)
-    ...     try:
-    ...         new_mo = polib.mofile(tmpf)
-    ...         for old, new in zip(orig_mo, new_mo):
-    ...             if old.msgid != new.msgid:
-    ...                 old.msgstr
-    ...                 new.msgstr
-    ...     finally:
-    ...         os.unlink(tmpf)
+    ``wrapwidth``
+        integer, the wrap width, only useful when the ``-w`` option was passed
+        to xgettext to generate the po file that was used to format the mo file
+        (optional, default: ``78``).
+
+    ``autodetect_encoding``
+        boolean, if set to ``False`` the function will not try to detect the
+        mo file encoding (optional, default: ``True``).
+
+    ``encoding``
+        string, the encoding to use, only relevant if ``autodetect_encoding``
+        is set to ``False``.
+
+    ``check_for_duplicates``
+        whether to check for duplicate entries when adding entries to the
+        file (optional, default: ``False``).
     """
-    if kwargs.get('autodetect_encoding', True):
-        enc = detect_encoding(fpath, True)
-    else:
-        enc = kwargs.get('encoding', default_encoding)
-    parser = _MOFileParser(
-        fpath,
-        encoding=enc,
-        check_for_duplicates=kwargs.get('check_for_duplicates', False)
-    )
-    instance = parser.parse()
-    instance.wrapwidth = kwargs.get('wrapwidth', 78)
-    return instance
+    return _pofile_or_mofile(mofile, 'mofile', **kwargs)
 
 # }}}
 # function detect_encoding() {{{
 
-def detect_encoding(pofile, binary_mode=False):
+def detect_encoding(file, binary_mode=False):
     """
-    Try to detect the encoding used by the *pofile*. The parameter *pofile*
-    might be a PO file path or its content. The function will return 
-    polib default *encoding* if it's unable to detect it.
+    Try to detect the encoding used by the ``file``. The ``file`` argument can
+    be a PO or MO file path or a string containing the contents of the file.
+    If the encoding cannot be detected, the function will return the value of
+    ``default_encoding``.
 
-    **Keyword argument**:
-      - *pofile*: string, full or relative path to the po/mo file or its content.
-      - *binary_mode*: boolean, True if *pofile* has a mo file path.
+    Arguments:
 
-    **Examples**:
+    ``file``
+        string, full or relative path to the po/mo file or its content.
 
-    >>> print(detect_encoding('tests/test_noencoding.po'))
-    utf-8
-    >>> print(detect_encoding('tests/test_merge.pot'))
-    utf-8
-    >>> print(detect_encoding('tests/test_utf8.po'))
-    UTF-8
-    >>> print(detect_encoding(open('tests/test_utf8.po','r').read()))
-    UTF-8
-    >>> print(detect_encoding('tests/test_utf8.mo', True))
-    UTF-8
-    >>> print(detect_encoding('tests/test_iso-8859-15.po'))
-    ISO_8859-15
-    >>> print(detect_encoding('tests/test_iso-8859-15.mo', True))
-    ISO_8859-15
+    ``binary_mode``
+        boolean, set this to True if ``file`` is a mo file.
     """
     rx = re.compile(r'"?Content-Type:.+? charset=([\w_\-:\.]+)')
 
             return False
         return True
 
-    if not os.path.exists(pofile):
-            match = rx.search(pofile)
-            if match:
-                enc = match.group(1).strip()
-                if charset_exists(enc):
-                    return enc
+    if not os.path.exists(file):
+        match = rx.search(file)
+        if match:
+            enc = match.group(1).strip()
+            if charset_exists(enc):
+                return enc
     else:
         if binary_mode:
             mode = 'rb'
         else:
             mode = 'r'
-        f = open(pofile, mode)
+        f = open(file, mode)
         for l in f.readlines():
             match = rx.search(l)
             if match:
 
 def escape(st):
     """
-    Escape special chars and return the given string *st*.
-
-    **Examples**:
-
-    >>> escape('\\t and \\n and \\r and " and \\\\')
-    '\\\\t and \\\\n and \\\\r and \\\\" and \\\\\\\\'
+    Escapes the characters ``\\\\``, ``\\t``, ``\\n``, ``\\r`` and ``"`` in
+    the given string ``st`` and returns it.
     """
     return st.replace('\\', r'\\')\
              .replace('\t', r'\t')\
 
 def unescape(st):
     """
-    Unescape special chars and return the given string *st*.
-
-    **Examples**:
-
-    >>> unescape('\\\\t and \\\\n and \\\\r and \\\\" and \\\\\\\\')
-    '\\t and \\n and \\r and " and \\\\'
-    >>> unescape(r'\\n')
-    '\\n'
-    >>> unescape(r'\\\\n')
-    '\\\\n'
-    >>> unescape(r'\\\\n\\n')
-    '\\\\n\\n'
+    Unescapes the characters ``\\\\``, ``\\t``, ``\\n``, ``\\r`` and ``"`` in
+    the given string ``st`` and returns it.
     """
     def unescape_repl(m):
         m = m.group(1)
 
 class _BaseFile(list):
     """
-    Common parent class for POFile and MOFile classes.
-    This class must **not** be instanciated directly.
+    Common base class for the :class:`~polib.POFile` and :class:`~polib.MOFile`
+    classes. This class should **not** be instanciated directly.
     """
 
     def __init__(self, *args, **kwargs):
         """
-        Constructor.
+        Constructor, accepts the following keyword arguments:
 
-        **Keyword arguments**:
-          - *pofile*: string, path to po or mo file or its content
-          - *wrapwidth*: integer, the wrap width, only useful when -w option
-            was passed to xgettext to generate the po file that was used to
-            format the mo file, default to 78 (optional),
-          - *encoding*: string, the encoding to use, defaults to
-            "default_encoding" global variable (optional),
-          - *check_for_duplicates*: whether to check for duplicate entries
-            when adding entries to the file, default: False (optional).
+        ``pofile``
+            string, the path to the po or mo file, or its content as a string.
+
+        ``wrapwidth``
+            integer, the wrap width, only useful when the ``-w`` option was
+            passed to xgettext (optional, default: ``78``).
+
+        ``encoding``
+            string, the encoding to use, defaults to ``default_encoding``
+            global variable (optional).
+
+        ``check_for_duplicates``
+            whether to check for duplicate entries when adding entries to the
+            file, (optional, default: ``False``).
         """
         list.__init__(self)
         # the opened file handle
 
     def __unicode__(self):
         """
-        Unicode representation of the file.
+        Returns the unicode representation of the file.
         """
         ret = []
         entries = [self.metadata_as_entry()] + \
 
     def __str__(self):
         """
-        String representation of the file.
+        Returns the string representation of the file.
         """
         return unicode(self).encode(self.encoding)
 
     def __contains__(self, entry):
         """
-        Overriden method to implement the membership test (in and not in).
-        The method considers that an entry is in the file if it finds an 
-        entry that has the same msgid (case sensitive).
+        Overriden ``list`` method to implement the membership test (in and
+        not in).
+        The method considers that an entry is in the file if it finds an entry
+        that has the same msgid (the test is **case sensitive**).
 
-        **Keyword argument**:
-          - *entry*: an instance of polib._BaseEntry
+        Argument:
 
-        **Tests**:
-        >>> po = POFile()
-        >>> e1 = POEntry(msgid='foobar', msgstr='spam')
-        >>> e2 = POEntry(msgid='barfoo', msgstr='spam')
-        >>> e3 = POEntry(msgid='foobar', msgstr='eggs')
-        >>> e4 = POEntry(msgid='spameggs', msgstr='eggs')
-        >>> po.append(e1)
-        >>> po.append(e2)
-        >>> e1 in po
-        True
-        >>> e2 not in po
-        False
-        >>> e3 in po
-        True
-        >>> e4 in po
-        False
+        ``entry``
+            an instance of :class:`~polib._BaseEntry`.
         """
         return self.find(entry.msgid, by='msgid') is not None
 
     def append(self, entry):
         """
         Overriden method to check for duplicates entries, if a user tries to
-        add an entry that already exists, the method will raise a ValueError
-        exception.
+        add an entry that is already in the file, the method will raise a
+        ``ValueError`` exception.
 
-        **Keyword argument**:
-          - *entry*: an instance of polib._BaseEntry
+        Argument:
 
-        **Tests**:
-        >>> e1 = POEntry(msgid='foobar', msgstr='spam')
-        >>> e2 = POEntry(msgid='foobar', msgstr='eggs')
-        >>> po = POFile(check_for_duplicates=True)
-        >>> po.append(e1)
-        >>> try:
-        ...     po.append(e2)
-        ... except ValueError, e:
-        ...     unicode(e)
-        u'Entry "foobar" already exists'
+        ``entry``
+            an instance of :class:`~polib._BaseEntry`.
         """
         if self.check_for_duplicates and entry in self:
             raise ValueError('Entry "%s" already exists' % entry.msgid)
     def insert(self, index, entry):
         """
         Overriden method to check for duplicates entries, if a user tries to
-        insert an entry that already exists, the method will raise a ValueError
-        exception.
+        add an entry that is already in the file, the method will raise a
+        ``ValueError`` exception.
 
-        **Keyword arguments**:
-          - *index*: index at which the entry should be inserted
-          - *entry*: an instance of polib._BaseEntry
+        Arguments:
 
-        **Tests**:
-        >>> import polib
-        >>> polib.check_for_duplicates = True
-        >>> e1 = POEntry(msgid='foobar', msgstr='spam')
-        >>> e2 = POEntry(msgid='barfoo', msgstr='eggs')
-        >>> e3 = POEntry(msgid='foobar', msgstr='eggs')
-        >>> po = POFile(check_for_duplicates=True)
-        >>> po.insert(0, e1)
-        >>> po.insert(1, e2)
-        >>> try:
-        ...     po.insert(0, e3)
-        ... except ValueError, e:
-        ...     unicode(e)
-        u'Entry "foobar" already exists'
+        ``index``
+            index at which the entry should be inserted.
+
+        ``entry``
+            an instance of :class:`~polib._BaseEntry`.
         """
         if self.check_for_duplicates and entry in self:
             raise ValueError('Entry "%s" already exists' % entry.msgid)
         super(_BaseFile, self).insert(index, entry)
 
-    def __repr__(self):
-        """Return the official string representation of the object."""
-        return '<%s instance at %x>' % (self.__class__.__name__, id(self))
-
     def metadata_as_entry(self):
         """
-        Return the metadata as an entry:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_fuzzy_header.po')
-        >>> unicode(po) == unicode(open('tests/test_fuzzy_header.po').read())
-        True
+        Returns the file metadata as a :class:`~polib.POFile` instance.
         """
         e = POEntry(msgid='')
         mdata = self.ordered_metadata()
 
     def save(self, fpath=None, repr_method='__str__'):
         """
-        Save the po file to file *fpath* if no file handle exists for
-        the object. If there's already an open file and no fpath is
-        provided, then the existing file is rewritten with the modified
-        data.
+        Saves the po file to ``fpath``.
+        If it is an existing file and no ``fpath`` is provided, then the
+        existing file is rewritten with the modified data.
 
-        **Keyword arguments**:
-          - *fpath*: string, full or relative path to the file.
-          - *repr_method*: string, the method to use for output.
+        Keyword arguments:
+
+        ``fpath``
+            string, full or relative path to the file.
+
+        ``repr_method``
+            string, the method to use for output.
         """
         if self.fpath is None and fpath is None:
             raise IOError('You must provide a file path to save() method')
     def find(self, st, by='msgid', include_obsolete_entries=False,
              msgctxt=False):
         """
-        Find entry which msgid (or property identified by the *by*
-        attribute) matches the string *st*.
+        Find the entry which msgid (or property identified by the ``by``
+        argument) matches the string ``st``.
 
-        **Keyword arguments**:
-          - *st*: string, the string to search for
-          - *by*: string, the comparison attribute
-          - *include_obsolete_entries*: boolean, whether to also search in 
-            entries that are obsolete
-          - *msgctxt*: string, allows to specify a specific message context
-            for the search.
+        Keyword arguments:
 
-        **Examples**:
+        ``st``
+            string, the string to search for.
 
-        >>> po = pofile('tests/test_utf8.po')
-        >>> entry = po.find('Thursday')
-        >>> entry.msgstr
-        u'Jueves'
-        >>> entry = po.find('test context')
-        >>> entry.msgstr
-        u'test context 1'
-        >>> entry = po.find('test context', msgctxt='@context1')
-        >>> entry.msgstr
-        u'test context 1'
-        >>> entry = po.find('test context', msgctxt='@context2')
-        >>> entry.msgstr
-        u'test context 2'
-        >>> entry = po.find('Some unexistant msgid')
-        >>> entry is None
-        True
-        >>> entry = po.find('Jueves', 'msgstr')
-        >>> entry.msgid
-        u'Thursday'
+        ``by``
+            string, the property to use for comparison (default: ``msgid``).
+
+        ``include_obsolete_entries``
+            boolean, whether to also search in entries that are obsolete.
+
+        ``msgctxt``
+            string, allows to specify a specific message context for the
+            search.
         """
         for e in self:
             if getattr(e, by) == st:
 
     def ordered_metadata(self):
         """
-        Convenience method that return the metadata ordered. The return
-        value is list of tuples (metadata name, metadata_value).
+        Convenience method that returns an ordered version of the metadata
+        dictionnary. The return value is list of tuples (metadata name,
+        metadata_value).
         """
         # copy the dict first
         metadata = self.metadata.copy()
 
     def to_binary(self):
         """
-        Return the mofile binary representation.
+        Return the binary representation of the file.
         """
-        import array
         offsets = []
         entries = self.translated_entries()
         # the keys are sorted in the .mo file
 
     def _encode(self, mixed):
         """
-        Encode the given argument with the file encoding if the type is unicode
-        and return the encoded string.
+        Encodes the given ``mixed`` argument with the file encoding if and
+        only if it's an unicode string and returns the encoded string.
         """
         if type(mixed) == types.UnicodeType:
             return mixed.encode(self.encoding)
 # class POFile {{{
 
 class POFile(_BaseFile):
-    '''
+    """
     Po (or Pot) file reader/writer.
-    POFile objects inherit the list objects methods.
-
-    **Example**:
-
-    >>> po = POFile()
-    >>> entry1 = POEntry(
-    ...     msgid="Some english text",
-    ...     msgstr="Un texte en anglais"
-    ... )
-    >>> entry1.occurrences = [('testfile', 12),('another_file', 1)]
-    >>> entry1.comment = "Some useful comment"
-    >>> entry2 = POEntry(
-    ...     msgid="Peace in some languages",
-    ...     msgstr="Pace سلام שלום Hasîtî 和平",
-    ... )
-    >>> entry2.occurrences = [('testfile', 15),('another_file', 5)]
-    >>> entry2.comment = "Another useful comment"
-    >>> entry3 = POEntry(
-    ...     msgid='Some entry with quotes " \\"',
-    ...     msgstr='Un message unicode avec des quotes " \\"'
-    ... )
-    >>> entry3.comment = "Test string quoting"
-    >>> po.append(entry1)
-    >>> po.append(entry2)
-    >>> po.append(entry3)
-    >>> po.header = "Some Header"
-    >>> print(po)
-    # Some Header
-    msgid ""
-    msgstr ""
-    <BLANKLINE>
-    #. Some useful comment
-    #: testfile:12 another_file:1
-    msgid "Some english text"
-    msgstr "Un texte en anglais"
-    <BLANKLINE>
-    #. Another useful comment
-    #: testfile:15 another_file:5
-    msgid "Peace in some languages"
-    msgstr "Pace سلام שלום Hasîtî 和平"
-    <BLANKLINE>
-    #. Test string quoting
-    msgid "Some entry with quotes \\" \\""
-    msgstr "Un message unicode avec des quotes \\" \\""
-    <BLANKLINE>
-    '''
+    This class inherits the :class:`~polib._BaseFile` class and, by extension,
+    the python ``list`` type.
+    """
 
     def __unicode__(self):
-        """Return the string representation of the po file"""
+        """
+        Returns the unicode representation of the po file.
+        """
         ret, headers = '', self.header.split('\n')
         for header in headers:
             if header[:1] in [',', ':']:
 
     def save_as_mofile(self, fpath):
         """
-        Save the binary representation of the file to *fpath*.
+        Saves the binary representation of the file to given ``fpath``.
 
-        **Keyword arguments**:
-          - *fpath*: string, full or relative path to the file.
+        Keyword argument:
+
+        ``fpath``
+            string, full or relative path to the mo file.
         """
         _BaseFile.save(self, fpath, 'to_binary')
 
     def percent_translated(self):
         """
-        Convenience method that return the percentage of translated
+        Convenience method that returns the percentage of translated
         messages.
-
-        **Example**:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_pofile_helpers.po')
-        >>> po.percent_translated()
-        50
-        >>> po = POFile()
-        >>> po.percent_translated()
-        100
         """
         total = len([e for e in self if not e.obsolete])
         if total == 0:
 
     def translated_entries(self):
         """
-        Convenience method that return a list of translated entries.
-
-        **Example**:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_pofile_helpers.po')
-        >>> len(po.translated_entries())
-        6
+        Convenience method that returns the list of translated entries.
         """
         return [e for e in self if e.translated()]
 
     def untranslated_entries(self):
         """
-        Convenience method that return a list of untranslated entries.
-
-        **Example**:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_pofile_helpers.po')
-        >>> len(po.untranslated_entries())
-        4
+        Convenience method that returns the list of untranslated entries.
         """
         return [e for e in self if not e.translated() and not e.obsolete \
                 and not 'fuzzy' in e.flags]
 
     def fuzzy_entries(self):
         """
-        Convenience method that return the list of 'fuzzy' entries.
-
-        **Example**:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_pofile_helpers.po')
-        >>> len(po.fuzzy_entries())
-        2
+        Convenience method that returns the list of fuzzy entries.
         """
         return [e for e in self if 'fuzzy' in e.flags]
 
     def obsolete_entries(self):
         """
-        Convenience method that return the list of obsolete entries.
-
-        **Example**:
-
-        >>> import polib
-        >>> po = polib.pofile('tests/test_pofile_helpers.po')
-        >>> len(po.obsolete_entries())
-        4
+        Convenience method that returns the list of obsolete entries.
         """
         return [e for e in self if e.obsolete]
 
     def merge(self, refpot):
         """
-        XXX this could not work if encodings are different, needs thinking
+        FIXME: this could not work if encodings are different, needs thinking
         and general refactoring of how polib handles encoding...
 
-        Convenience method that merge the current pofile with the pot file
+        Convenience method that merges the current pofile with the pot file
         provided. It behaves exactly as the gettext msgmerge utility:
 
-          - comments of this file will be preserved, but extracted comments
-            and occurrences will be discarded
-          - any translations or comments in the file will be discarded,
-            however dot comments and file positions will be preserved
-          - keep the fuzzy flag
+        * comments of this file will be preserved, but extracted comments and
+          occurrences will be discarded;
+        * any translations or comments in the file will be discarded, however,
+          dot comments and file positions will be preserved;
+        * the fuzzy flags are preserved.
 
-        **Keyword argument**:
-          - *refpot*: object POFile, the reference catalog.
+        Keyword argument:
 
-        **Example**:
-
-        >>> import polib
-        >>> refpot = polib.pofile('tests/test_merge.pot')
-        >>> po = polib.pofile('tests/test_merge_before.po')
-        >>> po.merge(refpot)
-        >>> expected_po = polib.pofile('tests/test_merge_after.po')
-        >>> unicode(po) == unicode(expected_po)
-        True
+        ``refpot``
+            object POFile, the reference catalog.
         """
         for entry in refpot:
             e = self.find(entry.msgid, include_obsolete_entries=True)
                 e = POEntry()
                 self.append(e)
             e.merge(entry)
-        # ok, now we must "obsolete" entries that are not in the refpot
-        # anymore
+        # ok, now we must "obsolete" entries that are not in the refpot anymore
         for entry in self:
             if refpot.find(entry.msgid) is None:
                 entry.obsolete = True
 # class MOFile {{{
 
 class MOFile(_BaseFile):
-    '''
+    """
     Mo file reader/writer.
-    MOFile objects inherit the list objects methods.
-
-    **Example**:
-
-    >>> mo = MOFile()
-    >>> entry1 = POEntry(
-    ...     msgid="Some english text",
-    ...     msgstr="Un texte en anglais"
-    ... )
-    >>> entry2 = POEntry(
-    ...     msgid="I need my dirty cheese",
-    ...     msgstr="Je veux mon sale fromage"
-    ... )
-    >>> entry3 = MOEntry(
-    ...     msgid='Some entry with quotes " \\"',
-    ...     msgstr='Un message unicode avec des quotes " \\"'
-    ... )
-    >>> mo.append(entry1)
-    >>> mo.append(entry2)
-    >>> mo.append(entry3)
-    >>> print(mo)
-    msgid ""
-    msgstr ""
-    <BLANKLINE>
-    msgid "Some english text"
-    msgstr "Un texte en anglais"
-    <BLANKLINE>
-    msgid "I need my dirty cheese"
-    msgstr "Je veux mon sale fromage"
-    <BLANKLINE>
-    msgid "Some entry with quotes \\" \\""
-    msgstr "Un message unicode avec des quotes \\" \\""
-    <BLANKLINE>
-    '''
+    This class inherits the :class:`~polib._BaseFile` class and, by
+    extension, the python ``list`` type.
+    """
 
     def __init__(self, *args, **kwargs):
         """
-        MOFile constructor. Mo files have two other properties:
-            - magic_number: the magic_number of the binary file,
-            - version: the version of the mo spec.
+        Constructor, accepts the following keyword arguments:
+
+        ``magic_number``
+            the magic_number of the binary file.
+
+        ``version``
+            the version of the mo file specification.
         """
         _BaseFile.__init__(self, *args, **kwargs)
         self.magic_number = None
 
     def save_as_pofile(self, fpath):
         """
-        Save the string representation of the file to *fpath*.
+        Saves the mofile as a pofile to ``fpath``.
 
-        **Keyword argument**:
-          - *fpath*: string, full or relative path to the file.
+        Keyword argument:
+
+        ``fpath``
+            string, full or relative path to the file.
         """
         _BaseFile.save(self, fpath)
 
-    def save(self, fpath):
+    def save(self, fpath=None):
         """
-        Save the binary representation of the file to *fpath*.
+        Saves the mofile to ``fpath``.
 
-        **Keyword argument**:
-          - *fpath*: string, full or relative path to the file.
+        Keyword argument:
+
+        ``fpath``
+            string, full or relative path to the file.
         """
         _BaseFile.save(self, fpath, 'to_binary')
 
 
 class _BaseEntry(object):
     """
-    Base class for POEntry or MOEntry objects.
-    This class must *not* be instanciated directly.
+    Base class for :class:`~polib.POEntry` and :class:`~polib.MOEntry` classes.
+    This class should **not** be instanciated directly.
     """
 
     def __init__(self, *args, **kwargs):
-        """Base Entry constructor."""
+        """
+        TODO: document keyword arguments.
+        """
         self.msgid = kwargs.get('msgid', '')
         self.msgstr = kwargs.get('msgstr', '')
         self.msgid_plural = kwargs.get('msgid_plural', '')
         self.msgctxt = kwargs.get('msgctxt', None)
 
     def __repr__(self):
-        """Return the official string representation of the object."""
+        """
+        Returns the python representation of the entry.
+        """
         return '<%s instance at %x>' % (self.__class__.__name__, id(self))
 
     def __unicode__(self, wrapwidth=78):
         """
-        Unicode representation of the entry.
+        Returns the unicode representation of the entry.
         """
         if self.obsolete:
             delflag = '#~ '
 
     def __str__(self):
         """
-        String representation of the entry.
+        Returns the string representation of the entry.
         """
         return unicode(self).encode(self.encoding)
 
 class POEntry(_BaseEntry):
     """
     Represents a po file entry.
-
-    **Examples**:
-
-    >>> entry = POEntry(msgid='Welcome', msgstr='Bienvenue')
-    >>> entry.occurrences = [('welcome.py', 12), ('anotherfile.py', 34)]
-    >>> print(entry)
-    #: welcome.py:12 anotherfile.py:34
-    msgid "Welcome"
-    msgstr "Bienvenue"
-    <BLANKLINE>
-    >>> entry = POEntry()
-    >>> entry.occurrences = [('src/some-very-long-filename-that-should-not-be-wrapped-even-if-it-is-larger-than-the-wrap-limit.c', 32), ('src/eggs.c', 45)]
-    >>> entry.comment = 'A plural translation. This is a very very very long line please do not wrap, this is just for testing comment wrapping...'
-    >>> entry.tcomment = 'A plural translation. This is a very very very long line please do not wrap, this is just for testing comment wrapping...'
-    >>> entry.flags.append('c-format')
-    >>> entry.previous_msgctxt = '@somecontext'
-    >>> entry.previous_msgid = 'I had eggs but no spam !'
-    >>> entry.previous_msgid_plural = 'I had eggs and %d spam !'
-    >>> entry.msgctxt = '@somenewcontext'
-    >>> entry.msgid = 'I have spam but no egg !'
-    >>> entry.msgid_plural = 'I have spam and %d eggs !'
-    >>> entry.msgstr_plural[0] = "J'ai du jambon mais aucun oeuf !"
-    >>> entry.msgstr_plural[1] = "J'ai du jambon et %d oeufs !"
-    >>> print(entry)
-    #. A plural translation. This is a very very very long line please do not
-    #. wrap, this is just for testing comment wrapping...
-    # A plural translation. This is a very very very long line please do not wrap,
-    # this is just for testing comment wrapping...
-    #: src/some-very-long-filename-that-should-not-be-wrapped-even-if-it-is-larger-than-the-wrap-limit.c:32
-    #: src/eggs.c:45
-    #, c-format
-    #| msgctxt "@somecontext"
-    #| msgid "I had eggs but no spam !"
-    #| msgid_plural "I had eggs and %d spam !"
-    msgctxt "@somenewcontext"
-    msgid "I have spam but no egg !"
-    msgid_plural "I have spam and %d eggs !"
-    msgstr[0] "J'ai du jambon mais aucun oeuf !"
-    msgstr[1] "J'ai du jambon et %d oeufs !"
-    <BLANKLINE>
     """
 
     def __init__(self, *args, **kwargs):
-        """POEntry constructor."""
+        """
+        TODO: document keyword arguments.
+        """
         _BaseEntry.__init__(self, *args, **kwargs)
         self.comment = kwargs.get('comment', '')
         self.tcomment = kwargs.get('tcomment', '')
 
     def __unicode__(self, wrapwidth=78):
         """
-        Return the string representation of the entry.
+        Returns the unicode representation of the entry.
         """
         if self.obsolete:
             return _BaseEntry.__unicode__(self)
         return ret
 
     def __cmp__(self, other):
-        '''
+        """
         Called by comparison operations if rich comparison is not defined.
-
-        **Tests**:
-        >>> a  = POEntry(msgid='a', occurrences=[('b.py', 1), ('b.py', 3)])
-        >>> b  = POEntry(msgid='b', occurrences=[('b.py', 1), ('b.py', 3)])
-        >>> c1 = POEntry(msgid='c1', occurrences=[('a.py', 1), ('b.py', 1)])
-        >>> c2 = POEntry(msgid='c2', occurrences=[('a.py', 1), ('a.py', 3)])
-        >>> po = POFile()
-        >>> po.append(a)
-        >>> po.append(b)
-        >>> po.append(c1)
-        >>> po.append(c2)
-        >>> po.sort()
-        >>> print(po)
-        # 
-        msgid ""
-        msgstr ""
-        <BLANKLINE>
-        #: a.py:1 a.py:3
-        msgid "c2"
-        msgstr ""
-        <BLANKLINE>
-        #: a.py:1 b.py:1
-        msgid "c1"
-        msgstr ""
-        <BLANKLINE>
-        #: b.py:1 b.py:3
-        msgid "a"
-        msgstr ""
-        <BLANKLINE>
-        #: b.py:1 b.py:3
-        msgid "b"
-        msgstr ""
-        <BLANKLINE>
-        '''
+        """
         def compare_occurrences(a, b):
             """
             Compare an entry occurrence with another one.
 
     def translated(self):
         """
-        Return True if the entry has been translated or False.
+        Returns ``True`` if the entry has been translated or ``False``
+        otherwise.
         """
         if self.obsolete or 'fuzzy' in self.flags:
             return False
         self.occurrences = other.occurrences
         self.comment = other.comment
         fuzzy = 'fuzzy' in self.flags
-        self.flags = other.flags[:] #Clone flags
+        self.flags = other.flags[:]  # clone flags
         if fuzzy:
             self.flags.append('fuzzy')
         self.msgid_plural = other.msgid_plural
 class MOEntry(_BaseEntry):
     """
     Represents a mo file entry.
-
-    **Examples**: