Better Documentation Through Automation:
       Creating docutils & Sphinx Extensions

       Doug Hellmann
       @doughellmann
       PyCon 2013




Saturday, March 16, 13
Markup Language




Saturday, March 16, 13
Extensible
                         Markup Language




Saturday, March 16, 13
Saturday, March 16, 13
Sphinx
         Application




Saturday, March 16, 13
Sphinx            Build
         Application     Environment




                            .rst




Saturday, March 16, 13
Sphinx            Build      docutils
         Application     Environment    parser




                            .rst




Saturday, March 16, 13
Sphinx            Build      docutils     Sphinx
         Application     Environment    parser      Builder




                            .rst                  .pdf   .html




Saturday, March 16, 13
section

                         title             paragraph

                         #text    #text emphasis       #text   literal

                                             #text             #text




Saturday, March 16, 13
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam
      vulputate elementum lectus a viverra. Vivamus hendrerit egestas
      lacinia. Proin tellus lectus, scelerisque vitae rutrum eget,
      ultrices vel metus. Quisque :ref:`target-name` pharetra lorem
      vehicula lorem posuere molestie cursus ipsum ornare. Class
      aptent taciti sociosqu ad litora torquent per conubia nostra,
      per inceptos himenaeos. Maecenas eu sapien at tellus suscipit
      aliquet :pep:`8` ut non tellus. Nulla facilisis bibendum dolor,
      quis mattis urna posuere eget. Nulla quis dui id augue faucibus
      varius. Nam eu leo quam. Fusce :term:`condimentum` placerat nisi
      nec vestibulum. Duis tortor sapien, commodo ac faucibus
      nec :rfc:`1822`, rutrum quis urna. Pellentesque cursus facilisis
      odio, id aliquam sem commodo vestibulum. Proin eget velit sed
      justo ultricies vulputate.




Saturday, March 16, 13
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam
      vulputate elementum lectus a viverra. Vivamus hendrerit egestas
      lacinia. Proin tellus lectus, scelerisque vitae rutrum eget,
      ultrices vel metus. Quisque :ref:`target-name` pharetra lorem
      vehicula lorem posuere molestie cursus ipsum ornare. Class
      aptent taciti sociosqu ad litora torquent per conubia nostra,
      per inceptos himenaeos. Maecenas eu sapien at tellus suscipit
      aliquet :pep:`8` ut non tellus. Nulla facilisis bibendum dolor,
      quis mattis urna posuere eget. Nulla quis dui id augue faucibus
      varius. Nam eu leo quam. Fusce :term:`condimentum` placerat nisi
      nec vestibulum. Duis tortor sapien, commodo ac faucibus
      nec :rfc:`1822`, rutrum quis urna. Pellentesque cursus facilisis
      odio, id aliquam sem commodo vestibulum. Proin eget velit sed
      justo ultricies vulputate.




Saturday, March 16, 13
.. seealso::

           PyEnchant_
             Python interface to enchant_.

           :ref:`project-sphinxcontrib-spelling`
             Project home page for the spelling checker.

           sphinxcontrib_
             BitBucket repository for sphinxcontrib-spelling and
             several other Sphinx extensions.


      .. include:: example.py
         :literal:
         :start-after: # end-of-header-comment


      .. image:: figure.png




Saturday, March 16, 13
2.6

        - Fixed a problem with hook script line endings under Cygwin
          (`Issue 68 <https://bitbucket.org/dhellmann/
      virtualenvwrapper/issue/68>`_).
        - Updated documentation to include a list of the compatible
          shells
          (:ref:`supported-shells`) and Python versions
          (:ref:`supported-versions`) (`Issue 70 <https://
      bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_).
        - Fixed installation dependency on virtualenv (`Issue 60
      <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_).
        - Fixed the method for determining the Python version so it
          works
          under Python 2.4 (`Issue 61 <https://bitbucket.org/
      dhellmann/virtualenvwrapper/issue/60>`_).
        - Converted the test infrastructure to use `tox
          <http://codespeak.net/tox/index.html>`_ instead of home-
      grown
          scripts in the Makefile.




Saturday, March 16, 13
2.6

        - Fixed a problem with hook script line endings under Cygwin
          (`Issue 68 <https://bitbucket.org/dhellmann/
      virtualenvwrapper/issue/68>`_).
        - Updated documentation to include a list of the compatible
          shells
          (:ref:`supported-shells`) and Python versions
          (:ref:`supported-versions`) (`Issue 70 <https://
      bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_).
        - Fixed installation dependency on virtualenv (`Issue 60
      <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_).
        - Fixed the method for determining the Python version so it
          works
          under Python 2.4 (`Issue 61 <https://bitbucket.org/
      dhellmann/virtualenvwrapper/issue/60>`_).
        - Converted the test infrastructure to use `tox
          <http://codespeak.net/tox/index.html>`_ instead of home-
      grown
          scripts in the Makefile.




Saturday, March 16, 13
2.6

        - Fixed a problem with hook script line endings under Cygwin
          (`Issue 68 <https://bitbucket.org/dhellmann/
      virtualenvwrapper/issue/68>`_).
        - Updated documentation to include a list of the compatible
          shells
          (:ref:`supported-shells`) and Python versions
          (:ref:`supported-versions`) (`Issue 70 <https://
      bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_).
        - Fixed installation dependency on virtualenv (`Issue 60
      <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_).
        - Fixed the method for determining the Python version so it
          works
          under Python 2.4 (`Issue 61 <https://bitbucket.org/
      dhellmann/virtualenvwrapper/issue/60>`_).
        - Converted the test infrastructure to use `tox
          <http://codespeak.net/tox/index.html>`_ instead of home-
      grown
          scripts in the Makefile.




Saturday, March 16, 13
`Issue 68 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/68>`_




Saturday, March 16, 13
`Issue 68 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/68>`_




Saturday, March 16, 13
`Issue 68 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/68>`_




Saturday, March 16, 13
`Issue 68 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/68>`_


                                          :bbissue:`68`




Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
from docutils import nodes, utils
      from docutils.parsers.rst.roles import set_classes


      def bbissue_role(name, rawtext, text, lineno, inliner, options={},
                        content=[]):
          "Link to a BitBucket issue."
          try:
               issue_num = int(text)
               if issue_num <= 0:
                   raise ValueError
          except ValueError:
               msg = inliner.reporter.error(
                   '"%s" is an invalid bug id.' % text,
                   line=lineno)
               prb = inliner.problematic(rawtext, rawtext, msg)
               return [prb], [msg]
          app = inliner.document.settings.env.app
          node = make_link_node(rawtext, app, 'issue',
                                  text, options)
          return [node], []


      def make_link_node(rawtext, app, type, slug, options):
          "Create a link to a BitBucket resource."
          try:
               base = app.config.bitbucket_project_url
               if not base:
Saturday, March 16, 13
app = inliner.document.settings.env.app
        node = make_link_node(rawtext, app, 'issue',
                              text, options)
        return [node], []


   def make_link_node(rawtext, app, type, slug, options):
       "Create a link to a BitBucket resource."
       try:
            base = app.config.bitbucket_project_url
            if not base:
                raise AttributeError
       except AttributeError, err:
            raise ValueError('bitbucket_project_url not set (%s)' %
                             str(err))

        slash = '/' if base[-1] != '/' else ''
        ref = base + slash + type + '/' + slug + '/'
        set_classes(options)
        node = nodes.reference(rawtext,
                               type + ' ' + utils.unescape(slug),
                               refuri=ref,
                               **options)
        return node


      def setup(app):
                "Install the plugin."
                app.info('Initializing BitBucket plugin')
                app.add_role('bbissue', bbissue_role)
