summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndi Albrecht <albrecht.andi@gmail.com>2009-04-07 19:29:38 +0200
committerAndi Albrecht <albrecht.andi@gmail.com>2009-04-07 19:29:38 +0200
commite6ac0d076e3de6a3e24bba00e49f733d7f69fda6 (patch)
tree25c80a5cc9ca7a41a5a890e7c4171c42403ea65c
parent882205e8345ddacbbc0e59bc092f43e7e1f5d2cf (diff)
parent55410fc4c2e8163f0e89d14652b267ea5765e30c (diff)
downloadsqlparse-e6ac0d076e3de6a3e24bba00e49f733d7f69fda6.tar.gz
Merged docs branch.
-rw-r--r--.hgignore2
-rw-r--r--docs/agogo/layout.html237
-rw-r--r--docs/agogo/static/agogo.css_t328
-rw-r--r--docs/agogo/static/bgfooter.png (renamed from docs/tango/static/bgfooter.png)bin434 -> 434 bytes
-rw-r--r--docs/agogo/static/bgtop.png (renamed from docs/tango/static/bgtop.png)bin430 -> 430 bytes
-rw-r--r--docs/agogo/theme.conf18
-rw-r--r--docs/source/analyzing.rst64
-rw-r--r--docs/source/api.rst33
-rw-r--r--docs/source/cmdline.rst8
-rw-r--r--docs/source/conf.py4
-rw-r--r--docs/source/index.rst9
-rw-r--r--docs/source/intro.rst108
-rw-r--r--docs/source/ui.rst15
-rw-r--r--docs/tango/static/default.css_t90
-rw-r--r--docs/tango/theme.conf28
-rw-r--r--sqlparse/__init__.py11
-rw-r--r--sqlparse/sql.py96
17 files changed, 880 insertions, 171 deletions
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..2f3bba6
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,2 @@
+syntax: glob
+docs/build \ No newline at end of file
diff --git a/docs/agogo/layout.html b/docs/agogo/layout.html
new file mode 100644
index 0000000..2a6989c
--- /dev/null
+++ b/docs/agogo/layout.html
@@ -0,0 +1,237 @@
+{%- block doctype -%}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+{%- endblock %}
+{%- set reldelim1 = reldelim1 is not defined and ' &raquo;' or reldelim1 %}
+{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
+
+{%- macro relbar() %}
+ <div class="related">
+ <h3>{{ _('Navigation') }}</h3>
+ <ul>
+ {%- for rellink in rellinks %}
+ <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags }}"
+ {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+ {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
+ {%- endfor %}
+ {%- block rootrellink %}
+ <li><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
+ {%- endblock %}
+ {%- for parent in parents %}
+ <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
+ {%- endfor %}
+ {%- block relbaritems %} {% endblock %}
+ </ul>
+ </div>
+ {%- endmacro %}
+
+ {%- macro sidebar() %}
+ {%- if not embedded %}{% if not theme_nosidebar|tobool %}
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ {%- block sidebarlogo %}
+ {%- if logo %}
+ <p class="logo"><a href="{{ pathto(master_doc) }}">
+ <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
+ </a></p>
+ {%- endif %}
+ {%- endblock %}
+ {%- block sidebartoc %}
+ {%- if display_toc %}
+ <h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
+ {{ toc }}
+ {%- endif %}
+ {%- endblock %}
+ {%- block sidebarrel %}
+ {%- if prev %}
+ <h4>{{ _('Previous topic') }}</h4>
+ <p class="topless"><a href="{{ prev.link|e }}"
+ title="{{ _('previous chapter') }}">{{ prev.title }}</a></p>
+ {%- endif %}
+ {%- if next %}
+ <h4>{{ _('Next topic') }}</h4>
+ <p class="topless"><a href="{{ next.link|e }}"
+ title="{{ _('next chapter') }}">{{ next.title }}</a></p>
+ {%- endif %}
+ {%- endblock %}
+ {%- block sidebarsourcelink %}
+ {%- if show_source and has_source and sourcename %}
+ <h3>{{ _('This Page') }}</h3>
+ <ul class="this-page-menu">
+ <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
+ rel="nofollow">{{ _('Show Source') }}</a></li>
+ </ul>
+ {%- endif %}
+ {%- endblock %}
+ {%- if customsidebar %}
+ {% include customsidebar %}
+ {%- endif %}
+ {%- block sidebarsearch %}
+ {%- if pagename != "search" %}
+ <div id="searchbox" style="display: none">
+ <h3>{{ _('Quick search') }}</h3>
+ <form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="{{ _('Go') }}" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ {{ _('Enter search terms or a module, class or function name.') }}
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ {%- endif %}
+ {%- endblock %}
+ </div>
+ </div>
+ {%- endif %}{% endif %}
+ {%- endmacro %}
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ {{ metatags }}
+ {%- if not embedded %}
+ {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
+ {%- else %}
+ {%- set titlesuffix = "" %}
+ {%- endif %}
+ <title>{{ title|striptags }}{{ titlesuffix }}</title>
+ <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+ <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
+ {%- if not embedded %}
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '{{ pathto("", 1) }}',
+ VERSION: '{{ release|e }}',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '{{ file_suffix }}',
+ HAS_SOURCE: {{ has_source|lower }}
+ };
+ </script>
+ {%- for scriptfile in script_files %}
+ <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
+ {%- endfor %}
+ {%- if use_opensearch %}
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
+ href="{{ pathto('_static/opensearch.xml', 1) }}"/>
+ {%- endif %}
+ {%- if favicon %}
+ <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
+ {%- endif %}
+ {%- endif %}
+ {%- block linktags %}
+ {%- if hasdoc('about') %}
+ <link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
+ {%- endif %}
+ {%- if hasdoc('genindex') %}
+ <link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
+ {%- endif %}
+ {%- if hasdoc('search') %}
+ <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
+ {%- endif %}
+ {%- if hasdoc('copyright') %}
+ <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
+ {%- endif %}
+ <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
+ {%- if parents %}
+ <link rel="up" title="{{ parents[-1].title|striptags }}" href="{{ parents[-1].link|e }}" />
+ {%- endif %}
+ {%- if next %}
+ <link rel="next" title="{{ next.title|striptags }}" href="{{ next.link|e }}" />
+ {%- endif %}
+ {%- if prev %}
+ <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}" />
+ {%- endif %}
+ {%- endblock %}
+ {%- block extrahead %} {% endblock %}
+ </head>
+ <body>
+
+ <div class="header-wrapper">
+ <div class="header">
+ <h1><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a></h1>
+ <div class="rel">
+ {%- for rellink in rellinks %}
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags }}"
+ {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+ {%- if not loop.last %}{{ reldelim2 }}{% endif %}
+ {%- endfor %}
+ </div>
+ </div>
+ </div>
+
+ <div class="content-wrapper">
+ <div class="content">
+ <div class="document">
+ {%- block document %}
+ <div class="documentwrapper">
+ {%- if not embedded %}{% if not theme_nosidebar|tobool %}
+ <div class="bodywrapper">
+ {%- endif %}{% endif %}
+ <div class="body">
+ {% block body %} {% endblock %}
+ </div>
+ {%- if not embedded %}{% if not theme_nosidebar|tobool %}
+ </div>
+ {%- endif %}{% endif %}
+ </div>
+ {%- endblock %}
+ </div>
+ <div class="sidebar">
+ <h3>{{ _('Contents') }}</h3>
+ {{ toctree() }}
+ <h3 style="margin-top: 1.5em;">{{ _('Search') }}</h3>
+ <form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="{{ _('Go') }}" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ {{ _('Enter search terms or a module, class or function name.') }}
+ </p>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ </div>
+
+ <div class="footer-wrapper">
+ {%- block footer %}
+ <div class="footer">
+ <div class="left">
+ {%- for rellink in rellinks %}
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags }}"
+ {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+ {%- if not loop.last %}{{ reldelim2 }}{% endif %}
+ {%- endfor %}
+ {%- if show_source and has_source and sourcename %}
+ <br/>
+ <a href="{{ pathto('_sources/' + sourcename, true)|e }}"
+ rel="nofollow">{{ _('Show Source') }}</a>
+ {%- endif %}
+ </div>
+
+ <div class="right">
+ {%- if hasdoc('copyright') %}
+ {% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
+ {%- else %}
+ {% trans copyright=copyright|e %}&copy; Copyright {{ copyright }}.{% endtrans %}
+ {%- endif %}
+ {%- if last_updated %}
+ {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
+ {%- endif %}
+ {%- if show_sphinx %}<br/>
+ {% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
+ {%- endif %}
+ </div>
+ <div class="clearer"></div>
+ </div>
+ {%- endblock %}
+ </div>
+
+ </body>
+</html>
diff --git a/docs/agogo/static/agogo.css_t b/docs/agogo/static/agogo.css_t
new file mode 100644
index 0000000..97dc91b
--- /dev/null
+++ b/docs/agogo/static/agogo.css_t
@@ -0,0 +1,328 @@
+* {
+ margin: 0px;
+ padding: 0px;
+}
+
+body {
+ font-family: {{ theme_bodyfont }};
+ line-height: 1.4em;
+ font-size: 14px;
+ color: black;
+ background-color: {{ theme_bgcolor }};
+}
+
+
+/* Page layout */
+
+div.header, div.content, div.footer {
+ width: {{ theme_pagewidth }};
+ margin-left: auto;
+ margin-right: auto;
+}
+
+div.header-wrapper {
+ background: {{ theme_headerbg }};
+ border-bottom: 3px solid #2e3436;
+}
+
+
+/* Default body styles */
+a {
+ text-decoration: none;
+ color: {{ theme_linkcolor }};
+}
+
+.clearer {
+ clear: both;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+h1, h2, h3, h4 {
+ font-family: {{ theme_headerfont }};
+ font-weight: normal;
+ color: {{ theme_headercolor2 }};
+ margin-bottom: .8em;
+}
+
+h1 {
+ color: {{ theme_headercolor1 }};
+}
+
+h2 {
+ padding-bottom: .5em;
+ border-bottom: 1px solid {{ theme_headercolor2 }};
+}
+
+a.headerlink {
+ visibility: hidden;
+ color: #dddddd;
+ padding-left: .3em;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+
+
+/* Header */
+
+div.header {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+div.header h1 {
+ font-family: {{ theme_headerfont }};
+ font-weight: normal;
+ font-size: 160%;
+ letter-spacing: .08em;
+}
+
+div.header h1 a {
+ color: white;
+}
+
+div.header div.rel {
+ margin-top: 1em;
+}
+
+div.header div.rel a {
+ color: {{ theme_headerlinkcolor }};
+ letter-spacing: .1em;
+ text-transform: uppercase;
+}
+
+
+/* Content */
+div.content-wrapper {
+ background-color: white;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+
+div.document {
+ width: {{ theme_documentwidth }};
+ float: left;
+}
+
+div.body {
+ padding-right: 2em;
+ text-align: justify;
+}
+
+div.document ul {
+ margin-left: 1.2em;
+ list-style-type: square;
+}
+
+div.document dd {
+ margin-left: 1.2em;
+ margin-top: .4em;
+ margin-bottom: 1em;
+}
+
+div.document .section {
+ margin-top: 1.7em;
+}
+div.document .section:first-child {
+ margin-top: 0px;
+}
+
+div.document div.highlight {
+ padding: 3px;
+ background-color: #eeeeec;
+ border-top: 2px solid #dddddd;
+ border-bottom: 2px solid #dddddd;
+ margin-top: .8em;
+ margin-bottom: .8em;
+}
+
+div.document h2 {
+ margin-top: .7em;
+}
+
+div.document p {
+ margin-bottom: .5em;
+}
+
+div.document li.toctree-l1 {
+ margin-bottom: 1em;
+}
+
+div.document .descname {
+ font-weight: bold;
+}
+
+div.document .docutils.literal {
+ background-color: #eeeeec;
+ padding: 1px;
+}
+
+div.document .docutils.xref.literal {
+ background-color: transparent;
+ padding: 0px;
+}
+
+
+/* Sidebar */
+
+div.sidebar {
+ width: {{ theme_sidebarwidth }};
+ float: right;
+ font-size: .9em;
+}
+
+div.sidebar h3 {
+ color: #2e3436;
+ text-transform: uppercase;
+ font-size: 130%;
+ letter-spacing: .1em;
+}
+
+div.sidebar ul {
+ list-style-type: none;
+}
+
+div.sidebar li.toctree-l1 a {
+ display: block;
+ padding: 1px;
+ border: 1px solid #dddddd;
+ background-color: #eeeeec;
+ margin-bottom: .4em;
+ padding-left: 3px;
+ color: #2e3436;
+}
+
+div.sidebar li.toctree-l2 a {
+ background-color: transparent;
+ border: none;
+ border-bottom: 1px solid #dddddd;
+}
+
+div.sidebar li.toctree-l2:last-child a {
+ border-bottom: none;
+}
+
+div.sidebar li.toctree-l1.current a {
+ border-right: 5px solid {{ theme_headerlinkcolor }};
+}
+
+div.sidebar li.toctree-l1.current li.toctree-l2 a {
+ border-right: none;
+}
+
+
+/* Footer */
+
+div.footer-wrapper {
+ background: {{ theme_footerbg }};
+ border-top: 4px solid #babdb6;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ min-height: 80px;
+}
+
+div.footer, div.footer a {
+ color: #888a85;
+}
+
+div.footer .right {
+ text-align: right;
+}
+
+div.footer .left {
+ text-transform: uppercase;
+}
+
+
+/* Styles copied form basic theme */
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
diff --git a/docs/tango/static/bgfooter.png b/docs/agogo/static/bgfooter.png
index 9ce5bdd..9ce5bdd 100644
--- a/docs/tango/static/bgfooter.png
+++ b/docs/agogo/static/bgfooter.png
Binary files differ
diff --git a/docs/tango/static/bgtop.png b/docs/agogo/static/bgtop.png
index a0d4709..a0d4709 100644
--- a/docs/tango/static/bgtop.png
+++ b/docs/agogo/static/bgtop.png
Binary files differ
diff --git a/docs/agogo/theme.conf b/docs/agogo/theme.conf
new file mode 100644
index 0000000..9cdac5d
--- /dev/null
+++ b/docs/agogo/theme.conf
@@ -0,0 +1,18 @@
+[theme]
+inherit = basic
+stylesheet = agogo.css
+pygments_style = tango
+
+[options]
+bodyfont = "Verdana", Arial, sans-serif
+headerfont = "Georgia", "Times New Roman", serif
+pagewidth = 70em
+documentwidth = 50em
+sidebarwidth = 20em
+bgcolor = #eeeeec
+headerbg = url(bgtop.png) top left repeat-x
+footerbg = url(bgfooter.png) top left repeat-x
+linkcolor = #ce5c00
+headercolor1 = #204a87
+headercolor2 = #3465a4
+headerlinkcolor = #fcaf3e \ No newline at end of file
diff --git a/docs/source/analyzing.rst b/docs/source/analyzing.rst
new file mode 100644
index 0000000..07b1fe9
--- /dev/null
+++ b/docs/source/analyzing.rst
@@ -0,0 +1,64 @@
+.. _analyze:
+
+Analyzing the Parsed Statement
+==============================
+
+When the :meth:`~sqlparse.parse` function is called the returned value
+is a tree-ish representation of the analyzed statements. The returned
+objects can be used by applications to retrieve further information about
+the parsed SQL.
+
+
+Base Classes
+------------
+
+All returned objects inherit from these base classes.
+The :class:`~sqlparse.sql.Token` class represents a single token and
+:class:`~sqlparse.sql.TokenList` class is a group of tokens.
+The latter provides methods for inspecting it's child tokens.
+
+.. autoclass:: sqlparse.sql.Token
+ :members:
+
+.. autoclass:: sqlparse.sql.TokenList
+ :members:
+
+
+SQL Representing Classes
+------------------------
+
+The following classes represent distinct parts of a SQL statement.
+
+.. autoclass:: sqlparse.sql.Statement
+ :members:
+
+.. autoclass:: sqlparse.sql.Comment
+ :members:
+
+.. autoclass:: sqlparse.sql.Identifier
+ :members:
+
+.. autoclass:: sqlparse.sql.IdentifierList
+ :members:
+
+.. autoclass:: sqlparse.sql.Where
+ :members:
+
+.. autoclass:: sqlparse.sql.Case
+ :members:
+
+.. autoclass:: sqlparse.sql.Parenthesis
+ :members:
+
+.. autoclass:: sqlparse.sql.If
+ :members:
+
+.. autoclass:: sqlparse.sql.For
+ :members:
+
+.. autoclass:: sqlparse.sql.Assignment
+ :members:
+
+.. autoclass:: sqlparse.sql.Comparsion
+ :members:
+
diff --git a/docs/source/api.rst b/docs/source/api.rst
index 3bce389..2531c9b 100644
--- a/docs/source/api.rst
+++ b/docs/source/api.rst
@@ -1,6 +1,9 @@
:mod:`sqlparse` -- Parse SQL statements
=======================================
+.. module:: sqlparse
+ :synopsis: Parse SQL statements.
+
The :mod:`sqlparse` module provides the following functions on module-level.
.. autofunction:: sqlparse.split
@@ -10,3 +13,33 @@ The :mod:`sqlparse` module provides the following functions on module-level.
.. autofunction:: sqlparse.parse
+.. _formatting:
+
+Formatting of SQL Statements
+----------------------------
+
+The :meth:`~sqlparse.format` function accepts the following keyword arguments.
+
+``keyword_case``
+ Changes how keywords are formatted. Allowed values are "upper", "lower"
+ and "capitalize".
+
+``identifier_case``
+ Changes how identifiers are formatted. Allowed values are "upper", "lower",
+ and "capitalize".
+
+``strip_comments``
+ If ``True`` comments are removed from the statements.
+
+``reindent``
+ If ``True`` the indentations of the statements are changed.
+
+``indent_tabs``
+ If ``True`` tabs instead of spaces are used for indentation.
+
+``indent_width``
+ The width of the indentation, defaults to 2.
+
+``output_format``
+ If given the output is additionally formatted to be used as a variable
+ in a programming language. Allowed values are "python" and "php".
diff --git a/docs/source/cmdline.rst b/docs/source/cmdline.rst
deleted file mode 100644
index 93a35a7..0000000
--- a/docs/source/cmdline.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-``sqlformat`` -- Command Line Script
-===========================================
-
-The :mod:`sqlparse` module is shipped with the script
-:program:`sqlformat` which provides a command line interface to the formatting
-functions.
-
-.. todo:: Describe options and example usage.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index b84245a..63e1b90 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -83,7 +83,7 @@ exclude_trees = []
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = 'tango'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
@@ -93,7 +93,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
-html_theme = 'sphinxdoc'
+html_theme = 'agogo'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 40e99e0..44d03a2 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -3,17 +3,16 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-Welcome to python-sqlparse's documentation!
-===========================================
-
-Contents:
+python-sqlparse's documentation contents
+========================================
.. toctree::
:maxdepth: 2
intro
api
- cmdline
+ analyzing
+ ui
changes
diff --git a/docs/source/intro.rst b/docs/source/intro.rst
index 3d7a888..931659f 100644
--- a/docs/source/intro.rst
+++ b/docs/source/intro.rst
@@ -2,44 +2,58 @@ Introduction
============
:mod:`sqlparse` is a non-validating SQL parser for Python.
-
It provides support for parsing, splitting and formatting SQL statements.
-
-:mod:`sqlparse` is released under the terms of the
+The module is released under the terms of the
`New BSD license <http://www.opensource.org/licenses/bsd-license.php>`_.
-Visit http://sqlformat.appspot.com to try it's formatting features.
+Visit the project page at http://python-sqlparse.googlecode.com for
+further information about this project.
Download & Installation
-----------------------
-To download and install :mod:`sqlparse` on your system run the following
-commands:
+The latest released version can be obtained from the
+`downloads page <http://code.google.com/p/python-sqlparse/downloads/list>`_
+on the project's website. To extract the source archive and to install
+the module on your system run
.. code-block:: bash
- $ git clone git://github.com/andialbrecht/python-sqlparse.git
- $ cd python-sqlparse.git/
- $ sudo python setup.py install
+ $ tar cvfz python-sqlparse-VERSION.tar.gz
+ $ cd python-sqlparse/
+ $ sudo python setup.py install
+
+Alternatively you can install :mod:`sqlparse` from the
+`Python Packge Index <http://pypi.python.org/pypi/sqlparse>`_ with your
+favorite tool for installing Python modules. For example when using
+`pip <http://pypi.python.org/pypi/pip>`_ run :command:`pip install sqlparse`.
-A tarball of the current sources is available under the following URL:
-http://github.com/andialbrecht/python-sqlparse/tarball/master
+Getting Started
+---------------
-Example Usage
--------------
+The :mod:`sqlparse` module provides three simple functions on module level
+to achieve some common tasks when working with SQL statements.
+This section shows some simple usage examples of these functions.
-Here are some usage examples of this module.
+Let's get started with splitting a string containing one or more SQL
+statements into a list of single statements using :meth:`~sqlparse.split`:
-Splitting statements::
+.. code-block:: python
>>> import sqlparse
>>> sql = 'select * from foo; select * from bar;'
>>> sqlparse.split(sql)
- <<< [u'select * from foo; ', u'select * from bar;']
+ [u'select * from foo; ', u'select * from bar;']
+
+The end of a statement is identified by the occurrence of a semicolon.
+Semicolons within certain SQL constructs like ``BEGIN ... END`` blocks
+are handled correctly by the splitting mechanism.
+
+SQL statements can be beautified by using the :meth:`~sqlarse.format` function.
-Formatting statemtents::
+.. code-block:: python
>>> sql = 'select * from foo where id in (select id from bar);'
>>> print sqlparse.format(sql, reindent=True, keyword_case='upper')
@@ -49,18 +63,37 @@ Formatting statemtents::
(SELECT id
FROM bar);
-Now, let's have a deeper look at the internals::
+In this case all keywords in the given SQL are uppercased and the
+indentation is changed to make it more readable. Read :ref:`formatting` for
+a full reference of supported options given as keyword arguments
+to that function.
+
+Before proceeding with a closer look at the internal representation of
+SQL statements, you should be aware that this SQL parser is intentionally
+non-validating. It assumes that the given input is at least some kind
+of SQL and then it tries to analyze as much as possible without making
+too much assumptions about the concrete dialect or the actual statement.
+At least it's up to the user of this API to interpret the results right.
+
+When using the :meth:`~sqlparse.parse` function a tuple of
+:class:`~sqlparse.sql.Statement` instances is returned:
+
+.. code-block:: python
>>> sql = 'select * from "someschema"."mytable" where id = 1'
- >>> pared = sqlparse.parse(sql)
- >>> pared
- <<< (<Statement 'select...' at 0x9ad08ec>,)
- >>> stmt = parsed[0]
- >>> stmt.to_unicode() # converting it back to unicode
- <<< u'select * from "someschema"."mytable" where id = 1'
- >>> # This is how the internal representation looks like:
+ >>> parsed = sqlparse.parse(sql)
+ >>> parsed
+ (<Statement 'select...' at 0x9ad08ec>,)
+
+Each item of the tuple is a single statement as identified by the above
+mentioned :meth:`~sqlparse.split` function. So let's grab the only element
+from that list and have a look at the ``tokens`` attribute.
+Sub-tokens are stored in this attribute.
+
+.. code-block:: python
+
+ >>> stmt = parsed[0] # grab the Statement object
>>> stmt.tokens
- <<<
(<DML 'select' at 0x9b63c34>,
<Whitespace ' ' at 0x9b63e8c>,
<Operator '*' at 0x9b63e64>,
@@ -70,16 +103,33 @@ Now, let's have a deeper look at the internals::
<Identifier '"somes...' at 0x9b5c62c>,
<Whitespace ' ' at 0x9b63f04>,
<Where 'where ...' at 0x9b5caac>)
- >>>
+Each object can be converted back to a string at any time:
+
+.. code-block:: python
+
+ >>> stmt.to_unicode()
+ u'select * from "someschema"."mytable" where id = 1'
+ >>> stmt.tokens[-1].to_unicode() # or just the WHERE part
+ u'where id = 1'
-.. todo:: Describe general concepts
- Why non-validating? Processing stages (tokens, groups,...), filter,
+Details of the returned objects are described in :ref:`analyze`.
Development & Contributing
--------------------------
+The source code of this module is hosted on
+`bitbucket.org <http://bitbucket.org/andialbrecht/python-sqlparse/>`_.
+
+Run
+
+.. code-block:: bash
+
+ $ hg clone http://bitbucket.org/andialbrecht/python-sqlparse/
+
+to check out the latest sources from the Mercurial repository.
+
Please file bug reports and feature requests on the project site at
http://code.google.com/p/python-sqlparse/issues/entry or if you have
code to contribute upload it to http://codereview.appspot.com and
diff --git a/docs/source/ui.rst b/docs/source/ui.rst
new file mode 100644
index 0000000..264916e
--- /dev/null
+++ b/docs/source/ui.rst
@@ -0,0 +1,15 @@
+User Interfaces
+===============
+
+``sqlformat``
+ The ``sqlformat`` command line script ist distributed with the module.
+ Run :command:`sqlformat --help` to list available options and for usage
+ hints.
+
+``sqlformat.appspot.com``
+ An example `Google App Engine <http://code.google.com/appengine/>`_
+ application that exposes the formatting features using a web front-end.
+ See http://sqlformat.appspot.com for details.
+ The source for this application is available from a source code check out
+ of the :mod:`sqlparse` module (see :file:`extras/appengine`).
+
diff --git a/docs/tango/static/default.css_t b/docs/tango/static/default.css_t
deleted file mode 100644
index c86759a..0000000
--- a/docs/tango/static/default.css_t
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * Sphinx stylesheet -- default theme
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-@import url("basic.css");
-
-body {
- color: #000000;
- font-family: "Free Sans", Arial, Verdana, sans;
- font-size: 11pt;
- width: 70em;
- margin: 0;
- margin-left: auto;
- margin-right: auto;
-}
-
-
-div.related {
- background: #eeeeec; /* #d3d7cf; */
- color: white;
- padding-bottom: .6em;
- padding-top: .6em;
-}
-
-div.related a {
- color: #2e3436;
- text-decoration: none;
-}
-
-div.document {
- background: #eeeeec;
-}
-
-div.body {
- background: white;
- padding: .5em;
- -moz-border-radius: 0px 10px 10px 10px;
- border-right: 1px solid #eeeeec;
-}
-
-div.document h1, h2, h3, h4 {
- color: #204a87;
- font-weight: normal;
- letter-spacing: .05em;
-}
-
-div.document p, dl, div.highlight {
- margin-left: 25px;
-}
-
-div.document dd p, dd {
- margin-left: .5em;
-}
-
-div.document a {
- color: #f57900;
-}
-
-div.sphinxsidebarwrapper {
- background: url(bgfooter.png) top left repeat-x #eeeeec;
- padding-right: .5em;
-}
-
-div.sphinxsidebar ul {
- margin: 0;
- padding: 0;
-}
-
-div.sphinxsidebar a {
- color: #888a85;
- text-decoration: none;
-}
-
-div.footer {
- font-size: .8em;
- color: #888a85;
- text-align: right;
- padding: 10px;
-}
-
-div.footer a {
- color: #888a85;
-}
-
-div.highlight pre {
- background-color: #eeeeec;
- border: 1px solid #babdb6;
- padding: 7px;
-} \ No newline at end of file
diff --git a/docs/tango/theme.conf b/docs/tango/theme.conf
deleted file mode 100644
index 812330f..0000000
--- a/docs/tango/theme.conf
+++ /dev/null
@@ -1,28 +0,0 @@
-[theme]
-inherit = basic
-stylesheet = default.css
-pygments_style = sphinx
-
-[options]
-rightsidebar = false
-stickysidebar = false
-
-footerbgcolor = #11303d
-footertextcolor = #ffffff
-sidebarbgcolor = #1c4e63
-sidebartextcolor = #ffffff
-sidebarlinkcolor = #98dbcc
-relbarbgcolor = #133f52
-relbartextcolor = #ffffff
-relbarlinkcolor = #ffffff
-bgcolor = #ffffff
-textcolor = #000000
-headbgcolor = #f2f2f2
-headtextcolor = #20435c
-headlinkcolor = #c60f0f
-linkcolor = #355f7c
-codebgcolor = #eeffcc
-codetextcolor = #333333
-
-bodyfont = sans-serif
-headfont = 'Trebuchet MS', sans-serif
diff --git a/sqlparse/__init__.py b/sqlparse/__init__.py
index 01b3bd8..9a97dc0 100644
--- a/sqlparse/__init__.py
+++ b/sqlparse/__init__.py
@@ -30,9 +30,7 @@ def parse(sql):
*sql* is a single string containting one or more SQL statements.
- The returned :class:`~sqlparse.parser.Statement` are fully analyzed.
-
- Returns a list of :class:`~sqlparse.parser.Statement` instances.
+ Returns a tuple of :class:`~sqlparse.sql.Statement` instances.
"""
stack = engine.FilterStack()
stack.full_analyze()
@@ -42,10 +40,9 @@ def parse(sql):
def format(sql, **options):
"""Format *sql* according to *options*.
- Returns a list of :class:`~sqlparse.parse.Statement` instances like
- :meth:`parse`, but the statements are formatted according to *options*.
+ Available options are documented in :ref:`formatting`.
- Available options are documented in the :mod:`~sqlparse.format` module.
+ Returns the formatted SQL statement as string.
"""
stack = engine.FilterStack()
options = formatter.validate_options(options)
@@ -55,7 +52,7 @@ def format(sql, **options):
def split(sql):
- """Split *sql* into separate statements.
+ """Split *sql* into single statements.
Returns a list of strings.
"""
diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 372a3c7..db9f1c1 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -9,6 +9,12 @@ from sqlparse import tokens as T
class Token(object):
+ """Base class for all other classes in this module.
+
+ It represents a single token and has two instance attributes:
+ ``value`` is the unchange value of the token and ``ttype`` is
+ the type of the token.
+ """
__slots__ = ('value', 'ttype')
@@ -28,6 +34,7 @@ class Token(object):
return self.value
def to_unicode(self):
+ """Returns a unicode representation of this object."""
return unicode(self)
def _get_repr_name(self):
@@ -42,6 +49,17 @@ class Token(object):
return re.sub('\s+', ' ', short)
def match(self, ttype, values, regex=False):
+ """Checks whether the token matches the given arguments.
+
+ *ttype* is a token type. If this token doesn't match the given token
+ type.
+ *values* is a list of possible values for this token. The values
+ are OR'ed together so if only one of the values matches ``True``
+ is returned. Except for keyword tokens the comparsion is
+ case-sensitive. For convenience it's ok to pass in a single string.
+ If *regex* is ``True`` (default is ``False``) the given values are
+ treated as regular expressions.
+ """
if self.ttype is not ttype:
return False
if values is None:
@@ -64,13 +82,20 @@ class Token(object):
return self.value in values
def is_group(self):
+ """Returns ``True`` if this object has children."""
return False
def is_whitespace(self):
+ """Return ``True`` if this token is a whitespace token."""
return self.ttype and self.ttype in T.Whitespace
class TokenList(Token):
+ """A group of tokens.
+
+ It has an additional instance attribute ``tokens`` which holds a
+ list of child-tokens.
+ """
__slots__ = ('value', 'ttype', 'tokens')
@@ -104,6 +129,10 @@ class TokenList(Token):
token._pprint_tree(max_depth, depth+1)
def flatten(self):
+ """Generator yielding ungrouped tokens.
+
+ This method is recursively called for all child tokens.
+ """
for token in self.tokens:
if isinstance(token, TokenList):
for item in token.flatten():
@@ -118,6 +147,11 @@ class TokenList(Token):
return [x for x in self.tokens if isinstance(x, TokenList)]
def token_first(self, ignore_whitespace=True):
+ """Returns the first child token.
+
+ If *ignore_whitespace* is ``True`` (the default), whitespace
+ tokens are ignored.
+ """
for token in self.tokens:
if ignore_whitespace and token.is_whitespace():
continue
@@ -125,6 +159,13 @@ class TokenList(Token):
return None
def token_next_by_instance(self, idx, clss):
+ """Returns the next token matching a class.
+
+ *idx* is where to start searching in the list of child tokens.
+ *clss* is a list of classes the token should be an instance of.
+
+ If no matching token can be found ``None`` is returned.
+ """
if type(clss) not in (types.ListType, types.TupleType):
clss = (clss,)
if type(clss) is not types.TupleType:
@@ -135,6 +176,7 @@ class TokenList(Token):
return None
def token_next_by_type(self, idx, ttypes):
+ """Returns next matching token by it's token type."""
if not isinstance(ttypes, (types.TupleType, types.ListType)):
ttypes = [ttypes]
for token in self.tokens[idx:]:
@@ -143,6 +185,7 @@ class TokenList(Token):
return None
def token_next_match(self, idx, ttype, value, regex=False):
+ """Returns next token where it's ``match`` method returns ``True``."""
if type(idx) != types.IntType:
idx = self.token_index(idx)
for token in self.tokens[idx:]:
@@ -162,6 +205,11 @@ class TokenList(Token):
return None
def token_prev(self, idx, skip_ws=True):
+ """Returns the previous token relative to *idx*.
+
+ If *skip_ws* is ``True`` (the default) whitespace tokens are ignored.
+ ``None`` is returned if there's no previous token.
+ """
while idx != 0:
idx -= 1
if self.tokens[idx].is_whitespace() and skip_ws:
@@ -169,6 +217,11 @@ class TokenList(Token):
return self.tokens[idx]
def token_next(self, idx, skip_ws=True):
+ """Returns the next token relative to *idx*.
+
+ If *skip_ws* is ``True`` (the default) whitespace tokens are ignored.
+ ``None`` is returned if there's no next token.
+ """
while idx < len(self.tokens)-1:
idx += 1
if self.tokens[idx].is_whitespace() and skip_ws:
@@ -180,7 +233,11 @@ class TokenList(Token):
return self.tokens.index(token)
def tokens_between(self, start, end, exclude_end=False):
- """Return all tokens between (and including) start and end."""
+ """Return all tokens between (and including) start and end.
+
+ If *exclude_end* is ``True`` (default is ``False``) the end token
+ is included too.
+ """
if exclude_end:
offset = 0
else:
@@ -188,7 +245,7 @@ class TokenList(Token):
return self.tokens[self.token_index(start):self.token_index(end)+offset]
def group_tokens(self, grp_cls, tokens):
- """Replace tokens by instance of grp_cls."""
+ """Replace tokens by an instance of *grp_cls*."""
idx = self.token_index(tokens[0])
for t in tokens:
self.tokens.remove(t)
@@ -197,14 +254,22 @@ class TokenList(Token):
return grp
def insert_before(self, where, token):
+ """Inserts *token* before *where*."""
self.tokens.insert(self.token_index(where), token)
class Statement(TokenList):
+ """Represents a SQL statement."""
__slots__ = ('value', 'ttype', 'tokens')
def get_type(self):
+ """Returns the type of a statement.
+
+ The returned value is a string holding an upper-cased reprint of
+ the first DML or DDL keyword. If the first token in this group
+ isn't a DML or DDL keyword "UNKNOWN" is returned.
+ """
first_token = self.token_first()
if first_token.ttype in (T.Keyword.DML, T.Keyword.DDL):
return first_token.value.upper()
@@ -213,13 +278,19 @@ class Statement(TokenList):
class Identifier(TokenList):
+ """Represents an identifier.
+
+ Identifiers may have aliases or typecasts.
+ """
__slots__ = ('value', 'ttype', 'tokens')
def has_alias(self):
+ """Returns ``True`` if an alias is present."""
return self.get_alias() is not None
def get_alias(self):
+ """Returns the alias for this identifier or ``None``."""
kw = self.token_next_match(0, T.Keyword, 'AS')
if kw is not None:
alias = self.token_next(self.token_index(kw))
@@ -236,15 +307,23 @@ class Identifier(TokenList):
return alias.to_unicode()
def get_name(self):
+ """Returns the name of this identifier.
+
+ This is either it's alias or it's real name. The returned valued can
+ be considered as the name under which the object corresponding to
+ this identifier is known within the current statement.
+ """
alias = self.get_alias()
if alias is not None:
return alias
return self.get_real_name()
def get_real_name(self):
+ """Returns the real name (object name) of this identifier."""
return self.token_next_by_type(0, T.Name).value
def get_typecast(self):
+ """Returns the typecast or ``None`` of this object as a string."""
marker = self.token_next_match(0, T.Punctuation, '::')
if marker is None:
return None
@@ -255,37 +334,50 @@ class Identifier(TokenList):
class IdentifierList(TokenList):
+ """A list of :class:`~sqlparse.sql.Identifier`\'s."""
__slots__ = ('value', 'ttype', 'tokens')
def get_identifiers(self):
+ """Returns the identifiers.
+
+ Whitespaces and punctuations are not included in this list.
+ """
return [x for x in self.tokens if isinstance(x, Identifier)]
class Parenthesis(TokenList):
+ """Tokens between parenthesis."""
__slots__ = ('value', 'ttype', 'tokens')
class Assignment(TokenList):
+ """An assignment like 'var := val;'"""
__slots__ = ('value', 'ttype', 'tokens')
class If(TokenList):
+ """An 'if' clause with possible 'else if' or 'else' parts."""
__slots__ = ('value', 'ttype', 'tokens')
class For(TokenList):
+ """A 'FOR' loop."""
__slots__ = ('value', 'ttype', 'tokens')
class Comparsion(TokenList):
+ """A comparsion used for example in WHERE clauses."""
__slots__ = ('value', 'ttype', 'tokens')
class Comment(TokenList):
+ """A comment."""
__slots__ = ('value', 'ttype', 'tokens')
class Where(TokenList):
+ """A WHERE clause."""
__slots__ = ('value', 'ttype', 'tokens')
class Case(TokenList):
+ """A CASE statement with one or more WHEN and possibly an ELSE part."""
__slots__ = ('value', 'ttype', 'tokens')