Saturday, March 16, 13
app = inliner.document.settings.env.app
        node = make_link_node(rawtext, app, 'issue',
                              text, options)
        return [node], []


   def make_link_node(rawtext, app, type, slug, options):
       "Create a link to a BitBucket resource."
       try:
            base = app.config.bitbucket_project_url
            if not base:
                raise AttributeError
       except AttributeError, err:
            raise ValueError('bitbucket_project_url not set (%s)' %
                             str(err))

        slash = '/' if base[-1] != '/' else ''
        ref = base + slash + type + '/' + slug + '/'
        set_classes(options)
        node = nodes.reference(rawtext,
                               type + ' ' + utils.unescape(slug),
                               refuri=ref,
                               **options)
        return node


      def setup(app):
                "Install the plugin."
                app.info('Initializing BitBucket plugin')
                app.add_role('bbissue', bbissue_role)
Saturday, March 16, 13
app = inliner.document.settings.env.app
        node = make_link_node(rawtext, app, 'issue',
                              text, options)
        return [node], []


   def make_link_node(rawtext, app, type, slug, options):
       "Create a link to a BitBucket resource."
       try:
            base = app.config.bitbucket_project_url
            if not base:
                raise AttributeError
       except AttributeError, err:
            raise ValueError('bitbucket_project_url not set (%s)' %
                             str(err))

        slash = '/' if base[-1] != '/' else ''
        ref = base + slash + type + '/' + slug + '/'
        set_classes(options)
        node = nodes.reference(rawtext,
                               type + ' ' + utils.unescape(slug),
                               refuri=ref,
                               **options)
        return node


      def setup(app):
                "Install the plugin."
                app.info('Initializing BitBucket plugin')
                app.add_role('bbissue', bbissue_role)
Saturday, March 16, 13
app = inliner.document.settings.env.app
        node = make_link_node(rawtext, app, 'issue',
                              text, options)
        return [node], []


   def make_link_node(rawtext, app, type, slug, options):
       "Create a link to a BitBucket resource."
       try:
            base = app.config.bitbucket_project_url
            if not base:
                raise AttributeError
       except AttributeError, err:
            raise ValueError('bitbucket_project_url not set (%s)' %
                             str(err))

        slash = '/' if base[-1] != '/' else ''
        ref = base + slash + type + '/' + slug + '/'
        set_classes(options)
        node = nodes.reference(rawtext,
                               type + ' ' + utils.unescape(slug),
                               refuri=ref,
                               **options)
        return node


      def setup(app):
                "Install the plugin."
                app.info('Initializing BitBucket plugin')
                app.add_role('bbissue', bbissue_role)
Saturday, March 16, 13
app = inliner.document.settings.env.app
        node = make_link_node(rawtext, app, 'issue',
                              text, options)
        return [node], []


   def make_link_node(rawtext, app, type, slug, options):
       "Create a link to a BitBucket resource."
       try:
            base = app.config.bitbucket_project_url
            if not base:
                raise AttributeError
       except AttributeError, err:
            raise ValueError('bitbucket_project_url not set (%s)' %
                             str(err))

        slash = '/' if base[-1] != '/' else ''
        ref = base + slash + type + '/' + slug + '/'
        set_classes(options)
        node = nodes.reference(rawtext,
                               type + ' ' + utils.unescape(slug),
                               refuri=ref,
                               **options)
        return node


      def setup(app):
                "Install the plugin."
                app.info('Initializing BitBucket plugin')
                app.add_role('bbissue', bbissue_role)
Saturday, March 16, 13
node = nodes.reference(rawtext,
                                      type + ' ' + utils.unescape(slug),
                                      refuri=ref,
                                      **options)
               return node


      def setup(app):
          "Install the plugin."
          app.info('Initializing BitBucket plugin')
          app.add_role('bbissue', bbissue_role)
          app.add_config_value('bitbucket_project_url', None, 'env')
          return




Saturday, March 16, 13
node = nodes.reference(rawtext,
                                      type + ' ' + utils.unescape(slug),
                                      refuri=ref,
                                      **options)
               return node


      def setup(app):
          "Install the plugin."
          app.info('Initializing BitBucket plugin')
          app.add_role('bbissue', bbissue_role)
          app.add_config_value('bitbucket_project_url', None, 'env')
          return




Saturday, March 16, 13
node = nodes.reference(rawtext,
                                      type + ' ' + utils.unescape(slug),
                                      refuri=ref,
                                      **options)
               return node


      def setup(app):
          "Install the plugin."
          app.info('Initializing BitBucket plugin')
          app.add_role('bbissue', bbissue_role)
          app.add_config_value('bitbucket_project_url', None, 'env')
          return




Saturday, March 16, 13
2.6

           - Fixed a problem with hook script line endings under Cygwin
             (:bbissue:`68`).
           - Updated documentation to include a list of the
             compatible shells
             (:ref:`supported-shells`) and Python versions
             (:ref:`supported-versions`) (:bbissue:`70`).
           - Fixed installation dependency on virtualenv (:bbissue:`60`).
           - Fixed the method for determining the Python version so
             it works under Python 2.4 (:bbissue:`61`).
           - Converted the test infrastructure to use `tox
             <http://codespeak.net/tox/index.html>`_ instead of
             home-grown
             scripts in the Makefile.




Saturday, March 16, 13
2.6

           - Fixed a problem with hook script line endings under Cygwin
             (:bbissue:`68`).
           - Updated documentation to include a list of the
             compatible shells
             (:ref:`supported-shells`) and Python versions
             (:ref:`supported-versions`) (:bbissue:`70`).
           - Fixed installation dependency on virtualenv (:bbissue:`60`).
           - Fixed the method for determining the Python version so
             it works under Python 2.4 (:bbissue:`61`).
           - Converted the test infrastructure to use `tox
             <http://codespeak.net/tox/index.html>`_ instead of
             home-grown
             scripts in the Makefile.




Saturday, March 16, 13
2.6
        • Fixed a problem with hook script line endings under
          Cygwin (issue 68).
        • Updated documentation to include a list of the
          compatible shells (Supported Shells) and Python
          versions (Python Versions) (issue 70).
        • Fixed installation dependency on virtualenv (issue 60).
        • Fixed the method for determining the Python version so
          it works under Python 2.4 (issue 61).
        • Converted the test infrastructure to use tox instead of
          home-grown scripts in the Makefile.




Saturday, March 16, 13
.. name:: arguments
                            :option: value
                            :option: another-value

                            body line
                            body line




Saturday, March 16, 13
.. name:: arguments
                            :option: value
                            :option: another-value

                            body line
                            body line




Saturday, March 16, 13
.. name:: arguments
                            :option: value
                            :option: another-value

                            body line
                            body line




Saturday, March 16, 13
.. name:: arguments
                            :option: value
                            :option: another-value

                            body line
                            body line




Saturday, March 16, 13
.. sqltable:: List of Users
         :connection_string: sqlite:///sampledata.db

                 select
                   name as 'Name',
                   email as 'E-mail'
                 from
                   users
                 order by
                   Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
         :connection_string: sqlite:///sampledata.db

                 select
                   name as 'Name',
                   email as 'E-mail'
                 from
                   users
                 order by
                   Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
         :connection_string: sqlite:///sampledata.db

                 select
                   name as 'Name',
                   email as 'E-mail'
                 from
                   users
                 order by
                   Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
         :connection_string: sqlite:///sampledata.db

                 select
                   name as 'Name',
                   email as 'E-mail'
                 from
                   users
                 order by
                   Name asc




Saturday, March 16, 13
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
from docutils.parsers.rst.directives.tables import Table

      class SQLTable(Table):

                option_spec = {'widths': directives.positive_int_list,
                               'class': directives.class_option,
                               'name': directives.unchanged,
                               'connection_string':directives.unchanged,
                               }

                def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

Saturday, March 16, 13   # Connect to the database
def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
Saturday, March 16, 13
def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
Saturday, March 16, 13
def run(self):
                    env = self.state.document.settings.env
                    app = env.app
                    config = app.config

                         # Make sure we have some content, which for now we
                         # assume is a query.
                         if not self.content:
                             error = self.state_machine.reporter.error(
                                 'No query in sqltable directive',
                                 nodes.literal_block(self.block_text,
                                                     self.block_text),
                                 line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
Saturday, March 16, 13
line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

Saturday, March 16, 13
                         # Build the node containing the table content
line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

Saturday, March 16, 13
                         # Build the node containing the table content
line=self.lineno)
                             return [error]

                         # Connect to the database
                         connection_string = self.options.get(
                             'connection_string',
                             config.sqltable_connection_string,
                             )
                         app.info('Connecting to %s' % connection_string)
                         engine = sqlalchemy.create_engine(connection_string)

                         # Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

Saturday, March 16, 13
                         # Build the node containing the table content
# Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
Saturday, March 16, 13
# Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
Saturday, March 16, 13
# Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
Saturday, March 16, 13
# Run the query
                         query = 'n'.join(self.content)
                         app.info('Running query %r' % query)
                         results = engine.execute(query)

                         # Extract some values we need for building the table.
                         table_headers = results.keys()
                         table_body = results
                         max_cols = len(table_headers)
                         max_header_cols = max_cols

                         # Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
Saturday, March 16, 13
# Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
Saturday, March 16, 13   row_node = nodes.row()
# Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
Saturday, March 16, 13   row_node = nodes.row()
# Handle the width settings and title
                         col_widths = self.get_column_widths(max_cols)
                         title, messages = self.make_title()

                         # Build the node containing the table content
                         table_node = self.build_table(table_body,
                                                        col_widths,
                                                        table_headers)
                         table_node['classes'] += self.options.get('class', [])
                         self.add_name(table_node)
                         if title:
                             table_node.insert(0, title)
                         return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
Saturday, March 16, 13   row_node = nodes.row()
Table Node Hierarchy




Saturday, March 16, 13
Table Node Hierarchy

                              table




Saturday, March 16, 13
Table Node Hierarchy

                              table

                              tgroup




Saturday, March 16, 13
Table Node Hierarchy

                                    table

                                    tgroup

                          colspec




Saturday, March 16, 13
Table Node Hierarchy

                                    table

                                    tgroup

                          colspec   thead




Saturday, March 16, 13
Table Node Hierarchy

                                    table

                                    tgroup

                          colspec   thead

                                    row




Saturday, March 16, 13
Table Node Hierarchy

                                    table

                                    tgroup

                          colspec   thead

                                    row


                                    entry



Saturday, March 16, 13
Table Node Hierarchy

                                      table

                                     tgroup

                          colspec     thead

                                      row


                                     entry


                                    paragraph
Saturday, March 16, 13
Table Node Hierarchy

                                      table

                                     tgroup

                          colspec     thead     tbody

                                      row


                                     entry


                                    paragraph
Saturday, March 16, 13
Table Node Hierarchy

                                      table

                                     tgroup

                          colspec     thead      tbody

                                      row         row


                                     entry       entry


                                    paragraph   paragraph
Saturday, March 16, 13
return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)    table
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()                              tgroup
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                 colspec
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.
                         tbody = nodes.tbody()
Saturday, March 16, 13
                         tgroup += tbody
return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)    table
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()                              tgroup
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                 colspec
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.
                         tbody = nodes.tbody()
Saturday, March 16, 13
                         tgroup += tbody
return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)    table
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()                              tgroup
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                 colspec
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.
                         tbody = nodes.tbody()
Saturday, March 16, 13
                         tgroup += tbody
return [table_node] + messages

                def build_table(self, table_data, col_widths, headers):
                    table = nodes.table()

                         # Set up the column specifications
                         # based on the widths.
                         tgroup = nodes.tgroup(cols=len(col_widths))
                         table += tgroup
                         tgroup.extend(nodes.colspec(colwidth=col_width)    table
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()                              tgroup
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                 colspec
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.
                         tbody = nodes.tbody()
Saturday, March 16, 13
                         tgroup += tbody
tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                   thead
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )
                                                                             row

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.     entry
                         tbody = nodes.tbody()
                         tgroup += tbody
                         rows = []
                         for row in table_data:                            paragraph
                             trow = nodes.row()
                             for cell in row:
                                 entry = nodes.entry()
                                 para = nodes.paragraph(
                                     text=unicode(cell))
                                 entry += para
Saturday, March 16, 13           trow += entry
tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                   thead
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )
                                                                             row

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.     entry
                         tbody = nodes.tbody()
                         tgroup += tbody
                         rows = []
                         for row in table_data:                            paragraph
                             trow = nodes.row()
                             for cell in row:
                                 entry = nodes.entry()
                                 para = nodes.paragraph(
                                     text=unicode(cell))
                                 entry += para
Saturday, March 16, 13           trow += entry
tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                   thead
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )
                                                                             row

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.     entry
                         tbody = nodes.tbody()
                         tgroup += tbody
                         rows = []
                         for row in table_data:                            paragraph
                             trow = nodes.row()
                             for cell in row:
                                 entry = nodes.entry()
                                 para = nodes.paragraph(
                                     text=unicode(cell))
                                 entry += para
Saturday, March 16, 13           trow += entry
tgroup.extend(nodes.colspec(colwidth=col_width)
                                       for col_width in col_widths)

                         # Set the headers
                         thead = nodes.thead()
                         tgroup += thead
                         row_node = nodes.row()
                         thead += row_node                                   thead
                         row_node.extend(
                             nodes.entry(h, nodes.paragraph(text=h))
                             for h in headers
                             )
                                                                             row

                         # The body of the table is made up of rows.
                         # Each row contains a series of entries,
                         # and each entry contains a paragraph of text.     entry
                         tbody = nodes.tbody()
                         tgroup += tbody
                         rows = []
                         for row in table_data:                            paragraph
                             trow = nodes.row()
                             for cell in row:
                                 entry = nodes.entry()
                                 para = nodes.paragraph(
                                     text=unicode(cell))
                                 entry += para
Saturday, March 16, 13           trow += entry
)

            # The body of the table is made up of rows.
            # Each row contains a series of entries,
            # and each entry contains a paragraph of text.
            tbody = nodes.tbody()
            tgroup += tbody
            rows = []                                                 tbody
            for row in table_data:
                trow = nodes.row()
                for cell in row:
                    entry = nodes.entry()                              row
                    para = nodes.paragraph(
                        text=unicode(cell))
                    entry += para
                    trow += entry                                     entry
                rows.append(trow)
            tbody.extend(rows)

            #print table                                             paragraph
            return table

      def setup(app):
                app.info('Initializing SQLTable')
                app.add_config_value('sqltable_connection_string',
                                     '',
Saturday, March 16, 13               'env')
)

            # The body of the table is made up of rows.
            # Each row contains a series of entries,
            # and each entry contains a paragraph of text.
            tbody = nodes.tbody()
            tgroup += tbody
            rows = []                                                 tbody
            for row in table_data:
                trow = nodes.row()
                for cell in row:
                    entry = nodes.entry()                              row
                    para = nodes.paragraph(
                        text=unicode(cell))
                    entry += para
                    trow += entry                                     entry
                rows.append(trow)
            tbody.extend(rows)

            #print table                                             paragraph
            return table

      def setup(app):
                app.info('Initializing SQLTable')
                app.add_config_value('sqltable_connection_string',
                                     '',
Saturday, March 16, 13               'env')
)

            # The body of the table is made up of rows.
            # Each row contains a series of entries,
            # and each entry contains a paragraph of text.
            tbody = nodes.tbody()
            tgroup += tbody
            rows = []                                                 tbody
            for row in table_data:
                trow = nodes.row()
                for cell in row:
                    entry = nodes.entry()                              row
                    para = nodes.paragraph(
                        text=unicode(cell))
                    entry += para
                    trow += entry                                     entry
                rows.append(trow)
            tbody.extend(rows)

            #print table                                             paragraph
            return table

      def setup(app):
                app.info('Initializing SQLTable')
                app.add_config_value('sqltable_connection_string',
                                     '',
Saturday, March 16, 13               'env')
)

            # The body of the table is made up of rows.
            # Each row contains a series of entries,
            # and each entry contains a paragraph of text.
            tbody = nodes.tbody()
            tgroup += tbody
            rows = []                                                 tbody
            for row in table_data:
                trow = nodes.row()
                for cell in row:
                    entry = nodes.entry()                              row
                    para = nodes.paragraph(
                        text=unicode(cell))
                    entry += para
                    trow += entry                                     entry
                rows.append(trow)
            tbody.extend(rows)

            #print table                                             paragraph
            return table

      def setup(app):
                app.info('Initializing SQLTable')
                app.add_config_value('sqltable_connection_string',
                                     '',
Saturday, March 16, 13               'env')
)

            # The body of the table is made up of rows.
            # Each row contains a series of entries,
            # and each entry contains a paragraph of text.
            tbody = nodes.tbody()
            tgroup += tbody
            rows = []                                                 tbody
            for row in table_data:
                trow = nodes.row()
                for cell in row:
                    entry = nodes.entry()                              row
                    para = nodes.paragraph(
                        text=unicode(cell))
                    entry += para
                    trow += entry                                     entry
                rows.append(trow)
            tbody.extend(rows)

            #print table                                             paragraph
            return table

      def setup(app):
                app.info('Initializing SQLTable')
                app.add_config_value('sqltable_connection_string',
                                     '',
Saturday, March 16, 13               'env')
.. sqltable:: List of Users
        :connection_string: sqlite:///sampledata.db

                select
                  name as 'Name',
                  email as 'E-mail'
                from
                  users
                order by
                  Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
        :connection_string: sqlite:///sampledata.db

                select
                  name as 'Name',
                  email as 'E-mail'
                from
                  users
                order by
                  Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
        :connection_string: sqlite:///sampledata.db

                select
                  name as 'Name',
                  email as 'E-mail'
                from
                  users
                order by
                  Name asc




Saturday, March 16, 13
.. sqltable:: List of Users
        :connection_string: sqlite:///sampledata.db

                select
                  name as 'Name',
                  email as 'E-mail'
                from
                  users
                order by
                  Name asc




Saturday, March 16, 13
Sphinx            Build      docutils     Sphinx
         Application     Environment    parser      Builder




                            .rst                  .pdf   .html




Saturday, March 16, 13
Saturday, March 16, 13
.rst




Saturday, March 16, 13
.rst




Saturday, March 16, 13
.rst   check




                                word
                                 list




Saturday, March 16, 13
.rst   check




                                word
                                 list




Saturday, March 16, 13
section

                         title             paragraph

                         #text    #text emphasis       #text   literal

                                             #text             #text




Saturday, March 16, 13
section

                         title             paragraph

                         #text    #text emphasis       #text   literal

                                             #text             #text




Saturday, March 16, 13
from sphinx.builders import Builder

      class SpellingBuilder(Builder):

                name = 'spelling'

                def init(self):
                    self.docnames = []
                    self.document_data = []

                         project_words = os.path.join(self.srcdir,
                             self.config.spelling_word_list_filename)

                         self.checker = SpellingChecker(
                             lang=self.config.spelling_lang,
                             suggest=self.config.spelling_show_suggestions,
                             word_list_filename=project_words,
                             )
                         self.output_filename = os.path.join(self.outdir,
                                                             'output.txt')
                         self.output = codecs.open(self.output_filename,
                                                   'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):
Saturday, March 16, 13
from sphinx.builders import Builder

      class SpellingBuilder(Builder):

                name = 'spelling'

                def init(self):
                    self.docnames = []
                    self.document_data = []

                         project_words = os.path.join(self.srcdir,
                             self.config.spelling_word_list_filename)

                         self.checker = SpellingChecker(
                             lang=self.config.spelling_lang,
                             suggest=self.config.spelling_show_suggestions,
                             word_list_filename=project_words,
                             )
                         self.output_filename = os.path.join(self.outdir,
                                                             'output.txt')
                         self.output = codecs.open(self.output_filename,
                                                   'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):
Saturday, March 16, 13
from sphinx.builders import Builder

      class SpellingBuilder(Builder):

                name = 'spelling'

                def init(self):
                    self.docnames = []
                    self.document_data = []

                         project_words = os.path.join(self.srcdir,
                             self.config.spelling_word_list_filename)

                         self.checker = SpellingChecker(
                             lang=self.config.spelling_lang,
                             suggest=self.config.spelling_show_suggestions,
                             word_list_filename=project_words,
                             )
                         self.output_filename = os.path.join(self.outdir,
                                                             'output.txt')
                         self.output = codecs.open(self.output_filename,
                                                   'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):
Saturday, March 16, 13
from sphinx.builders import Builder

      class SpellingBuilder(Builder):

                name = 'spelling'

                def init(self):
                    self.docnames = []
                    self.document_data = []

                         project_words = os.path.join(self.srcdir,
                             self.config.spelling_word_list_filename)

                         self.checker = SpellingChecker(
                             lang=self.config.spelling_lang,
                             suggest=self.config.spelling_show_suggestions,
                             word_list_filename=project_words,
                             )
                         self.output_filename = os.path.join(self.outdir,
                                                             'output.txt')
                         self.output = codecs.open(self.output_filename,
                                                   'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):
Saturday, March 16, 13
from sphinx.builders import Builder

      class SpellingBuilder(Builder):

                name = 'spelling'

                def init(self):
                    self.docnames = []
                    self.document_data = []

                         project_words = os.path.join(self.srcdir,
                             self.config.spelling_word_list_filename)

                         self.checker = SpellingChecker(
                             lang=self.config.spelling_lang,
                             suggest=self.config.spelling_show_suggestions,
                             word_list_filename=project_words,
                             )
                         self.output_filename = os.path.join(self.outdir,
                                                             'output.txt')
                         self.output = codecs.open(self.output_filename,
                                                   'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):
Saturday, March 16, 13
'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):

                         filename = self.env.doc2path(docname, base=None)

                         for node in doctree.traverse(docutils.nodes.Text):
                             if (node.tagname == '#text' and
                                 node.parent and
                                 node.parent.tagname in TEXT_NODES):

                                 # Determine the line number for this node
                                 lineno = get_line_number(node)

                                 # Check the text of the node.
                                 for word, suggestions in
                                     self.checker.check(node.astext()):

                                     msg_parts = [ docname ]
                                     if lineno:
                                         msg_parts.append(
                                             darkgreen('(line %3d)' % lineno)
                                             )
                                     msg_parts.append(red(word))
                                     msg_parts.append(
                                         self.format_suggestions(suggestions)
Saturday, March 16, 13                   )
'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):

                         filename = self.env.doc2path(docname, base=None)

                         for node in doctree.traverse(docutils.nodes.Text):
                             if (node.tagname == '#text' and
                                 node.parent and
                                 node.parent.tagname in TEXT_NODES):

                                 # Determine the line number for this node
                                 lineno = get_line_number(node)

                                 # Check the text of the node.
                                 for word, suggestions in
                                     self.checker.check(node.astext()):

                                     msg_parts = [ docname ]
                                     if lineno:
                                         msg_parts.append(
                                             darkgreen('(line %3d)' % lineno)
                                             )
                                     msg_parts.append(red(word))
                                     msg_parts.append(
                                         self.format_suggestions(suggestions)
Saturday, March 16, 13                   )
'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):

                         filename = self.env.doc2path(docname, base=None)

                         for node in doctree.traverse(docutils.nodes.Text):
                             if (node.tagname == '#text' and
                                 node.parent and
                                 node.parent.tagname in TEXT_NODES):

                                 # Determine the line number for this node
                                 lineno = get_line_number(node)

                                 # Check the text of the node.
                                 for word, suggestions in
                                     self.checker.check(node.astext()):

                                     msg_parts = [ docname ]
                                     if lineno:
                                         msg_parts.append(
                                             darkgreen('(line %3d)' % lineno)
                                             )
                                     msg_parts.append(red(word))
                                     msg_parts.append(
                                         self.format_suggestions(suggestions)
Saturday, March 16, 13                   )
'wt', encoding='UTF-8')

                def write_doc(self, docname, doctree):

                         filename = self.env.doc2path(docname, base=None)

                         for node in doctree.traverse(docutils.nodes.Text):
                             if (node.tagname == '#text' and
                                 node.parent and
                                 node.parent.tagname in TEXT_NODES):

                                 # Determine the line number for this node
                                 lineno = get_line_number(node)

                                 # Check the text of the node.
                                 for word, suggestions in
                                     self.checker.check(node.astext()):

                                     msg_parts = [ docname ]
                                     if lineno:
                                         msg_parts.append(
                                             darkgreen('(line %3d)' % lineno)
                                             )
                                     msg_parts.append(red(word))
                                     msg_parts.append(
                                         self.format_suggestions(suggestions)
Saturday, March 16, 13                   )
msg_parts = [ docname ]
                          if lineno:
                              msg_parts.append(
                                  darkgreen('(line %3d)' % lineno)
                                  )
                          msg_parts.append(red(word))
                          msg_parts.append(
                              self.format_suggestions(suggestions)
                              )
                          msg = ' '.join(msg_parts)
                          self.info(msg)
                          self.output.write(u"%s:%s: (%s) %sn" % (
                              self.env.doc2path(docname, None),
                              lineno, word,
                              self.format_suggestions(suggestions),
                              ))

                          # Found at least one bad spelling
                          self.app.statuscode = 1

            return

                def finish(self):
                       self.output.close()
                       self.info('Output written to %s' % self.output_filename)
Saturday, March 16, 13
                       return
msg_parts = [ docname ]
                          if lineno:
                              msg_parts.append(
                                  darkgreen('(line %3d)' % lineno)
                                  )
                          msg_parts.append(red(word))
                          msg_parts.append(
                              self.format_suggestions(suggestions)
                              )
                          msg = ' '.join(msg_parts)
                          self.info(msg)
                          self.output.write(u"%s:%s: (%s) %sn" % (
                              self.env.doc2path(docname, None),
                              lineno, word,
                              self.format_suggestions(suggestions),
                              ))

                          # Found at least one bad spelling
                          self.app.statuscode = 1

            return

                def finish(self):
                       self.output.close()
                       self.info('Output written to %s' % self.output_filename)
Saturday, March 16, 13
                       return
self.env.doc2path(docname, None),
                                     lineno, word,
                                     self.format_suggestions(suggestions),
                                     ))

                                  # Found at least one bad spelling
                                  self.app.statuscode = 1

                         return

                def finish(self):
                    self.output.close()
                    self.info('Output written to %s' % self.output_filename)
                    return

      def setup(app):
          app.info('Initializing Spelling Checker')
          app.add_builder(SpellingBuilder)
          return




Saturday, March 16, 13
self.env.doc2path(docname, None),
                                     lineno, word,
                                     self.format_suggestions(suggestions),
                                     ))

                                  # Found at least one bad spelling
                                  self.app.statuscode = 1

                         return

                def finish(self):
                    self.output.close()
                    self.info('Output written to %s' % self.output_filename)
                    return

      def setup(app):
          app.info('Initializing Spelling Checker')
          app.add_builder(SpellingBuilder)
          return




Saturday, March 16, 13
self.env.doc2path(docname, None),
                                     lineno, word,
                                     self.format_suggestions(suggestions),
                                     ))

                                  # Found at least one bad spelling
                                  self.app.statuscode = 1

                         return

                def finish(self):
                    self.output.close()
                    self.info('Output written to %s' % self.output_filename)
                    return

      def setup(app):
          app.info('Initializing Spelling Checker')
          app.add_builder(SpellingBuilder)
          return




Saturday, March 16, 13
$ sphinx-build -b spelling -d build/doctrees 
        source build/spelling

      Running Sphinx v1.1.2
      Initializing Spelling Checker
      loading reprint directive
      loading books directives
      loading pickled environment... done
      building [spelling]: all documents
      updating environment: 0 added, 0 changed, 0 removed
      looking for now-outdated files... none found
      preparing documents... done
      index (line 13) blarg ["blare", "blarney", "Blair", "blamer",
      "blazer", "blog"]
      writing output... [100%]
      Spelling checker messages written to /Users/dhellmann/Devel/
      website/website/build/spelling/output.txt
      build finished with problems.




Saturday, March 16, 13
$ sphinx-build -b spelling -d build/doctrees 
        source build/spelling

      Running Sphinx v1.1.2
      Initializing Spelling Checker
      loading reprint directive
      loading books directives
      loading pickled environment... done
      building [spelling]: all documents
      updating environment: 0 added, 0 changed, 0 removed
      looking for now-outdated files... none found
      preparing documents... done
      index (line 13) blarg ["blare", "blarney", "Blair", "blamer",
      "blazer", "blog"]
      writing output... [100%]
      Spelling checker messages written to /Users/dhellmann/Devel/
      website/website/build/spelling/output.txt
      build finished with problems.




Saturday, March 16, 13
$ sphinx-build -b spelling -d build/doctrees 
        source build/spelling

      Running Sphinx v1.1.2
      Initializing Spelling Checker
      loading reprint directive
      loading books directives
      loading pickled environment... done
      building [spelling]: all documents
      updating environment: 0 added, 0 changed, 0 removed
      looking for now-outdated files... none found
      preparing documents... done
      index (line 13) blarg ["blare", "blarney", "Blair", "blamer",
      "blazer", "blog"]
      writing output... [100%]
      Spelling checker messages written to /Users/dhellmann/Devel/
      website/website/build/spelling/output.txt
      build finished with problems.




Saturday, March 16, 13
Better Documentation Through Automation:
       Creating docutils & Sphinx Extensions

       Doug Hellmann
       @doughellmann
       PyCon 2013

            http://docutils.sourceforge.net/
            https://bitbucket.org/birkenfeld/sphinx-contrib/
            http://packages.python.org/pyenchant/
            http://doughellmann.com

Saturday, March 16, 13

Better Documentation Through Automation: Creating docutils & Sphinx Extensions

  • 1.
    Better Documentation ThroughAutomation: Creating docutils & Sphinx Extensions Doug Hellmann @doughellmann PyCon 2013 Saturday, March 16, 13
  • 2.
  • 3.
    Extensible Markup Language Saturday, March 16, 13
  • 4.
  • 5.
    Sphinx Application Saturday, March 16, 13
  • 6.
    Sphinx Build Application Environment .rst Saturday, March 16, 13
  • 7.
    Sphinx Build docutils Application Environment parser .rst Saturday, March 16, 13
  • 8.
    Sphinx Build docutils Sphinx Application Environment parser Builder .rst .pdf .html Saturday, March 16, 13
  • 9.
    section title paragraph #text #text emphasis #text literal #text #text Saturday, March 16, 13
  • 10.
    Lorem ipsum dolorsit amet, consectetur adipiscing elit. Aliquam vulputate elementum lectus a viverra. Vivamus hendrerit egestas lacinia. Proin tellus lectus, scelerisque vitae rutrum eget, ultrices vel metus. Quisque :ref:`target-name` pharetra lorem vehicula lorem posuere molestie cursus ipsum ornare. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas eu sapien at tellus suscipit aliquet :pep:`8` ut non tellus. Nulla facilisis bibendum dolor, quis mattis urna posuere eget. Nulla quis dui id augue faucibus varius. Nam eu leo quam. Fusce :term:`condimentum` placerat nisi nec vestibulum. Duis tortor sapien, commodo ac faucibus nec :rfc:`1822`, rutrum quis urna. Pellentesque cursus facilisis odio, id aliquam sem commodo vestibulum. Proin eget velit sed justo ultricies vulputate. Saturday, March 16, 13
  • 11.
    Lorem ipsum dolorsit amet, consectetur adipiscing elit. Aliquam vulputate elementum lectus a viverra. Vivamus hendrerit egestas lacinia. Proin tellus lectus, scelerisque vitae rutrum eget, ultrices vel metus. Quisque :ref:`target-name` pharetra lorem vehicula lorem posuere molestie cursus ipsum ornare. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas eu sapien at tellus suscipit aliquet :pep:`8` ut non tellus. Nulla facilisis bibendum dolor, quis mattis urna posuere eget. Nulla quis dui id augue faucibus varius. Nam eu leo quam. Fusce :term:`condimentum` placerat nisi nec vestibulum. Duis tortor sapien, commodo ac faucibus nec :rfc:`1822`, rutrum quis urna. Pellentesque cursus facilisis odio, id aliquam sem commodo vestibulum. Proin eget velit sed justo ultricies vulputate. Saturday, March 16, 13
  • 12.
    .. seealso:: PyEnchant_ Python interface to enchant_. :ref:`project-sphinxcontrib-spelling` Project home page for the spelling checker. sphinxcontrib_ BitBucket repository for sphinxcontrib-spelling and several other Sphinx extensions. .. include:: example.py :literal: :start-after: # end-of-header-comment .. image:: figure.png Saturday, March 16, 13
  • 13.
    2.6 - Fixed a problem with hook script line endings under Cygwin (`Issue 68 <https://bitbucket.org/dhellmann/ virtualenvwrapper/issue/68>`_). - Updated documentation to include a list of the compatible shells (:ref:`supported-shells`) and Python versions (:ref:`supported-versions`) (`Issue 70 <https:// bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_). - Fixed installation dependency on virtualenv (`Issue 60 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_). - Fixed the method for determining the Python version so it works under Python 2.4 (`Issue 61 <https://bitbucket.org/ dhellmann/virtualenvwrapper/issue/60>`_). - Converted the test infrastructure to use `tox <http://codespeak.net/tox/index.html>`_ instead of home- grown scripts in the Makefile. Saturday, March 16, 13
  • 14.
    2.6 - Fixed a problem with hook script line endings under Cygwin (`Issue 68 <https://bitbucket.org/dhellmann/ virtualenvwrapper/issue/68>`_). - Updated documentation to include a list of the compatible shells (:ref:`supported-shells`) and Python versions (:ref:`supported-versions`) (`Issue 70 <https:// bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_). - Fixed installation dependency on virtualenv (`Issue 60 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_). - Fixed the method for determining the Python version so it works under Python 2.4 (`Issue 61 <https://bitbucket.org/ dhellmann/virtualenvwrapper/issue/60>`_). - Converted the test infrastructure to use `tox <http://codespeak.net/tox/index.html>`_ instead of home- grown scripts in the Makefile. Saturday, March 16, 13
  • 15.
    2.6 - Fixed a problem with hook script line endings under Cygwin (`Issue 68 <https://bitbucket.org/dhellmann/ virtualenvwrapper/issue/68>`_). - Updated documentation to include a list of the compatible shells (:ref:`supported-shells`) and Python versions (:ref:`supported-versions`) (`Issue 70 <https:// bitbucket.org/dhellmann/virtualenvwrapper/issue/70>`_). - Fixed installation dependency on virtualenv (`Issue 60 <https://bitbucket.org/dhellmann/virtualenvwrapper/issue/60>`_). - Fixed the method for determining the Python version so it works under Python 2.4 (`Issue 61 <https://bitbucket.org/ dhellmann/virtualenvwrapper/issue/60>`_). - Converted the test infrastructure to use `tox <http://codespeak.net/tox/index.html>`_ instead of home- grown scripts in the Makefile. Saturday, March 16, 13
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 21.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 22.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 23.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 24.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 25.
    from docutils importnodes, utils from docutils.parsers.rst.roles import set_classes def bbissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): "Link to a BitBucket issue." try: issue_num = int(text) if issue_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( '"%s" is an invalid bug id.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: Saturday, March 16, 13
  • 26.
    app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError('bitbucket_project_url not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) Saturday, March 16, 13
  • 27.
    app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError('bitbucket_project_url not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) Saturday, March 16, 13
  • 28.
    app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError('bitbucket_project_url not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) Saturday, March 16, 13
  • 29.
    app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError('bitbucket_project_url not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) Saturday, March 16, 13
  • 30.
    app = inliner.document.settings.env.app node = make_link_node(rawtext, app, 'issue', text, options) return [node], [] def make_link_node(rawtext, app, type, slug, options): "Create a link to a BitBucket resource." try: base = app.config.bitbucket_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError('bitbucket_project_url not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) Saturday, March 16, 13
  • 31.
    node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) app.add_config_value('bitbucket_project_url', None, 'env') return Saturday, March 16, 13
  • 32.
    node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) app.add_config_value('bitbucket_project_url', None, 'env') return Saturday, March 16, 13
  • 33.
    node = nodes.reference(rawtext, type + ' ' + utils.unescape(slug), refuri=ref, **options) return node def setup(app): "Install the plugin." app.info('Initializing BitBucket plugin') app.add_role('bbissue', bbissue_role) app.add_config_value('bitbucket_project_url', None, 'env') return Saturday, March 16, 13
  • 34.
    2.6 - Fixed a problem with hook script line endings under Cygwin (:bbissue:`68`). - Updated documentation to include a list of the compatible shells (:ref:`supported-shells`) and Python versions (:ref:`supported-versions`) (:bbissue:`70`). - Fixed installation dependency on virtualenv (:bbissue:`60`). - Fixed the method for determining the Python version so it works under Python 2.4 (:bbissue:`61`). - Converted the test infrastructure to use `tox <http://codespeak.net/tox/index.html>`_ instead of home-grown scripts in the Makefile. Saturday, March 16, 13
  • 35.
    2.6 - Fixed a problem with hook script line endings under Cygwin (:bbissue:`68`). - Updated documentation to include a list of the compatible shells (:ref:`supported-shells`) and Python versions (:ref:`supported-versions`) (:bbissue:`70`). - Fixed installation dependency on virtualenv (:bbissue:`60`). - Fixed the method for determining the Python version so it works under Python 2.4 (:bbissue:`61`). - Converted the test infrastructure to use `tox <http://codespeak.net/tox/index.html>`_ instead of home-grown scripts in the Makefile. Saturday, March 16, 13
  • 36.
    2.6 • Fixed a problem with hook script line endings under Cygwin (issue 68). • Updated documentation to include a list of the compatible shells (Supported Shells) and Python versions (Python Versions) (issue 70). • Fixed installation dependency on virtualenv (issue 60). • Fixed the method for determining the Python version so it works under Python 2.4 (issue 61). • Converted the test infrastructure to use tox instead of home-grown scripts in the Makefile. Saturday, March 16, 13
  • 37.
    .. name:: arguments :option: value :option: another-value body line body line Saturday, March 16, 13
  • 38.
    .. name:: arguments :option: value :option: another-value body line body line Saturday, March 16, 13
  • 39.
    .. name:: arguments :option: value :option: another-value body line body line Saturday, March 16, 13
  • 40.
    .. name:: arguments :option: value :option: another-value body line body line Saturday, March 16, 13
  • 41.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 42.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 43.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 44.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 45.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 46.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 47.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 48.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 49.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 50.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 51.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 52.
    from docutils.parsers.rst.directives.tables importTable class SQLTable(Table): option_spec = {'widths': directives.positive_int_list, 'class': directives.class_option, 'name': directives.unchanged, 'connection_string':directives.unchanged, } def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] Saturday, March 16, 13 # Connect to the database
  • 53.
    def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) Saturday, March 16, 13
  • 54.
    def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) Saturday, March 16, 13
  • 55.
    def run(self): env = self.state.document.settings.env app = env.app config = app.config # Make sure we have some content, which for now we # assume is a query. if not self.content: error = self.state_machine.reporter.error( 'No query in sqltable directive', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) Saturday, March 16, 13
  • 56.
    line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() Saturday, March 16, 13 # Build the node containing the table content
  • 57.
    line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() Saturday, March 16, 13 # Build the node containing the table content
  • 58.
    line=self.lineno) return [error] # Connect to the database connection_string = self.options.get( 'connection_string', config.sqltable_connection_string, ) app.info('Connecting to %s' % connection_string) engine = sqlalchemy.create_engine(connection_string) # Run the query query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() Saturday, March 16, 13 # Build the node containing the table content
  • 59.
    # Run thequery query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): Saturday, March 16, 13
  • 60.
    # Run thequery query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): Saturday, March 16, 13
  • 61.
    # Run thequery query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): Saturday, March 16, 13
  • 62.
    # Run thequery query = 'n'.join(self.content) app.info('Running query %r' % query) results = engine.execute(query) # Extract some values we need for building the table. table_headers = results.keys() table_body = results max_cols = len(table_headers) max_header_cols = max_cols # Handle the width settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): Saturday, March 16, 13
  • 63.
    # Handle thewidth settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead Saturday, March 16, 13 row_node = nodes.row()
  • 64.
    # Handle thewidth settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead Saturday, March 16, 13 row_node = nodes.row()
  • 65.
    # Handle thewidth settings and title col_widths = self.get_column_widths(max_cols) title, messages = self.make_title() # Build the node containing the table content table_node = self.build_table(table_body, col_widths, table_headers) table_node['classes'] += self.options.get('class', []) self.add_name(table_node) if title: table_node.insert(0, title) return [table_node] + messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead Saturday, March 16, 13 row_node = nodes.row()
  • 66.
  • 67.
    Table Node Hierarchy table Saturday, March 16, 13
  • 68.
    Table Node Hierarchy table tgroup Saturday, March 16, 13
  • 69.
    Table Node Hierarchy table tgroup colspec Saturday, March 16, 13
  • 70.
    Table Node Hierarchy table tgroup colspec thead Saturday, March 16, 13
  • 71.
    Table Node Hierarchy table tgroup colspec thead row Saturday, March 16, 13
  • 72.
    Table Node Hierarchy table tgroup colspec thead row entry Saturday, March 16, 13
  • 73.
    Table Node Hierarchy table tgroup colspec thead row entry paragraph Saturday, March 16, 13
  • 74.
    Table Node Hierarchy table tgroup colspec thead tbody row entry paragraph Saturday, March 16, 13
  • 75.
    Table Node Hierarchy table tgroup colspec thead tbody row row entry entry paragraph paragraph Saturday, March 16, 13
  • 76.
    return [table_node] +messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) table for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup tgroup += thead row_node = nodes.row() thead += row_node colspec row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() Saturday, March 16, 13 tgroup += tbody
  • 77.
    return [table_node] +messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) table for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup tgroup += thead row_node = nodes.row() thead += row_node colspec row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() Saturday, March 16, 13 tgroup += tbody
  • 78.
    return [table_node] +messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) table for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup tgroup += thead row_node = nodes.row() thead += row_node colspec row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() Saturday, March 16, 13 tgroup += tbody
  • 79.
    return [table_node] +messages def build_table(self, table_data, col_widths, headers): table = nodes.table() # Set up the column specifications # based on the widths. tgroup = nodes.tgroup(cols=len(col_widths)) table += tgroup tgroup.extend(nodes.colspec(colwidth=col_width) table for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup tgroup += thead row_node = nodes.row() thead += row_node colspec row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() Saturday, March 16, 13 tgroup += tbody
  • 80.
    tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node thead row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) row # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. entry tbody = nodes.tbody() tgroup += tbody rows = [] for row in table_data: paragraph trow = nodes.row() for cell in row: entry = nodes.entry() para = nodes.paragraph( text=unicode(cell)) entry += para Saturday, March 16, 13 trow += entry
  • 81.
    tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node thead row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) row # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. entry tbody = nodes.tbody() tgroup += tbody rows = [] for row in table_data: paragraph trow = nodes.row() for cell in row: entry = nodes.entry() para = nodes.paragraph( text=unicode(cell)) entry += para Saturday, March 16, 13 trow += entry
  • 82.
    tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node thead row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) row # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. entry tbody = nodes.tbody() tgroup += tbody rows = [] for row in table_data: paragraph trow = nodes.row() for cell in row: entry = nodes.entry() para = nodes.paragraph( text=unicode(cell)) entry += para Saturday, March 16, 13 trow += entry
  • 83.
    tgroup.extend(nodes.colspec(colwidth=col_width) for col_width in col_widths) # Set the headers thead = nodes.thead() tgroup += thead row_node = nodes.row() thead += row_node thead row_node.extend( nodes.entry(h, nodes.paragraph(text=h)) for h in headers ) row # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. entry tbody = nodes.tbody() tgroup += tbody rows = [] for row in table_data: paragraph trow = nodes.row() for cell in row: entry = nodes.entry() para = nodes.paragraph( text=unicode(cell)) entry += para Saturday, March 16, 13 trow += entry
  • 84.
    ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() tgroup += tbody rows = [] tbody for row in table_data: trow = nodes.row() for cell in row: entry = nodes.entry() row para = nodes.paragraph( text=unicode(cell)) entry += para trow += entry entry rows.append(trow) tbody.extend(rows) #print table paragraph return table def setup(app): app.info('Initializing SQLTable') app.add_config_value('sqltable_connection_string', '', Saturday, March 16, 13 'env')
  • 85.
    ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() tgroup += tbody rows = [] tbody for row in table_data: trow = nodes.row() for cell in row: entry = nodes.entry() row para = nodes.paragraph( text=unicode(cell)) entry += para trow += entry entry rows.append(trow) tbody.extend(rows) #print table paragraph return table def setup(app): app.info('Initializing SQLTable') app.add_config_value('sqltable_connection_string', '', Saturday, March 16, 13 'env')
  • 86.
    ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() tgroup += tbody rows = [] tbody for row in table_data: trow = nodes.row() for cell in row: entry = nodes.entry() row para = nodes.paragraph( text=unicode(cell)) entry += para trow += entry entry rows.append(trow) tbody.extend(rows) #print table paragraph return table def setup(app): app.info('Initializing SQLTable') app.add_config_value('sqltable_connection_string', '', Saturday, March 16, 13 'env')
  • 87.
    ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() tgroup += tbody rows = [] tbody for row in table_data: trow = nodes.row() for cell in row: entry = nodes.entry() row para = nodes.paragraph( text=unicode(cell)) entry += para trow += entry entry rows.append(trow) tbody.extend(rows) #print table paragraph return table def setup(app): app.info('Initializing SQLTable') app.add_config_value('sqltable_connection_string', '', Saturday, March 16, 13 'env')
  • 88.
    ) # The body of the table is made up of rows. # Each row contains a series of entries, # and each entry contains a paragraph of text. tbody = nodes.tbody() tgroup += tbody rows = [] tbody for row in table_data: trow = nodes.row() for cell in row: entry = nodes.entry() row para = nodes.paragraph( text=unicode(cell)) entry += para trow += entry entry rows.append(trow) tbody.extend(rows) #print table paragraph return table def setup(app): app.info('Initializing SQLTable') app.add_config_value('sqltable_connection_string', '', Saturday, March 16, 13 'env')
  • 89.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 90.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 91.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 92.
    .. sqltable:: Listof Users :connection_string: sqlite:///sampledata.db select name as 'Name', email as 'E-mail' from users order by Name asc Saturday, March 16, 13
  • 93.
    Sphinx Build docutils Sphinx Application Environment parser Builder .rst .pdf .html Saturday, March 16, 13
  • 94.
  • 95.
  • 96.
  • 97.
    .rst check word list Saturday, March 16, 13
  • 98.
    .rst check word list Saturday, March 16, 13
  • 99.
    section title paragraph #text #text emphasis #text literal #text #text Saturday, March 16, 13
  • 100.
    section title paragraph #text #text emphasis #text literal #text #text Saturday, March 16, 13
  • 101.
    from sphinx.builders importBuilder class SpellingBuilder(Builder): name = 'spelling' def init(self): self.docnames = [] self.document_data = [] project_words = os.path.join(self.srcdir, self.config.spelling_word_list_filename) self.checker = SpellingChecker( lang=self.config.spelling_lang, suggest=self.config.spelling_show_suggestions, word_list_filename=project_words, ) self.output_filename = os.path.join(self.outdir, 'output.txt') self.output = codecs.open(self.output_filename, 'wt', encoding='UTF-8') def write_doc(self, docname, doctree): Saturday, March 16, 13
  • 102.
    from sphinx.builders importBuilder class SpellingBuilder(Builder): name = 'spelling' def init(self): self.docnames = [] self.document_data = [] project_words = os.path.join(self.srcdir, self.config.spelling_word_list_filename) self.checker = SpellingChecker( lang=self.config.spelling_lang, suggest=self.config.spelling_show_suggestions, word_list_filename=project_words, ) self.output_filename = os.path.join(self.outdir, 'output.txt') self.output = codecs.open(self.output_filename, 'wt', encoding='UTF-8') def write_doc(self, docname, doctree): Saturday, March 16, 13
  • 103.
    from sphinx.builders importBuilder class SpellingBuilder(Builder): name = 'spelling' def init(self): self.docnames = [] self.document_data = [] project_words = os.path.join(self.srcdir, self.config.spelling_word_list_filename) self.checker = SpellingChecker( lang=self.config.spelling_lang, suggest=self.config.spelling_show_suggestions, word_list_filename=project_words, ) self.output_filename = os.path.join(self.outdir, 'output.txt') self.output = codecs.open(self.output_filename, 'wt', encoding='UTF-8') def write_doc(self, docname, doctree): Saturday, March 16, 13
  • 104.
    from sphinx.builders importBuilder class SpellingBuilder(Builder): name = 'spelling' def init(self): self.docnames = [] self.document_data = [] project_words = os.path.join(self.srcdir, self.config.spelling_word_list_filename) self.checker = SpellingChecker( lang=self.config.spelling_lang, suggest=self.config.spelling_show_suggestions, word_list_filename=project_words, ) self.output_filename = os.path.join(self.outdir, 'output.txt') self.output = codecs.open(self.output_filename, 'wt', encoding='UTF-8') def write_doc(self, docname, doctree): Saturday, March 16, 13
  • 105.
    from sphinx.builders importBuilder class SpellingBuilder(Builder): name = 'spelling' def init(self): self.docnames = [] self.document_data = [] project_words = os.path.join(self.srcdir, self.config.spelling_word_list_filename) self.checker = SpellingChecker( lang=self.config.spelling_lang, suggest=self.config.spelling_show_suggestions, word_list_filename=project_words, ) self.output_filename = os.path.join(self.outdir, 'output.txt') self.output = codecs.open(self.output_filename, 'wt', encoding='UTF-8') def write_doc(self, docname, doctree): Saturday, March 16, 13
  • 106.
    'wt', encoding='UTF-8') def write_doc(self, docname, doctree): filename = self.env.doc2path(docname, base=None) for node in doctree.traverse(docutils.nodes.Text): if (node.tagname == '#text' and node.parent and node.parent.tagname in TEXT_NODES): # Determine the line number for this node lineno = get_line_number(node) # Check the text of the node. for word, suggestions in self.checker.check(node.astext()): msg_parts = [ docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) Saturday, March 16, 13 )
  • 107.
    'wt', encoding='UTF-8') def write_doc(self, docname, doctree): filename = self.env.doc2path(docname, base=None) for node in doctree.traverse(docutils.nodes.Text): if (node.tagname == '#text' and node.parent and node.parent.tagname in TEXT_NODES): # Determine the line number for this node lineno = get_line_number(node) # Check the text of the node. for word, suggestions in self.checker.check(node.astext()): msg_parts = [ docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) Saturday, March 16, 13 )
  • 108.
    'wt', encoding='UTF-8') def write_doc(self, docname, doctree): filename = self.env.doc2path(docname, base=None) for node in doctree.traverse(docutils.nodes.Text): if (node.tagname == '#text' and node.parent and node.parent.tagname in TEXT_NODES): # Determine the line number for this node lineno = get_line_number(node) # Check the text of the node. for word, suggestions in self.checker.check(node.astext()): msg_parts = [ docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) Saturday, March 16, 13 )
  • 109.
    'wt', encoding='UTF-8') def write_doc(self, docname, doctree): filename = self.env.doc2path(docname, base=None) for node in doctree.traverse(docutils.nodes.Text): if (node.tagname == '#text' and node.parent and node.parent.tagname in TEXT_NODES): # Determine the line number for this node lineno = get_line_number(node) # Check the text of the node. for word, suggestions in self.checker.check(node.astext()): msg_parts = [ docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) Saturday, March 16, 13 )
  • 110.
    msg_parts = [docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) ) msg = ' '.join(msg_parts) self.info(msg) self.output.write(u"%s:%s: (%s) %sn" % ( self.env.doc2path(docname, None), lineno, word, self.format_suggestions(suggestions), )) # Found at least one bad spelling self.app.statuscode = 1 return def finish(self): self.output.close() self.info('Output written to %s' % self.output_filename) Saturday, March 16, 13 return
  • 111.
    msg_parts = [docname ] if lineno: msg_parts.append( darkgreen('(line %3d)' % lineno) ) msg_parts.append(red(word)) msg_parts.append( self.format_suggestions(suggestions) ) msg = ' '.join(msg_parts) self.info(msg) self.output.write(u"%s:%s: (%s) %sn" % ( self.env.doc2path(docname, None), lineno, word, self.format_suggestions(suggestions), )) # Found at least one bad spelling self.app.statuscode = 1 return def finish(self): self.output.close() self.info('Output written to %s' % self.output_filename) Saturday, March 16, 13 return
  • 112.
    self.env.doc2path(docname, None), lineno, word, self.format_suggestions(suggestions), )) # Found at least one bad spelling self.app.statuscode = 1 return def finish(self): self.output.close() self.info('Output written to %s' % self.output_filename) return def setup(app): app.info('Initializing Spelling Checker') app.add_builder(SpellingBuilder) return Saturday, March 16, 13
  • 113.
    self.env.doc2path(docname, None), lineno, word, self.format_suggestions(suggestions), )) # Found at least one bad spelling self.app.statuscode = 1 return def finish(self): self.output.close() self.info('Output written to %s' % self.output_filename) return def setup(app): app.info('Initializing Spelling Checker') app.add_builder(SpellingBuilder) return Saturday, March 16, 13
  • 114.
    self.env.doc2path(docname, None), lineno, word, self.format_suggestions(suggestions), )) # Found at least one bad spelling self.app.statuscode = 1 return def finish(self): self.output.close() self.info('Output written to %s' % self.output_filename) return def setup(app): app.info('Initializing Spelling Checker') app.add_builder(SpellingBuilder) return Saturday, March 16, 13
  • 115.
    $ sphinx-build -bspelling -d build/doctrees source build/spelling Running Sphinx v1.1.2 Initializing Spelling Checker loading reprint directive loading books directives loading pickled environment... done building [spelling]: all documents updating environment: 0 added, 0 changed, 0 removed looking for now-outdated files... none found preparing documents... done index (line 13) blarg ["blare", "blarney", "Blair", "blamer", "blazer", "blog"] writing output... [100%] Spelling checker messages written to /Users/dhellmann/Devel/ website/website/build/spelling/output.txt build finished with problems. Saturday, March 16, 13
  • 116.
    $ sphinx-build -bspelling -d build/doctrees source build/spelling Running Sphinx v1.1.2 Initializing Spelling Checker loading reprint directive loading books directives loading pickled environment... done building [spelling]: all documents updating environment: 0 added, 0 changed, 0 removed looking for now-outdated files... none found preparing documents... done index (line 13) blarg ["blare", "blarney", "Blair", "blamer", "blazer", "blog"] writing output... [100%] Spelling checker messages written to /Users/dhellmann/Devel/ website/website/build/spelling/output.txt build finished with problems. Saturday, March 16, 13
  • 117.
    $ sphinx-build -bspelling -d build/doctrees source build/spelling Running Sphinx v1.1.2 Initializing Spelling Checker loading reprint directive loading books directives loading pickled environment... done building [spelling]: all documents updating environment: 0 added, 0 changed, 0 removed looking for now-outdated files... none found preparing documents... done index (line 13) blarg ["blare", "blarney", "Blair", "blamer", "blazer", "blog"] writing output... [100%] Spelling checker messages written to /Users/dhellmann/Devel/ website/website/build/spelling/output.txt build finished with problems. Saturday, March 16, 13
  • 118.
    Better Documentation ThroughAutomation: Creating docutils & Sphinx Extensions Doug Hellmann @doughellmann PyCon 2013 http://docutils.sourceforge.net/ https://bitbucket.org/birkenfeld/sphinx-contrib/ http://packages.python.org/pyenchant/ http://doughellmann.com Saturday, March 16, 13