summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml21
-rw-r--r--Makefile10
-rw-r--r--TODO18
-rw-r--r--extras/appengine/README3
-rw-r--r--extras/appengine/app.yaml54
-rw-r--r--extras/appengine/appengine_config.py6
-rwxr-xr-xextras/appengine/bootstrap.py82
-rw-r--r--extras/appengine/config.py7
-rw-r--r--extras/appengine/cron.yaml4
-rw-r--r--extras/appengine/examples/customers.sql1
-rw-r--r--extras/appengine/examples/multiple_inserts.sql1
-rw-r--r--extras/appengine/examples/pg_view.sql1
-rw-r--r--extras/appengine/examples/subquery.sql1
-rw-r--r--extras/appengine/examples/subquery2.sql1
-rw-r--r--extras/appengine/index.yaml7
-rw-r--r--extras/appengine/main.py37
-rw-r--r--extras/appengine/sqlformat/__init__.py19
-rw-r--r--extras/appengine/sqlformat/legacy.py166
-rw-r--r--extras/appengine/sqlformat/templates/about.html46
-rw-r--r--extras/appengine/sqlformat/templates/api.html66
-rw-r--r--extras/appengine/sqlformat/templates/index.html120
-rw-r--r--extras/appengine/sqlformat/templates/master.html103
-rw-r--r--extras/appengine/sqlformat/templates/python-client-example.html17
-rw-r--r--extras/appengine/sqlformat/templates/source.html60
-rw-r--r--extras/appengine/static/bg_options.pngbin202 -> 0 bytes
-rw-r--r--extras/appengine/static/bgfieldset.pngbin227 -> 0 bytes
-rw-r--r--extras/appengine/static/bgfooter.pngbin434 -> 0 bytes
-rw-r--r--extras/appengine/static/bgtop.pngbin430 -> 0 bytes
-rw-r--r--extras/appengine/static/favicon.icobin4162 -> 0 bytes
-rw-r--r--extras/appengine/static/hotkeys.js1
-rw-r--r--extras/appengine/static/loading.gifbin4331 -> 0 bytes
-rw-r--r--extras/appengine/static/lynx_screenshot.pngbin66017 -> 0 bytes
-rw-r--r--extras/appengine/static/pygments.css59
-rw-r--r--extras/appengine/static/robots.txt8
-rw-r--r--extras/appengine/static/script.js98
-rw-r--r--extras/appengine/static/sitemap.xml25
-rw-r--r--extras/appengine/static/sqlformat_client_example.py20
-rw-r--r--extras/appengine/static/styles.css245
-rw-r--r--extras/buildbot/googlecode_atom.py171
-rw-r--r--extras/buildbot/master.cfg264
-rw-r--r--extras/sqlformat.pngbin5359 -> 0 bytes
-rw-r--r--extras/sqlformat.svg115
-rw-r--r--pytest.ini6
-rw-r--r--setup.py24
-rw-r--r--sqlparse/__init__.py8
-rw-r--r--sqlparse/compat.py39
-rw-r--r--sqlparse/engine/grouping.py17
-rw-r--r--sqlparse/filters.py42
-rw-r--r--sqlparse/lexer.py51
-rw-r--r--sqlparse/sql.py31
-rw-r--r--sqlparse/tokens.py9
-rw-r--r--sqlparse/utils.py75
-rw-r--r--tests/test_filters.py1
-rw-r--r--tests/test_format.py12
-rw-r--r--tests/test_functions.py1
-rw-r--r--tests/test_grouping.py27
-rw-r--r--tests/test_parse.py17
-rw-r--r--tests/test_pipeline.py8
-rw-r--r--tests/test_regressions.py10
-rw-r--r--tests/test_split.py48
-rw-r--r--tests/test_tokenize.py23
-rw-r--r--tests/utils.py12
-rw-r--r--tox.ini34
63 files changed, 247 insertions, 2105 deletions
diff --git a/.travis.yml b/.travis.yml
index 098eb14..56f8d9a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,8 @@
language: python
-python: 2.7
-env:
- - TOX_ENV=py26
- - TOX_ENV=py27
- - TOX_ENV=py32
- - TOX_ENV=py33
- - TOX_ENV=py34
- - TOX_ENV=pypy
-before_install:
- - sudo apt-get install pypy
-install:
- - pip install tox
-script:
- - tox -e $TOX_ENV
+python:
+ - "2.7"
+ - "3.3"
+ - "3.4"
+ - "pypy"
+install: "pip install pytest"
+script: "py.test"
diff --git a/Makefile b/Makefile
index 2acd83c..d5074ad 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,10 @@ coverage:
py.test --cov=sqlparse --cov-report=html --cov-report=term
clean:
- $(PYTHON) setup.py clean
- find . -name '*.pyc' -delete
- find . -name '*~' -delete
+ @$(PYTHON) setup.py clean
+ @find . -name '*.pyc' -delete
+ @find . -name '*~' -delete
+ @rm -rf *.egg-info
+ @rm -rf dist
+ @rm -rf htmlcov
+ @find . -name '__pycache__' -delete
diff --git a/TODO b/TODO
index 166df20..101c5a1 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,21 @@
+Goals for 0.2.0
+---------------
+
+X Drop support for Python <= 2.6
+X Remove SQLParserError from top level module.
+X Don't use 2to3 anymore
+~ Remove unused code
+~ Possible deprecation:
+ - RightMarginFilter
+ Seems to be broken and not used. However, a replacement would be good.
+~ Update documentation
+~ Cleanup docs on PyPI/github
+~ Write release notes
+
+
+Misc
+----
+
* See
https://groups.google.com/d/msg/sqlparse/huz9lKXt0Lc/11ybIKPJWbUJ
for some interesting hints and suggestions.
diff --git a/extras/appengine/README b/extras/appengine/README
deleted file mode 100644
index 04d32b2..0000000
--- a/extras/appengine/README
+++ /dev/null
@@ -1,3 +0,0 @@
-- Run "./bootstrap.py" to download all required Python modules.
-- Run "dev_appserver.py ." for a local server.
-- Have a look at config.py :)
diff --git a/extras/appengine/app.yaml b/extras/appengine/app.yaml
deleted file mode 100644
index b7cf550..0000000
--- a/extras/appengine/app.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
-application: sqlformat-hrd
-version: dev27
-runtime: python27
-api_version: 1
-threadsafe: true
-
-default_expiration: 7d # This is good for images, which never change
-
-handlers:
-
-- url: /(robots.txt|favicon.ico|sitemap.xml)
- static_files: static/\1
- upload: static/(robots.txt|favicon.ico|sitemap.xml)
-
-- url: /google7a062e78b56854c0.html
- static_files: static/robots.txt
- upload: static/robots.txt
-
-- url: /static/(script.js|styles.css)
- static_files: static/\1
- upload: static/(script.js|styles.css)
-
-- url: /static
- static_dir: static
-
-- url: .*
- script: main.app
-
-builtins:
-- appstats: on
-
-skip_files:
-- ^(.*/)?app\.yaml
-- ^(.*/)?app\.yml
-- ^(.*/)?index\.yaml
-- ^(.*/)?index\.yml
-- ^(.*/)?#.*#
-- ^(.*/)?.*~
-- ^(.*/)?.*\.py[co]
-- ^(.*/)?.*/RCS/.*
-- ^(.*/)?\..*
-- ^(.*/)?jinja2*
-
-inbound_services:
-- warmup
-
-libraries:
-- name: jinja2
- version: latest
-- name: markupsafe
- version: latest
-- name: setuptools
- version: latest
-
diff --git a/extras/appengine/appengine_config.py b/extras/appengine/appengine_config.py
deleted file mode 100644
index 8ed3ee5..0000000
--- a/extras/appengine/appengine_config.py
+++ /dev/null
@@ -1,6 +0,0 @@
-
-def webapp_add_wsgi_middleware(app):
- from google.appengine.ext.appstats import recording
- app = recording.appstats_wsgi_middleware(app)
- return app
-
diff --git a/extras/appengine/bootstrap.py b/extras/appengine/bootstrap.py
deleted file mode 100755
index debc2bf..0000000
--- a/extras/appengine/bootstrap.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-
-"""Downloads required third-party modules."""
-
-import os
-import urllib2
-import gzip
-import tarfile
-import tempfile
-import shutil
-import sys
-from StringIO import StringIO
-
-HERE = os.path.abspath(os.path.dirname(__file__))
-LIB_DIR = os.path.join(HERE, 'lib')
-
-PACKAGES = {
- 'http://pypi.python.org/packages/source/F/Flask/Flask-0.7.2.tar.gz':
- [('Flask-0.7.2/flask', 'flask')],
- 'http://pypi.python.org/packages/source/W/Werkzeug/Werkzeug-0.6.2.tar.gz':
- [('Werkzeug-0.6.2/werkzeug', 'werkzeug')],
- 'http://pypi.python.org/packages/source/J/Jinja2/Jinja2-2.5.5.tar.gz':
- [('Jinja2-2.5.5/jinja2/', 'jinja2')],
- 'http://pypi.python.org/packages/source/s/simplejson/simplejson-2.1.6.tar.gz':
- [('simplejson-2.1.6/simplejson', 'simplejson')],
- 'http://pypi.python.org/packages/source/P/Pygments/Pygments-1.4.tar.gz':
- [('Pygments-1.4/pygments', 'pygments')],
-}
-
-
-def fetch_all():
- if not os.path.isdir(LIB_DIR):
- os.makedirs(LIB_DIR)
- for url, targets in PACKAGES.iteritems():
- if not _missing_targets(targets):
- continue
- sys.stdout.write(url)
- sys.stdout.flush()
- fetch(url, targets)
- sys.stdout.write(' done\n')
- sys.stdout.flush()
-
-
-def fetch(url, targets):
- blob = urllib2.urlopen(url).read()
- gz = gzip.GzipFile(fileobj=StringIO(blob))
- tar = tarfile.TarFile(fileobj=gz)
- tmpdir = tempfile.mkdtemp()
- try:
- tar.extractall(tmpdir)
- for src, dest in targets:
- dest = os.path.join(LIB_DIR, dest)
- if os.path.isdir(dest):
- shutil.rmtree(dest)
- shutil.copytree(os.path.join(tmpdir, src), dest)
- finally:
- shutil.rmtree(tmpdir)
-
-
-def _missing_targets(targets):
- for _, dest in targets:
- dest = os.path.join(LIB_DIR, dest)
- if not os.path.isdir(dest):
- return True
- return False
-
-
-def link_sqlparse():
- if os.path.islink('sqlparse'):
- return
- elif os.path.exists('sqlparse'):
- shutil.rmtree('sqlparse')
- if hasattr(os, 'symlink'):
- os.symlink('../../sqlparse', 'sqlparse')
- else:
- shutil.copytree(os.path.join(HERE, '../../sqlparse'),
- 'sqlparse')
-
-
-if __name__ == '__main__':
- fetch_all()
- link_sqlparse()
diff --git a/extras/appengine/config.py b/extras/appengine/config.py
deleted file mode 100644
index 1599c00..0000000
--- a/extras/appengine/config.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# SQLFormat configuration
-
-# Debug flag
-DEBUG = True
-
-# Secret key, please change this
-SECRET_KEY = 'notsosecret'
diff --git a/extras/appengine/cron.yaml b/extras/appengine/cron.yaml
deleted file mode 100644
index a7fefce..0000000
--- a/extras/appengine/cron.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-cron:
-- description: Daily exception report
- url: /_ereporter?sender=albrecht.andi@googlemail.com&versions=all&delete=false
- schedule: every day 00:00 \ No newline at end of file
diff --git a/extras/appengine/examples/customers.sql b/extras/appengine/examples/customers.sql
deleted file mode 100644
index 8b73850..0000000
--- a/extras/appengine/examples/customers.sql
+++ /dev/null
@@ -1 +0,0 @@
-USE mydatabase;SELECT orders.customer, orders.day_of_order, orders.product, orders.quantity as number_ordered, inventory.quantity as number_instock, inventory.price FROM orders JOIN inventory ON orders.product = inventory.product; \ No newline at end of file
diff --git a/extras/appengine/examples/multiple_inserts.sql b/extras/appengine/examples/multiple_inserts.sql
deleted file mode 100644
index cf49d5d..0000000
--- a/extras/appengine/examples/multiple_inserts.sql
+++ /dev/null
@@ -1 +0,0 @@
-insert into customer (id, name) values (1, 'John');insert into customer (id, name) values (2, 'Jack');insert into customer (id, name) values (3, 'Jane');insert into customer (id, name) values (4, 'Jim');insert into customer (id, name) values (5, 'Jerry');insert into customer (id, name) values (1, 'Joe'); \ No newline at end of file
diff --git a/extras/appengine/examples/pg_view.sql b/extras/appengine/examples/pg_view.sql
deleted file mode 100644
index edf9f06..0000000
--- a/extras/appengine/examples/pg_view.sql
+++ /dev/null
@@ -1 +0,0 @@
-SELECT DISTINCT (current_database())::information_schema.sql_identifier AS view_catalog, (nv.nspname)::information_schema.sql_identifier AS view_schema, (v.relname)::information_schema.sql_identifier AS view_name, (current_database())::information_schema.sql_identifier AS table_catalog, (nt.nspname)::information_schema.sql_identifier AS table_schema, (t.relname)::information_schema.sql_identifier AS table_name FROM pg_namespace nv, pg_class v, pg_depend dv, pg_depend dt, pg_class t, pg_namespace nt WHERE ((((((((((((((nv.oid = v.relnamespace) AND (v.relkind = 'v'::"char")) AND (v.oid = dv.refobjid)) AND (dv.refclassid = ('pg_class'::regclass)::oid)) AND (dv.classid = ('pg_rewrite'::regclass)::oid)) AND (dv.deptype = 'i'::"char")) AND (dv.objid = dt.objid)) AND (dv.refobjid <> dt.refobjid)) AND (dt.classid = ('pg_rewrite'::regclass)::oid)) AND (dt.refclassid = ('pg_class'::regclass)::oid)) AND (dt.refobjid = t.oid)) AND (t.relnamespace = nt.oid)) AND (t.relkind = ANY (ARRAY['r'::"char", 'v'::"char"]))) AND pg_has_role(t.relowner, 'USAGE'::text)) ORDER BY (current_database())::information_schema.sql_identifier, (nv.nspname)::information_schema.sql_identifier, (v.relname)::information_schema.sql_identifier, (current_database())::information_schema.sql_identifier, (nt.nspname)::information_schema.sql_identifier, (t.relname)::information_schema.sql_identifier;
diff --git a/extras/appengine/examples/subquery.sql b/extras/appengine/examples/subquery.sql
deleted file mode 100644
index dd4bbc1..0000000
--- a/extras/appengine/examples/subquery.sql
+++ /dev/null
@@ -1 +0,0 @@
-select sum(a1.Sales) from Store_Information a1 where a1.Store_name in (select store_name from Geography a2 where a2.store_name = a1.store_name); \ No newline at end of file
diff --git a/extras/appengine/examples/subquery2.sql b/extras/appengine/examples/subquery2.sql
deleted file mode 100644
index 6c00a87..0000000
--- a/extras/appengine/examples/subquery2.sql
+++ /dev/null
@@ -1 +0,0 @@
-select user_id, count(*) as how_many from bboard where not exists (select 1 from bboard_authorized_maintainers bam where bam.user_id = bboard.user_id) and posting_time + 60 > sysdate group by user_id order by how_many desc; \ No newline at end of file
diff --git a/extras/appengine/index.yaml b/extras/appengine/index.yaml
deleted file mode 100644
index 7071349..0000000
--- a/extras/appengine/index.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-indexes:
-- kind: __google_ExceptionRecord
- properties:
- - name: date
- - name: major_version
- - name: minor_version
- direction: desc
diff --git a/extras/appengine/main.py b/extras/appengine/main.py
deleted file mode 100644
index ae4d251..0000000
--- a/extras/appengine/main.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# SQLFormat's main script, dead simple :)
-
-import os
-import sys
-
-LIB_DIR = os.path.join(os.path.dirname(__file__), 'lib')
-
-if LIB_DIR not in sys.path:
- sys.path.insert(0, LIB_DIR)
-
-from sqlformat import app
-
-import config
-
-import logging
-from google.appengine.ext import ereporter
-
-ereporter.register_logger()
-
-
-class EreporterMiddleware(object):
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- try:
- return self.app(environ, start_response)
- except:
- logging.exception('Exception in request:')
- logging.debug(environ)
- raise
-
-
-app.config.from_object(config)
-
-app = EreporterMiddleware(app)
diff --git a/extras/appengine/sqlformat/__init__.py b/extras/appengine/sqlformat/__init__.py
deleted file mode 100644
index 11f4d9d..0000000
--- a/extras/appengine/sqlformat/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from flask import Flask, make_response
-
-from sqlformat.legacy import legacy
-
-
-app = Flask('sqlformat')
-
-
-@app.route('/ping')
-def ping():
- return make_response('pong')
-
-@app.route('/_ah/warmup')
-def warmup():
- return make_response('polishing chrome')
-
-
-# Register legacy URLs last so that newer URLs replace them.
-app.register_blueprint(legacy)
diff --git a/extras/appengine/sqlformat/legacy.py b/extras/appengine/sqlformat/legacy.py
deleted file mode 100644
index 7f6c161..0000000
--- a/extras/appengine/sqlformat/legacy.py
+++ /dev/null
@@ -1,166 +0,0 @@
-"""Legacy URLs."""
-
-# This module reflects the URLs and behavior of the former Django
-# application.
-
-import logging
-import os
-import time
-
-from google.appengine.api import memcache
-
-from flask import Blueprint, make_response, render_template, Response, request
-
-from pygments import highlight
-from pygments.formatters import HtmlFormatter
-from pygments.lexers import SqlLexer, PythonLexer, PhpLexer
-
-import simplejson as json
-
-import sqlparse
-
-
-legacy = Blueprint('', 'legacy')
-
-
-EXAMPLES_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../examples'))
-
-
-@legacy.route('/', methods=['POST', 'GET'])
-def index():
- data = {'examples': _get_examples()}
- extra = {'highlight': True, 'comments': False,
- 'keywords': 'upper', 'idcase': '',
- 'n_indents': '2',
- 'lang': 'sql'}
- sql_orig = 'select * from foo join bar on val1 = val2 where id = 123;'
- if request.method == 'POST':
- oformat = request.form.get('format', 'html')
- extra['highlight'] = 'highlight' in request.form
- extra['comments'] = 'remove_comments' in request.form
- extra['keywords'] = request.form.get('keyword_case', '')
- extra['idcase'] = request.form.get('identifier_case', '')
- extra['n_indents'] = request.form.get('n_indents', '2')
- extra['lang'] = request.form.get('output_format', 'sql')
- sql = _get_sql(request.form, request.files)
- sql_orig = sql
- start = time.time()
- data['output'] = _format_sql(sql, request.form, format=oformat)
- data['proc_time'] = '%.3f' % (time.time()-start)
- if oformat == 'json':
- data['errors'] = ''
- return make_response(Response(json.dumps(data),
- content_type='text/x-json'))
- elif oformat == 'text':
- return make_response(Response(data['output'], content_type='text/plain'))
- data['sql_orig'] = sql_orig
- data['extra'] = extra
- return render_template('index.html', **data)
-
-
-@legacy.route('/source/')
-def source():
- return render_template('source.html')
-
-
-@legacy.route('/about/')
-def about():
- return render_template('about.html')
-
-@legacy.route('/api/')
-def api():
- return render_template('api.html')
-
-
-@legacy.route('/format/', methods=['GET', 'POST'])
-@legacy.route('/format', methods=['GET', 'POST'])
-def format_():
- if request.method == 'POST':
- sql = _get_sql(request.form, request.files)
- data = request.form
- else:
- sql = _get_sql(request.args)
- data = request.args
- formatted = _format_sql(sql, data, format='text')
- return make_response(Response(formatted, content_type='text/plain'))
-
-
-@legacy.route('/load_example', methods=['GET', 'POST'])
-def load_example():
- fname = request.form.get('fname')
- if fname is None:
- answer = 'Uups, I\'ve got no filename...'
- elif fname not in _get_examples():
- answer = 'Hmm, I think you don\'t want to do that.'
- else:
- answer = open(os.path.join(EXAMPLES_DIR, fname)).read()
- data = json.dumps({'answer': answer})
- return make_response(Response(data, content_type='text/x-json'))
-
-
-def _get_examples():
- examples = memcache.get('legacy_examples')
- if examples is None:
- examples = os.listdir(EXAMPLES_DIR)
- memcache.set('legacy_examples', examples)
- return examples
-
-
-def _get_sql(data, files=None):
- sql = None
- if files is not None and 'datafile' in files:
- raw = files['datafile'].read()
- try:
- sql = raw.decode('utf-8')
- except UnicodeDecodeError, err:
- logging.error(err)
- logging.debug(repr(raw))
- sql = (u'-- UnicodeDecodeError: %s\n'
- u'-- Please make sure to upload UTF-8 encoded data for now.\n'
- u'-- If you want to help improving this part of the application\n'
- u'-- please file a bug with some demo data at:\n'
- u'-- http://code.google.com/p/python-sqlparse/issues/entry\n'
- u'-- Thanks!\n' % err)
- if not sql:
- sql = data.get('data')
- return sql or ''
-
-
-def _format_sql(sql, data, format='html'):
- popts = {}
- if data.get('remove_comments'):
- popts['strip_comments'] = True
- if data.get('keyword_case', 'undefined') not in ('undefined', ''):
- popts['keyword_case'] = data.get('keyword_case')
- if data.get('identifier_case', 'undefined') not in ('undefined', ''):
- popts['identifier_case'] = data.get('identifier_case')
- if data.get('n_indents', None) is not None:
- val = data.get('n_indents')
- try:
- popts['indent_width'] = max(1, min(1000, int(val)))
- popts['reindent'] = True
- except (ValueError, TypeError):
- pass
- if (not 'indent_width' in popts and
- data.get('reindent', '').lower() in ('1', 'true', 't')):
- popts['indent_width'] = 2
- popts['reindent'] = True
- if data.get('output_format', None) is not None:
- popts['output_format'] = data.get('output_format')
- logging.debug('Format: %s, POPTS: %r', format, popts)
- logging.debug(sql)
- sql = sqlparse.format(sql, **popts)
- if format in ('html', 'json'):
- if data.get('highlight', False):
- if popts['output_format'] == 'python':
- lexer = PythonLexer()
- elif popts['output_format'] == 'php':
- lexer = PhpLexer()
- else:
- lexer = SqlLexer()
- sql = highlight(sql, lexer, HtmlFormatter())
- else:
- sql = ('<textarea class="resizable" '
- 'style="height: 350px; margin-top: 1em;">%s</textarea>'
- % sql)
- return sql
diff --git a/extras/appengine/sqlformat/templates/about.html b/extras/appengine/sqlformat/templates/about.html
deleted file mode 100644
index 2d4e03e..0000000
--- a/extras/appengine/sqlformat/templates/about.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends "master.html" %}
-
-{% block title %}About{% endblock %}
-
-{% block main %}
-<h1>About this Application</h1>
-<p>
- This application is a online SQL formatting tool.
-</p>
-<p>
- Basically it's a playground for a Python module to parse and format
- SQL statements. Sometimes it's easier to combine the available
- options and to see the resulting output using a web front-end than
- on the command line ;-)
-</p>
-<p>
- To get started, enter a SQL statement in the text box on the top,
- choose some options and click on &quot;Format SQL&quot; (Ctrl+F)
- to see the result.
-</p>
-<p>
- <em>Note:</em> The SQL formatter and parser is in an early stage
- of development. If you're looking for a mature tool, try one of
- <a href="http://www.google.com/search?q=online+sql+formatter">these</a>.
-</p>
-<h2>Using it from the Command Line</h2>
-<p>
- There are three ways to use this SQL formatter from the command line:
-</p>
-<ol>
- <li>Grab the <a href="/source/">sources</a> and use the module in your
- Python scripts.</li>
- <li>
- Write a little script in your favorite language that sends a POST
- request to this application.<br/>
- Read the <a href="/api/">API Documentation</a> for more information.
- </li>
- <li>Use
- <a href="/static/lynx_screenshot.png"
- alt="Lynx Screenshot" target="_blank"
- title="Screenshot: sqlformat.appspot.com on Lynx">Lynx
- </a>
- </li>
-</ol>
-
-{% endblock %}
diff --git a/extras/appengine/sqlformat/templates/api.html b/extras/appengine/sqlformat/templates/api.html
deleted file mode 100644
index 2b32cbb..0000000
--- a/extras/appengine/sqlformat/templates/api.html
+++ /dev/null
@@ -1,66 +0,0 @@
-{% extends "master.html" %}
-
-{% block title %}API{% endblock %}
-
-{% block main %}
-<h1>API Documentation</h1>
-
-<p>
- Using the API for this application is pretty simple. Just send a
- request to
-</p>
-<p>
- <code>http://sqlformat.appspot.com/format/</code>
-</p>
-
-<h2>Options</h2>
-<p>
- The server accepts various options to control formatting. Only
- the <em>data</em> option is required. All others are optional.<br />
- Either use <code>GET</code> and pack the options in the query string
- or <code>POST</code> and submit your parameters as form data.<br />
- When using <code>POST</code> make sure your request includes a
- <em>Content-Type: application/x-www-form-urlencoded</em> header.
-</p>
-
-<dl>
- <dt>data</dt>
- <dd>The SQL statement to format.</dd>
- <dt>remove_comments</dt>
- <dd>Set to 1 to remove comments.</dd>
- <dt>keyword_case</dt>
- <dd>How to convert keywords. Allowed values are 'lower', 'upper',
- 'capitalize'.</dd>
- <dt>identifier_case</dt>
- <dd>How to convert identifiers. Allowed values are 'lower', 'upper',
- 'capitalize'.</dd>
- <dt>n_indents</dt>
- <dd>An integer indicating the indendation depth.</dd>
- <dt>right_margin</dt>
- <dd>An integer indicating the maximum line length.</dd>
- <dt>output_format</dt>
- <dd>Transfer the statement into another programming language.
- Allowed values are 'python', 'php'</dd>
-</dl>
-
-<h2>Example</h2>
-<p>
- Here's a example in Python:
-</p>
-{% include "python-client-example.html" %}
-<p>
- <a href="/static/sqlformat_client_example.py">Download sqlformat_example_client.py</a>
-</p>
-
-<p>
- And another example using curl and a <code>GET</code> request:
-</p>
-<div class="highlight example"><pre>
-$ curl "http://sqlformat.appspot.com/format<b>?</b>keyword_case=upper<b>&</b>reindent=true<b>&</b>data=select%20*%20from%20foo;"
-SELECT *
-FROM foo;
-$
-</pre></div>
-
-
-{% endblock %}
diff --git a/extras/appengine/sqlformat/templates/index.html b/extras/appengine/sqlformat/templates/index.html
deleted file mode 100644
index 22d6fdb..0000000
--- a/extras/appengine/sqlformat/templates/index.html
+++ /dev/null
@@ -1,120 +0,0 @@
-{% extends "master.html" %}
-
-{% block main %}
-
-{% if output %}
- <a href="#output" class="skip">Jump to formatted query</a>
-{% endif %}
-
-<form method="post" action="" id="form_options" enctype="multipart/form-data">
- <div id="input">
- <div>
- <strong>Type your SQL here:</strong><br />
- <textarea id="id_data" rows="10" cols="40" name="data" class="resizable">{{ sql_orig }}</textarea>
- </div>
- <div style="margin-top: .5em;">
- <strong>...or upload a file:</strong>
- <input type="file" name="datafile" id="id_datafile" />
- </div>
- <div id="examples" style="margin-top: .5em;"></div>
- <div id="actions" style="margin-top: .5em;">
- <input type="submit" value="Format SQL" id="btn_format" />
- </div>
- {% if output %}<a name="output"></a>
- <div id="response">{{output|safe}}</div>
- {% else %}
- <div id="response"></div>
- {% endif %}
- <div id="proc_time">
- {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %}
- </div>
- <div style="margin-top: 1em;">
- <script type="text/javascript">
- <!--
- google_ad_client = "pub-8870624642249726";
- /* 468x60, Erstellt 07.03.09 */
- google_ad_slot = "9840041509";
- google_ad_width = 468;
- google_ad_height = 60;
- //-->
- </script>
- <script type="text/javascript"
- src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
- </script>
- </div>
-
- </div>
- <div id="options">
- <h1 class="skip">Options</h1>
- <fieldset><legend id="general"><strong>General Options</strong></legend>
- <div id="general_content" class="content">
- <input type="checkbox" id="id_remove_comments" name="remove_comments" value="1" {% if extra.comments %}checked="checked"{% endif %}/>
- <label for="id_remove_comments">Remove comments</label>
- <br />
- <input type="checkbox" id="id_highlight" name="highlight" value="1" {% if extra.highlight %}checked="checked"{% endif %} />
- <label for="id_highlight">Enable syntax highlighting</label>
- </div>
- </fieldset>
- <fieldset><legend id="kwcase">
- <strong>Keywords &amp; Identifiers</strong></legend>
- <div>
- Keywords: <select id="id_keyword_case" name="keyword_case">
- <option value="">Unchanged</option>
- <option value="lower" {% if extra.keywords == 'lower' %}selected="selected"{% endif %}>Lower case</option>
- <option value="upper" {% if extra.keywords == 'upper' %}selected="selected"{% endif %}>Upper case</option>
- <option value="capitalize" {% if extra.keywords == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option>
- </select>
- </div>
- <div>
- Identifiers: <select name="identifier_case" id="id_identifier_case">
- <option value="">Unchanged</option>
- <option value="lower" {% if extra.idcase == 'lower' %}selected="selected"{% endif %}>Lower case</option>
- <option value="upper" {% if extra.idcase == 'upper' %}selected="selected"{% endif %}>Upper case</option>
- <option value="capitalize" {% if extra.idcase == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option>
- </select>
- </div>
- </fieldset>
- <fieldset><legend id="indent"><strong>Indentation &amp; Margins</strong>
- </legend>
- <div id="indent_content" class="content">
- <label for="id_n_indents">Indentation: </label>
- <input name="n_indents" value="{{extra.n_indents}}" maxlength="2" type="text" id="id_n_indents" size="2" /> spaces
- <div class="help">Empty field means leave indentation unchanged.</div>
- </div>
- </fieldset>
- <fieldset><legend id="output"><strong>Output Format</strong></legend>
- <label for="id_output_format">Language: </label>
- <select name="output_format" id="id_output_format">
- <option value="sql" {% if extra.lang == 'sql' %}selected="selected"{% endif %}>SQL</option>
- <option value="python" {% if extra.lang == 'python' %}selected="selected"{% endif %}>Python</option>
- <option value="php" {% if extra.lang == 'php' %}selected="selected"{% endif %}>PHP</option>
- </select>
- </fieldset>
-
- <div class="dev">This software is in development.</div>
-
- <div>
- <g:plusone size="medium"></g:plusone>
- <a href="http://flattr.com/thing/350724/SQLFormat-Online-SQL-formatting-service" target="_blank">
- <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" />
- </a>
- </div>
- <div style="padding-top: 15px;">
- <a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="andialbrecht">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
- </div>
- </div>
- <div class="clearfix"></div>
-</form>
-
-<script language="javascript">
-html = '<strong>...or select an example:</strong> ';
-html = html + '<select onchange="load_example();" id="sel_example">';
-html = html + '<option value="">-- Choose Example --</option>';
-{% for ex in examples %}
- html = html + '<option value="{{ex}}">{{ex}}</option>';
-{% endfor %}
-html = html + '</select>';
-$('#examples').html(html);
-</script>
-{% endblock %}
-
diff --git a/extras/appengine/sqlformat/templates/master.html b/extras/appengine/sqlformat/templates/master.html
deleted file mode 100644
index 88a9d36..0000000
--- a/extras/appengine/sqlformat/templates/master.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<html>
- <head>
- <title>{% block title %}SQLFormat - Online SQL Formatter{% endblock %}</title>
- <meta name="keywords" content="SQL, format, parse, python, beautify, pretty, online, formatting, formatter" />
- <meta name="description" content="Easy to use web service to format SQL statements." />
- <link rel="stylesheet" href="/static/pygments.css" />
- <link rel="stylesheet" href="/static/styles.css" />
- <script src="http://www.google.com/jsapi"></script>
- <script>
- google.load("jquery", "1.2.6");
- </script>
- <script src="/static/hotkeys.js"></script>
- <script src="/static/script.js"></script>
- </head>
- <body>
-
- <div id="help">
- <p>Keyboard Shortcuts</p>
- <p>
- <span class="shortcut">H</span> - Show / hide this help window<br/>
- <span class="shortcut">Ctrl+F</span> - Format SQL and display result<br/>
- <span class="shortcut">O</span> - Show / hide options<br/>
- <span class="shortcut">T</span> - Set focus on SQL input<br/>
- </p>
- </div>
-
- <div id="header">
- <div id="header-inner">
- {% if user %}<img src="{{userimg}}" border="0" align="right" style="padding-top:.4em;"/>{% endif %}
- <h1>
- <a href="/">
- <span class="q">S<span class="q2">Q</span>L</span>Format
- </a>
- </h1>
- <div id="slogan">Online SQL formatting service</div>
- <div id="topmenu">
- <a href="/">Home</a>
- |
- <a href="/about/">About</a>
- |
- <a href="/source/">Source Code</a>
- |
- <a href="/api/">API</a>
-<!--
- |
- {% if user %}
- <a href="{{logout_url}}">Sign out</a>
- {% else %}
- <a href="{{login_url}}">Sign in</a>
- <span style="color: #babdb6;">with your Google account
- to save preferred settings.</span>
- {% endif %}
--->
- </div>
- </div>
- </div>
-
- <div id="main">
- <div id="main-inner">
- {% block main %}MAIN CONTENT GOES HERE{% endblock %}
- </div>
- </div>
-
- <div id="footer">
- <div id="footer-inner">
- <div style="float: left; font-size: .85em;">
- <div>&copy; 2011 Andi Albrecht&nbsp;&nbsp;
- <code>&lt;albrecht dot andi gmail&gt;</code>
- </div>
- <div>
- <a href="/">Home</a>
- |
- <a href="/about/">About</a>
- |
- <a href="/source/">Source Code</a>
- |
- <a href="/api/">API</a>
- |
- <a href="http://andialbrecht.wordpress.com/">Blog</a>
- </div>
- </div>
- <div style="float: right;">
- <img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif"
- alt="Powered by Google App Engine" />
- </div>
- <div class="clearfix"></div>
- </div>
- </div>
-
- <script type="text/javascript">
- var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
- document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
- </script>
- <script type="text/javascript">
- try {
- var pageTracker = _gat._getTracker("UA-3535525-2");
- pageTracker._trackPageview();
- } catch(err) {}</script>
- <script>init();</script>
- <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
-
- </body>
-</html>
diff --git a/extras/appengine/sqlformat/templates/python-client-example.html b/extras/appengine/sqlformat/templates/python-client-example.html
deleted file mode 100644
index 68bf820..0000000
--- a/extras/appengine/sqlformat/templates/python-client-example.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="highlight example"><pre><span class="c">#!/usr/bin/env python</span>
-
-<span class="k">import</span> <span class="nn">urllib</span>
-<span class="k">import</span> <span class="nn">urllib2</span>
-
-<span class="n">payload</span> <span class="o">=</span> <span class="p">(</span>
- <span class="p">(</span><span class="s">&#39;data&#39;</span><span class="p">,</span> <span class="s">&#39;select * from foo join bar on val1 = val2 where id = 123;&#39;</span><span class="p">),</span>
- <span class="p">(</span><span class="s">&#39;format&#39;</span><span class="p">,</span> <span class="s">&#39;text&#39;</span><span class="p">),</span>
- <span class="p">(</span><span class="s">&#39;keyword_case&#39;</span><span class="p">,</span> <span class="s">&#39;upper&#39;</span><span class="p">),</span>
- <span class="p">(</span><span class="s">&#39;reindent&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
- <span class="p">(</span><span class="s">&#39;n_indents&#39;</span><span class="p">,</span> <span class="mf">2</span><span class="p">),</span>
- <span class="p">)</span>
-
-<span class="n">response</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">&#39;http://sqlformat.appspot.com/format/&#39;</span><span class="p">,</span>
- <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">payload</span><span class="p">))</span>
-<span class="k">print</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
-</pre></div>
diff --git a/extras/appengine/sqlformat/templates/source.html b/extras/appengine/sqlformat/templates/source.html
deleted file mode 100644
index a0ed89d..0000000
--- a/extras/appengine/sqlformat/templates/source.html
+++ /dev/null
@@ -1,60 +0,0 @@
-{% extends "master.html" %}
-
-{% block title %}Source code{% endblock %}
-
-{% block main %}
-<div id="response">
- <h1>Source Code</h1>
-
- <h2>Python Module</h2>
- <p>
- The sources for the SQL parser and formatter module are
- hosted on Google Code.
- To clone the repository run:
- <p>
- <code class="pre"> hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse</code>
- </p>
- <p>
- <a href="http://python-sqlparse.googlecode.com">Visit the project page</a>
- |
- <a href="http://code.google.com/p/python-sqlparse/source/browse/">Browse the sources online</a>
- |
- <a href="http://python-sqlparse.googlecode.com/svn/docs/api/index.html"> API Documentation</a>
- </p>
- <p>
- Some relevant parts of the Python module contain code from the
- <a href="http://pygments.org/">pygments</a> syntax highlighter.
- The underlying Python module uses a non-validating SQL parser.
- This approach makes it possible to parse even syntactically incorrect
- SQL statements.
- </p>
-
- <p>
- Currently the parser module is used by
- <a href="http://crunchyfrog.googlecode.com/">CrunchyFrog</a> - a
- database front-end for Gnome.
- </p>
-
- <p>
- The <code>sqlparse</code> module is released under the terms of the
- <a href="http://www.opensource.org/licenses/bsd-license.php">New BSD License</a>.
- </p>
-
- <h2>App Engine Application</h2>
- <p>
- The source code for this App Engine application is available in the
- <code>examples</code> directory of the Python module
- (but it's really nothing special ;-).
- </p>
-
- <h2>Contributing</h2>
- <p>
- Please file bug reports and feature requests on the project site at
- <a href="http://code.google.com/p/python-sqlparse/issues/entry">http://code.google.com/p/python-sqlparse/issues/entry</a>
- or if you have code to contribute upload it to
- <a href="http://codereview.appspot.com">http://codereview.appspot.com</a>
- and add albrecht.andi@googlemail.com as reviewer.
- </p>
-
-</div>
-{% endblock %}
diff --git a/extras/appengine/static/bg_options.png b/extras/appengine/static/bg_options.png
deleted file mode 100644
index bc1a6ed..0000000
--- a/extras/appengine/static/bg_options.png
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/bgfieldset.png b/extras/appengine/static/bgfieldset.png
deleted file mode 100644
index 4d55f4a..0000000
--- a/extras/appengine/static/bgfieldset.png
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/bgfooter.png b/extras/appengine/static/bgfooter.png
deleted file mode 100644
index 9ce5bdd..0000000
--- a/extras/appengine/static/bgfooter.png
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/bgtop.png b/extras/appengine/static/bgtop.png
deleted file mode 100644
index a0d4709..0000000
--- a/extras/appengine/static/bgtop.png
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/favicon.ico b/extras/appengine/static/favicon.ico
deleted file mode 100644
index 1372520..0000000
--- a/extras/appengine/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/hotkeys.js b/extras/appengine/static/hotkeys.js
deleted file mode 100644
index 0e62a92..0000000
--- a/extras/appengine/static/hotkeys.js
+++ /dev/null
@@ -1 +0,0 @@
-(function(B){B.fn.__bind__=B.fn.bind;B.fn.__unbind__=B.fn.unbind;B.fn.__find__=B.fn.find;var A={version:"0.7.8",override:/keydown|keypress|keyup/g,triggersMap:{},specialKeys:{27:"esc",9:"tab",32:"space",13:"return",8:"backspace",145:"scroll",20:"capslock",144:"numlock",19:"pause",45:"insert",36:"home",46:"del",35:"end",33:"pageup",34:"pagedown",37:"left",38:"up",39:"right",40:"down",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"},newTrigger:function(E,D,F){var C={};C[E]={};C[E][D]={cb:F,disableInInput:false};return C}};if(B.browser.mozilla){A.specialKeys=B.extend(A.specialKeys,{96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9"})}B.fn.find=function(C){this.query=C;return B.fn.__find__.apply(this,arguments)};B.fn.unbind=function(H,E,G){if(B.isFunction(E)){G=E;E=null}if(E&&typeof E==="string"){var F=((this.prevObject&&this.prevObject.query)||(this[0].id&&this[0].id)||this[0]).toString();var D=H.split(" ");for(var C=0;C<D.length;C++){delete A.triggersMap[F][D[C]][E]}}return this.__unbind__(H,G)};B.fn.bind=function(J,F,K){var H=J.match(A.override);if(B.isFunction(F)||!H){return this.__bind__(J,F,K)}else{var N=null,I=B.trim(J.replace(A.override,""));if(I){N=this.__bind__(I,F,K)}if(typeof F==="string"){F={combi:F}}if(F.combi){for(var M=0;M<H.length;M++){var D=H[M];var G=F.combi.toLowerCase(),E=A.newTrigger(D,G,K),L=((this.prevObject&&this.prevObject.query)||(this[0].id&&this[0].id)||this[0]).toString();E[D][G].disableInInput=F.disableInInput;if(!A.triggersMap[L]){A.triggersMap[L]=E}else{if(!A.triggersMap[L][D]){A.triggersMap[L][D]=E[D]}}var C=A.triggersMap[L][D][G];if(!C){A.triggersMap[L][D][G]=[E[D][G]]}else{if(C.constructor!==Array){A.triggersMap[L][D][G]=[C]}else{A.triggersMap[L][D][G][C.length]=E[D][G]}}this.each(function(){var O=B(this);if(O.attr("hkId")&&O.attr("hkId")!==L){L=O.attr("hkId")+";"+L}O.attr("hkId",L)});N=this.__bind__(H.join(" "),F,A.handler)}}return N}};A.findElement=function(C){if(!B(C).attr("hkId")){if(B.browser.opera||B.browser.safari){while(!B(C).attr("hkId")&&C.parentNode){C=C.parentNode}}}return C};A.handler=function(E){var O=A.findElement(E.currentTarget),I=B(O),D=I.attr("hkId");if(D){D=D.split(";");var G=E.which,Q=E.type,P=A.specialKeys[G],N=!P&&String.fromCharCode(G).toLowerCase(),H=E.shiftKey,C=E.ctrlKey,M=E.altKey||E.originalEvent.altKey,F=null;for(var R=0;R<D.length;R++){if(A.triggersMap[D[R]][Q]){F=A.triggersMap[D[R]][Q];break}}if(F){var J;if(!H&&!C&&!M){J=F[P]||(N&&F[N])}else{var L="";if(M){L+="alt+"}if(C){L+="ctrl+"}if(H){L+="shift+"}J=F[L+P];if(!J){if(N){J=F[L+N]||F[L+A.shiftNums[N]]||(L==="shift+"&&F[A.shiftNums[N]])}}}if(J){var S=false;for(var R=0;R<J.length;R++){if(J[R].disableInInput){var K=B(E.target);if(I.is("input")||I.is("textarea")||K.is("input")||K.is("textarea")){return true}}S=S||J[R].cb.apply(this,[E])}return S}}}};window.hotkeys=A;return B})(jQuery); \ No newline at end of file
diff --git a/extras/appengine/static/loading.gif b/extras/appengine/static/loading.gif
deleted file mode 100644
index a879bed..0000000
--- a/extras/appengine/static/loading.gif
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/lynx_screenshot.png b/extras/appengine/static/lynx_screenshot.png
deleted file mode 100644
index d1592ac..0000000
--- a/extras/appengine/static/lynx_screenshot.png
+++ /dev/null
Binary files differ
diff --git a/extras/appengine/static/pygments.css b/extras/appengine/static/pygments.css
deleted file mode 100644
index da02807..0000000
--- a/extras/appengine/static/pygments.css
+++ /dev/null
@@ -1,59 +0,0 @@
-.c { color: #408080; font-style: italic } /* Comment */
-.err { border: 1px solid #FF0000 } /* Error */
-.k { color: #008000; font-weight: bold } /* Keyword */
-.o { color: #666666 } /* Operator */
-.cm { color: #408080; font-style: italic } /* Comment.Multiline */
-.cp { color: #BC7A00 } /* Comment.Preproc */
-.c1 { color: #408080; font-style: italic } /* Comment.Single */
-.cs { color: #408080; font-style: italic } /* Comment.Special */
-.gd { color: #A00000 } /* Generic.Deleted */
-.ge { font-style: italic } /* Generic.Emph */
-.gr { color: #FF0000 } /* Generic.Error */
-.gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.gi { color: #00A000 } /* Generic.Inserted */
-.go { color: #808080 } /* Generic.Output */
-.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
-.gs { font-weight: bold } /* Generic.Strong */
-.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.gt { color: #0040D0 } /* Generic.Traceback */
-.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.kp { color: #008000 } /* Keyword.Pseudo */
-.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.kt { color: #B00040 } /* Keyword.Type */
-.m { color: #666666 } /* Literal.Number */
-.s { color: #BA2121 } /* Literal.String */
-.na { color: #7D9029 } /* Name.Attribute */
-.nb { color: #008000 } /* Name.Builtin */
-.nc { color: #0000FF; font-weight: bold } /* Name.Class */
-.no { color: #880000 } /* Name.Constant */
-.nd { color: #AA22FF } /* Name.Decorator */
-.ni { color: #999999; font-weight: bold } /* Name.Entity */
-.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
-.nf { color: #0000FF } /* Name.Function */
-.nl { color: #A0A000 } /* Name.Label */
-.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
-.nt { color: #008000; font-weight: bold } /* Name.Tag */
-.nv { color: #19177C } /* Name.Variable */
-.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
-.w { color: #bbbbbb } /* Text.Whitespace */
-.mf { color: #666666 } /* Literal.Number.Float */
-.mh { color: #666666 } /* Literal.Number.Hex */
-.mi { color: #666666 } /* Literal.Number.Integer */
-.mo { color: #666666 } /* Literal.Number.Oct */
-.sb { color: #BA2121 } /* Literal.String.Backtick */
-.sc { color: #BA2121 } /* Literal.String.Char */
-.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
-.s2 { color: #BA2121 } /* Literal.String.Double */
-.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
-.sh { color: #BA2121 } /* Literal.String.Heredoc */
-.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
-.sx { color: #008000 } /* Literal.String.Other */
-.sr { color: #BB6688 } /* Literal.String.Regex */
-.s1 { color: #BA2121 } /* Literal.String.Single */
-.ss { color: #19177C } /* Literal.String.Symbol */
-.bp { color: #008000 } /* Name.Builtin.Pseudo */
-.vc { color: #19177C } /* Name.Variable.Class */
-.vg { color: #19177C } /* Name.Variable.Global */
-.vi { color: #19177C } /* Name.Variable.Instance */
-.il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/extras/appengine/static/robots.txt b/extras/appengine/static/robots.txt
deleted file mode 100644
index c033917..0000000
--- a/extras/appengine/static/robots.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Directions for web crawlers.
-# See http://www.robotstxt.org/wc/norobots.html.
-
-User-agent: HTTrack
-User-agent: puf
-User-agent: MSIECrawler
-User-agent: Nutch
-Disallow: /
diff --git a/extras/appengine/static/script.js b/extras/appengine/static/script.js
deleted file mode 100644
index 8bdf271..0000000
--- a/extras/appengine/static/script.js
+++ /dev/null
@@ -1,98 +0,0 @@
-var initialized = false;
-
-function update_output() {
- data = {}
- data.data = $('#id_data').val();
- data.format = 'json';
- if ( $('#id_remove_comments').attr('checked') ) {
- data.remove_comments = 1
- }
- if ( $('#id_highlight').attr('checked') ) { data.highlight = 1 }
- data.keyword_case = $('#id_keyword_case').val();
- data.identifier_case = $('#id_identifier_case').val();
- data.n_indents = $('#id_n_indents').val();
- data.output_format = $('#id_output_format').val();
- form = document.getElementById('form_options');
- $(form.elements).attr('disabled', 'disabled');
- $('#response').addClass('loading');
- $.post('/', data,
- function(data) {
- if ( data.output ) {
- $('#response').html(data.output);
- proc_time = 'Processed in '+data.proc_time+' seconds.';
- } else {
- $('#response').html('An error occured: '+data.errors);
- proc_time = '';
- }
- $('#proc_time').html(proc_time);
- $(form.elements).each( function(idx) {
- obj = $(this);
- if ( ! obj.is('.keep-disabled') ) {
- obj.removeAttr('disabled');
- }
- });
- $('#response').removeClass('loading');
- }, 'json');
- return false;
-}
-
-function toggle_fieldset(event) {
- id = $(this).attr('id');
- $('#'+id+'_content').slideDown();
- $('legend').each(function(idx) {
- obj = $('#'+this.id+'_content');
- if ( this.id != id ) {
- obj.slideUp();
- }
- });
-}
-
-
-function textarea_grab_focus(evt) {
- evt.stopPropagation();
- evt.preventDefault();
- $('#id_data').focus();
- return false;
-}
-
-
-function show_help() {
- $('#help').toggle();
- return false;
-}
-
-
-function hide_help() {
- $('#help').hide();
- return false;
-}
-
-function load_example() {
- fname = $('#sel_example').val();
- data = {fname: fname};
- $.post('/load_example', data,
- function(data) {
- $('#id_data').val(data.answer);
- }, 'json');
-}
-
-
-function init() {
- if (initialized) { return }
- //$('legend').bind('click', toggle_fieldset);
- // $('legend').each(function(idx) {
- // obj = $('#'+this.id+'_content');
- // if ( this.id != 'general' ) {
- // obj.hide();
- // }
- // });
- $(document).bind('keydown', {combi:'Ctrl+f'},
- update_output);
- $('#btn_format').val('Format SQL [Ctrl+F]');
- $(document).bind('keydown', {combi: 'h', disableInInput: true},
- show_help);
- $(document).bind('keydown', 'Esc', hide_help);
- $(document).bind('keydown', {combi: 't', disableInInput: true},
- textarea_grab_focus);
- initialized = true;
-} \ No newline at end of file
diff --git a/extras/appengine/static/sitemap.xml b/extras/appengine/static/sitemap.xml
deleted file mode 100644
index db3288e..0000000
--- a/extras/appengine/static/sitemap.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<urlset
- xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
- http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
-<!-- created with Free Online Sitemap Generator www.xml-sitemaps.com -->
-
-<url>
- <loc>http://sqlformat.appspot.com/</loc>
- <changefreq>monthly</changefreq>
-</url>
-<url>
- <loc>http://sqlformat.appspot.com/about/</loc>
- <changefreq>monthly</changefreq>
-</url>
-<url>
- <loc>http://sqlformat.appspot.com/source/</loc>
- <changefreq>monthly</changefreq>
-</url>
-<url>
- <loc>http://sqlformat.appspot.com/api/</loc>
- <changefreq>monthly</changefreq>
-</url>
-</urlset> \ No newline at end of file
diff --git a/extras/appengine/static/sqlformat_client_example.py b/extras/appengine/static/sqlformat_client_example.py
deleted file mode 100644
index 8b2a9e9..0000000
--- a/extras/appengine/static/sqlformat_client_example.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-
-import urllib
-import urllib2
-
-REMOTE_API = 'http://sqlformat.appspot.com/format/'
-
-payload = (
- ('data', 'select * from foo join bar on val1 = val2 where id = 123;'),
- ('format', 'text'),
- ('keyword_case', 'upper'),
- ('reindent', True),
- ('n_indents', 2),
- )
-
-
-response = urllib2.urlopen(REMOTE_API,
- urllib.urlencode(payload))
-print response.read()
-
diff --git a/extras/appengine/static/styles.css b/extras/appengine/static/styles.css
deleted file mode 100644
index 41a540a..0000000
--- a/extras/appengine/static/styles.css
+++ /dev/null
@@ -1,245 +0,0 @@
-body {
- color: #000000;
- background: #eeeeec;
- font-family: "Free Sans", Arial, Verdana, sans;
- font-size: 10pt;
- margin: 0;
- padding: 0;
-}
-
-#header {
- background: url(/static/bgtop.png) top left repeat-x;
- border-bottom: 3px solid #2e3436;
-}
-
-#header-inner, #main-inner, #footer-inner {
- width: 70em;
- margin-left: auto;
- margin-right: auto;
-}
-
-
-#header-inner h1 {
- margin: 0;
- padding: 0;
- margin-bottom: .2em;
- font-weight: normal;
- float: left;
- font-size: 2em;
- letter-spacing: .07em;
-}
-
-#header-inner .q {
- color: #f57900;
- padding-right: 3px;
-}
-
-#header-inner .q2 {
- font-family: Georgia, "Times New Roman", serif;
-}
-
-#header-inner h1 a {
- text-decoration: none;
- color: #eeeeec;
-}
-
-#header-inner #slogan {
- float: left;
- color: #babdb6;
- font-size: 1.4em;
- margin-left: 1em;
- letter-spacing: .18em;
- padding-top: .2em;
-}
-
-
-#topmenu {
- color: #729fcf;
- clear: left;
- padding-top: .5em;
- padding-bottom: .5em;
- font-size: 1.1em;
-}
-
-#topmenu a {
- color: #eeeeec;
- text-decoration: none;
-}
-
-#topmenu a:hover {
- color: #ce5c00;
-}
-
-
-#main {
- padding: 10px;
- background: white;
- line-height: 1.5em;
- text-align: justify;
-}
-
-#main form ul {
- margin: 0;
- padding: 0;
- list-style-type: none;
-}
-
-#main p, #main ol, #main .example, #main dl {
- font-size: 12pt;
- margin-left: 2em;
-}
-
-#main dt {
- font-weight: bold;
-}
-
-#main li {
- margin-bottom: .7em;
-}
-
-#main a {
- color: #f57900;
-}
-
-#main h1, h2, h3, h4 {
- color: #204a87;
- font-weight: normal;
- letter-spacing: .05em;
-}
-
-#main pre, #main code.pre {
- font-size: 10pt;
- line-height: 1em;
- padding: 4px;
- background-color: #eeeeec;
- border: 1px solid #babdb6;
-}
-
-#input {
- width: 50em;
- float: right;
- margin-left: 2em;
-}
-
-#options {
- width: 18em;
- float: left;
- color: #2e3436;
- margin-top: .75em;
- text-align: left;
-}
-
-#options fieldset {
- border: 1px solid #dddddd;
- margin-bottom: .6em;
- background: url(/static/bgfieldset.png) bottom left repeat-x;
- -moz-border-radius: 3px;
-}
-
-
-#options input, select {
- border: 1px solid #dddddd;
-}
-
-#options .help {
- font-size: .9em;
- color: #888a85;
- margin-bottom: .6em;
-}
-
-
-#footer {
- background: url(/static/bgfooter.png) top left repeat-x;
- padding: 10px;
- min-height: 80px;
- border-top: 4px solid #babdb6;
-}
-
-#footer-inner {
- width: 70em;
- margin-left: auto;
- margin-right: auto;
- color: #888a85;
-}
-
-#footer-inner a {
- color: #888a85;
-}
-
-#footer-inner a:hover {
- color: #555753;
-}
-
-.clearfix {
- clear: both;
-}
-
-.skip {
- display: none;
-}
-
-textarea {
- border: 1px solid #cccccc;
- border-bottom: none;
- padding: 4px;
- font-size: 12pt;
- width: 100%;
-}
-
-textarea:focus {
- background-color: #eeeeec;
-}
-
-div.grippie {
- background: url(/static/resize-grip.png) bottom right no-repeat #eeeeec;
- border-color: #cccccc;
- border-style: solid;
- border-width: 0pt 1px 1px;
- cursor: se-resize;
- height: 14px;
- overflow: hidden;
-}
-
-#help {
- display: none;
- position: fixed;
- right: 10%;
- left: 10%;
- top: 0;
- opacity: 0.85;
- -moz-opacity: 0.85;
- -khtml-opacity: 0.85;
- filter: alpha(opacity=85);
- -moz-border-radius: 0px 0px 10px 10px;
-
- background: #2e3436;
- color: white;
- font-weight: bold;
-
- padding: 1em;
- z-index: 1;
- overflow-x: hidden;
- overflow-y: auto;
-}
-
-#help .shortcut {
- color: #f57900;
- font-weight: bold;
- width: 20px;
- display: inline;
-}
-
-.loading {
- background: url(/static/loading.gif) top left no-repeat;
-}
-
-.dev {
- color: #cc0000;
- font-size: .9em;
- letter-spacing: 1;
-}
-
-#proc_time {
- color: #888a85;
- font-size: .85em;
-} \ No newline at end of file
diff --git a/extras/buildbot/googlecode_atom.py b/extras/buildbot/googlecode_atom.py
deleted file mode 100644
index 0d4631f..0000000
--- a/extras/buildbot/googlecode_atom.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# GoogleCode Atom Feed Poller
-# Author: Srivats P. <pstavirs>
-# Based on Mozilla's HgPoller
-# http://bonsai.mozilla.org/cvsblame.cgi?file=/mozilla/tools/buildbot/buildbot/changes/Attic/hgpoller.py&revision=1.1.4.2
-#
-# Description:
-# Use this ChangeSource for projects hosted on http://code.google.com/
-#
-# This ChangeSource uses the project's commit Atom feed. Depending upon the
-# frequency of commits, you can tune the polling interval for the feed
-# (default is 1 hour)
-#
-# Parameters:
-# feedurl (MANDATORY): The Atom feed URL of the GoogleCode repo
-# pollinterval (OPTIONAL): Polling frequency for the feed (in seconds)
-#
-# Example:
-# To poll the Ostinato project's commit feed every 3 hours, use -
-# from googlecode_atom import GoogleCodeAtomPoller
-# poller = GoogleCodeAtomPoller(
-# feedurl="http://code.google.com/feeds/p/ostinato/hgchanges/basic",
-# pollinterval=10800)
-# c['change_source'] = [ poller ]
-#
-
-from time import strptime
-from calendar import timegm
-from xml.dom import minidom, Node
-
-from twisted.python import log, failure
-from twisted.internet import defer, reactor
-from twisted.internet.task import LoopingCall
-from twisted.web.client import getPage
-
-from buildbot.changes import base, changes
-
-def googleCodePollerForProject(project, vcs, pollinterval=3600):
- return GoogleCodeAtomPoller(
- 'http://code.google.com/feeds/p/%s/%schanges/basic' % (project, vcs),
- pollinterval=pollinterval)
-
-
-class GoogleCodeAtomPoller(base.ChangeSource):
- """This source will poll a GoogleCode Atom feed for changes and
- submit them to the change master. Works for both Svn and Hg repos.
- TODO: branch processing
- """
-
- compare_attrs = ['feedurl', 'pollinterval']
- parent = None
- loop = None
- volatile = ['loop']
- working = False
-
- def __init__(self, feedurl, pollinterval=3600):
- """
- @type feedurl: string
- @param feedurl: The Atom feed URL of the GoogleCode repo
- (e.g. http://code.google.com/feeds/p/ostinato/hgchanges/basic)
-
- @type pollinterval: int
- @param pollinterval: The time (in seconds) between queries for
- changes (default is 1 hour)
- """
-
- self.feedurl = feedurl
- self.branch = None
- self.pollinterval = pollinterval
- self.lastChange = None
- self.loop = LoopingCall(self.poll)
-
- def startService(self):
- log.msg("GoogleCodeAtomPoller starting")
- base.ChangeSource.startService(self)
- reactor.callLater(0, self.loop.start, self.pollinterval)
-
- def stopService(self):
- log.msg("GoogleCodeAtomPoller stoppping")
- self.loop.stop()
- return base.ChangeSource.stopService(self)
-
- def describe(self):
- return ("Getting changes from the GoogleCode repo changes feed %s" %
- self._make_url())
-
- def poll(self):
- if self.working:
- log.msg("Not polling because last poll is still working")
- else:
- self.working = True
- d = self._get_changes()
- d.addCallback(self._process_changes)
- d.addCallbacks(self._finished_ok, self._finished_failure)
-
- def _finished_ok(self, res):
- assert self.working
- self.working = False
- log.msg("GoogleCodeAtomPoller poll success")
-
- return res
-
- def _finished_failure(self, res):
- log.msg("GoogleCodeAtomPoller poll failed: %s" % res)
- assert self.working
- self.working = False
- return None
-
- def _make_url(self):
- return "%s" % (self.feedurl)
-
- def _get_changes(self):
- url = self._make_url()
- log.msg("GoogleCodeAtomPoller polling %s" % url)
-
- return getPage(url, timeout=self.pollinterval)
-
- def _parse_changes(self, query):
- dom = minidom.parseString(query)
- entries = dom.getElementsByTagName("entry")
- changes = []
- # Entries come in reverse chronological order
- for i in entries:
- d = {}
-
- # revision is the last part of the 'id' url
- d["revision"] = i.getElementsByTagName(
- "id")[0].firstChild.data.split('/')[-1]
- if d["revision"] == self.lastChange:
- break # no more new changes
-
- d["when"] = timegm(strptime(
- i.getElementsByTagName("updated")[0].firstChild.data,
- "%Y-%m-%dT%H:%M:%SZ"))
- d["author"] = i.getElementsByTagName(
- "author")[0].getElementsByTagName("name")[0].firstChild.data
- # files and commit msg are separated by 2 consecutive <br/>
- content = i.getElementsByTagName(
- "content")[0].firstChild.data.split("<br/>\n <br/>")
- # Remove the action keywords from the file list
- fl = content[0].replace(
- u' \xa0\xa0\xa0\xa0Add\xa0\xa0\xa0\xa0', '').replace(
- u' \xa0\xa0\xa0\xa0Delete\xa0\xa0\xa0\xa0', '').replace(
- u' \xa0\xa0\xa0\xa0Modify\xa0\xa0\xa0\xa0', '')
- # Get individual files and remove the 'header'
- d["files"] = fl.encode("ascii", "replace").split("<br/>")[1:]
- d["files"] = [f.strip() for f in d["files"]]
- try:
- d["comments"] = content[1].encode("ascii", "replace")
- except:
- d["comments"] = "No commit message provided"
-
- changes.append(d)
-
- changes.reverse() # want them in chronological order
- return changes
-
- def _process_changes(self, query):
- change_list = self._parse_changes(query)
-
- # Skip calling addChange() if this is the first successful poll.
- if self.lastChange is not None:
- for change in change_list:
- c = changes.Change(revision = change["revision"],
- who = change["author"],
- files = change["files"],
- comments = change["comments"],
- when = change["when"],
- branch = self.branch)
- self.parent.addChange(c)
- if change_list:
- self.lastChange = change_list[-1]["revision"]
diff --git a/extras/buildbot/master.cfg b/extras/buildbot/master.cfg
deleted file mode 100644
index 92403fe..0000000
--- a/extras/buildbot/master.cfg
+++ /dev/null
@@ -1,264 +0,0 @@
-# -*- python -*-
-# ex: set syntax=python:
-
-# This is a sample buildmaster config file. It must be installed as
-# 'master.cfg' in your buildmaster's base directory (although the filename
-# can be changed with the --basedir option to 'mktap buildbot master').
-
-# It has one job: define a dictionary named BuildmasterConfig. This
-# dictionary has a variety of keys to control different aspects of the
-# buildmaster. They are documented in docs/config.xhtml .
-
-PYTHON_VERSIONS = ('2.4', '2.5', '2.6', '2.7', '3.2')
-
-
-# This is the dictionary that the buildmaster pays attention to. We also use
-# a shorter alias to save typing.
-c = BuildmasterConfig = {}
-
-####### DB URL
-
-# This specifies what database buildbot uses to store change and scheduler
-# state
-c['db_url'] = "sqlite:///state.sqlite"
-
-####### BUILDSLAVES
-
-# the 'slaves' list defines the set of allowable buildslaves. Each element is
-# a BuildSlave object, which is created with bot-name, bot-password. These
-# correspond to values given to the buildslave's mktap invocation.
-from buildbot.buildslave import BuildSlave
-c['slaves'] = [BuildSlave("bot1linux", "imtheslave")]
-
-# to limit to two concurrent builds on a slave, use
-# c['slaves'] = [BuildSlave("bot1name", "bot1passwd", max_builds=2)]
-
-
-# 'slavePortnum' defines the TCP port to listen on. This must match the value
-# configured into the buildslaves (with their --master option)
-
-c['slavePortnum'] = 9989
-
-####### CHANGESOURCES
-
-# the 'change_source' setting tells the buildmaster how it should find out
-# about source code changes. Any class which implements IChangeSource can be
-# put here: there are several in buildbot/changes/*.py to choose from.
-
-from buildbot.changes.pb import PBChangeSource
-c['change_source'] = PBChangeSource()
-
-from googlecode_atom import GoogleCodeAtomPoller
-poller = GoogleCodeAtomPoller(
- feedurl="http://code.google.com/feeds/p/python-sqlparse/hgchanges/basic",
- pollinterval=600)
-c['change_source'] = [ poller ]
-
-# For example, if you had CVSToys installed on your repository, and your
-# CVSROOT/freshcfg file had an entry like this:
-#pb = ConfigurationSet([
-# (None, None, None, PBService(userpass=('foo', 'bar'), port=4519)),
-# ])
-
-# then you could use the following buildmaster Change Source to subscribe to
-# the FreshCVS daemon and be notified on every commit:
-#
-#from buildbot.changes.freshcvs import FreshCVSSource
-#fc_source = FreshCVSSource("cvs.example.com", 4519, "foo", "bar")
-#c['change_source'] = fc_source
-
-# or, use a PBChangeSource, and then have your repository's commit script run
-# 'buildbot sendchange', or use contrib/svn_buildbot.py, or
-# contrib/arch_buildbot.py :
-#
-#from buildbot.changes.pb import PBChangeSource
-#c['change_source'] = PBChangeSource()
-
-# If you wat to use SVNPoller, it might look something like
-# # Where to get source code changes
-# from buildbot.changes.svnpoller import SVNPoller
-# source_code_svn_url='https://svn.myproject.org/bluejay/trunk'
-# svn_poller = SVNPoller(
-# svnurl=source_code_svn_url,
-# pollinterval=60*60, # seconds
-# histmax=10,
-# svnbin='/usr/bin/svn',
-## )
-# c['change_source'] = [ svn_poller ]
-
-####### SCHEDULERS
-
-## configure the Schedulers
-
-from buildbot.scheduler import Scheduler
-c['schedulers'] = []
-for py_ver in PYTHON_VERSIONS:
- c['schedulers'].append(
- Scheduler(name="py%s" % py_ver, branch=None,
- treeStableTimer=2*60,
- builderNames=["builder-%s" % py_ver]))
-
-
-####### BUILDERS
-
-# the 'builders' list defines the Builders. Each one is configured with a
-# dictionary, using the following keys:
-# name (required): the name used to describe this builder
-# slavename or slavenames (required): which slave(s) to use (must appear in c['slaves'])
-# factory (required): a BuildFactory to define how the build is run
-# builddir (optional): which subdirectory to run the builder in
-
-# buildbot/process/factory.py provides several BuildFactory classes you can
-# start with, which implement build processes for common targets (GNU
-# autoconf projects, CPAN perl modules, etc). The factory.BuildFactory is the
-# base class, and is configured with a series of BuildSteps. When the build
-# is run, the appropriate buildslave is told to execute each Step in turn.
-
-# the first BuildStep is typically responsible for obtaining a copy of the
-# sources. There are source-obtaining Steps in buildbot/steps/source.py for
-# CVS, SVN, and others.
-
-cvsroot = ":pserver:anonymous@cvs.sourceforge.net:/cvsroot/buildbot"
-cvsmodule = "buildbot"
-
-from buildbot.process import factory
-from buildbot.steps.source import CVS, Mercurial
-from buildbot.steps.shell import Compile, ShellCommand
-from buildbot.steps.python_twisted import Trial
-f1 = factory.BuildFactory()
-f1.addStep(CVS(cvsroot=cvsroot, cvsmodule=cvsmodule, login="", mode="copy"))
-f1.addStep(Compile(command=["python", "./setup.py", "build"]))
-f1.addStep(Trial(testChanges=True, testpath="."))
-
-from buildbot.config import BuilderConfig
-
-def _mk_factory(py_ver):
- py_bin = "/home/build/python/python%(ver)s/bin/python%(ver)s" % {"ver": py_ver}
- py2to3 = "/home/build/python/python%(ver)s/bin/2to3" % {"ver": py_ver}
- site_pkgs = "/home/build/python/python%(ver)s/lib/site-packages/sqlparse" % {"ver": py_ver}
- is_py3k = bool(py_ver.startswith("3"))
- workdir = "build/"
- f = factory.BuildFactory()
- f.addStep(Mercurial(repourl="http://python-sqlparse.googlecode.com/hg/"))
- f.addStep(ShellCommand(command=["rm", "-rf", site_pkgs],
- description="removing installed package",
- descriptionDone="site-pkgs clean"))
- if is_py3k:
- workdir = "build/extras/py3k/"
- f.addStep(ShellCommand(command=["make", "clean"],
- workdir=workdir,
- description="cleaning up",
- descriptionDone="cleaned up"))
- f.addStep(ShellCommand(command=["make", "2TO3=%s" % py2to3],
- workdir=workdir,
- description="creating py3 version",
- descriptionDone="py3 version created"))
- f.addStep(Compile(command=[py_bin, "setup.py", "build"],
- workdir=workdir))
- f.addStep(ShellCommand(command=[py_bin, "setup.py", "install"],
- description="installing module",
- descriptionDone="module installed",
- workdir=workdir))
- f.addStep(ShellCommand(command=["mv", "sqlparse", "_sqlparse"],
- description="moving local module",
- descriptionDone="local module moved",
- workdir=workdir))
- f.addStep(ShellCommand(command=[py_bin, "tests/run_tests.py"],
- description="running tests",
- descriptionDone="tests done",
- workdir=workdir))
- f.addStep(ShellCommand(command=["mv", "_sqlparse", "sqlparse"],
- description="restoring local module",
- descriptionDone="local module restored",
- workdir=workdir))
- return f
-
-def _mk_builder(py_ver):
- return BuilderConfig(
- name="builder-%s" % py_ver,
- slavename="bot1linux",
- builddir="full-%s" % py_ver,
- factory=_mk_factory(py_ver))
-
-c['builders'] = []
-for py_ver in PYTHON_VERSIONS:
- c['builders'].append(_mk_builder(py_ver))
-
-
-####### STATUS TARGETS
-
-# 'status' is a list of Status Targets. The results of each build will be
-# pushed to these targets. buildbot/status/*.py has a variety to choose from,
-# including web pages, email senders, and IRC bots.
-
-c['status'] = []
-
-from buildbot.status import html
-from buildbot.status.web import auth, authz
-authz_cfg=authz.Authz(
- # change any of these to True to enable; see the manual for more
- # options
- gracefulShutdown = False,
- forceBuild = True,
- forceAllBuilds = True,
- pingBuilder = True,
- stopBuild = False,
- stopAllBuilds = False,
- cancelPendingBuild = True,
-)
-c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg))
-
-from buildbot.status import mail
-c['status'].append(mail.MailNotifier(
- fromaddr="buildbot@andialbrecht.de",
- extraRecipients=["albrecht.andi@gmail.com"],
- sendToInterestedUsers=False,
- mode="failing"))
-#
-# from buildbot.status import words
-# c['status'].append(words.IRC(host="irc.example.com", nick="bb",
-# channels=["#example"]))
-# c['status'].append(words.IRC(host="irc.example.com", nick="bb",
-# channels=["#example"], useSSL=True))
-#
-# from buildbot.status import client
-# c['status'].append(client.PBListener(9988))
-
-
-####### DEBUGGING OPTIONS
-
-# if you set 'debugPassword', then you can connect to the buildmaster with
-# the diagnostic tool in contrib/debugclient.py . From this tool, you can
-# manually force builds and inject changes, which may be useful for testing
-# your buildmaster without actually committing changes to your repository (or
-# before you have a functioning 'sources' set up). The debug tool uses the
-# same port number as the slaves do: 'slavePortnum'.
-
-#c['debugPassword'] = "debugpassword"
-
-# if you set 'manhole', you can ssh into the buildmaster and get an
-# interactive python shell, which may be useful for debugging buildbot
-# internals. It is probably only useful for buildbot developers. You can also
-# use an authorized_keys file, or plain telnet.
-#from buildbot import manhole
-#c['manhole'] = manhole.PasswordManhole("tcp:9999:interface=127.0.0.1",
-# "admin", "password")
-
-
-####### PROJECT IDENTITY
-
-# the 'projectName' string will be used to describe the project that this
-# buildbot is working on. For example, it is used as the title of the
-# waterfall HTML page. The 'projectURL' string will be used to provide a link
-# from buildbot HTML pages to your project's home page.
-
-c['projectName'] = "python-sqlparse"
-c['projectURL'] = "http://python-sqlparse.googlecode.com"
-
-# the 'buildbotURL' string should point to the location where the buildbot's
-# internal web server (usually the html.WebStatus page) is visible. This
-# typically uses the port number set in the Waterfall 'status' entry, but
-# with an externally-visible host name which the buildbot cannot figure out
-# without some help.
-
-c['buildbotURL'] = "http://buildbot.andialbrecht.de"
diff --git a/extras/sqlformat.png b/extras/sqlformat.png
deleted file mode 100644
index 4189bc4..0000000
--- a/extras/sqlformat.png
+++ /dev/null
Binary files differ
diff --git a/extras/sqlformat.svg b/extras/sqlformat.svg
deleted file mode 100644
index 59e1183..0000000
--- a/extras/sqlformat.svg
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="120"
- height="60"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.46"
- version="1.0"
- sodipodi:docname="sqlformat.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape">
- <defs
- id="defs4">
- <linearGradient
- id="linearGradient3163">
- <stop
- id="stop3165"
- offset="0"
- style="stop-color:#888a85;stop-opacity:1;" />
- <stop
- id="stop3167"
- offset="1"
- style="stop-color:#565854;stop-opacity:1;" />
- </linearGradient>
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 526.18109 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="744.09448 : 526.18109 : 1"
- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
- id="perspective10" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3163"
- id="linearGradient3161"
- x1="57.357143"
- y1="1.6964277"
- x2="57.464291"
- y2="58.125"
- gradientUnits="userSpaceOnUse" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="5.6"
- inkscape:cx="58.539628"
- inkscape:cy="24.488765"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="1436"
- inkscape:window-height="720"
- inkscape:window-x="209"
- inkscape:window-y="171" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Ebene 1"
- inkscape:groupmode="layer"
- id="layer1">
- <rect
- style="fill:url(#linearGradient3161);fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.5103448;fill-opacity:1"
- id="rect2383"
- width="118.21429"
- height="58.035713"
- x="1.0714285"
- y="1.0714284"
- ry="3.5714285" />
- <text
- xml:space="preserve"
- style="font-size:41.68727112px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:FreeSans;-inkscape-font-specification:FreeSans"
- x="3.8212376"
- y="38.731842"
- id="text3169"
- transform="scale(1.3303696,0.7516708)"><tspan
- sodipodi:role="line"
- id="tspan3171"
- x="3.8212376"
- y="38.731842">S<tspan
- style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Georgia;-inkscape-font-specification:Georgia Italic"
- id="tspan3173">Q</tspan>L</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:29.59413719px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:FreeSans;-inkscape-font-specification:FreeSans"
- x="5.0176215"
- y="60.359047"
- id="text3177"
- transform="scale(1.1410205,0.8764084)"><tspan
- sodipodi:role="line"
- id="tspan3179"
- x="5.0176215"
- y="60.359047">Format</tspan></text>
- </g>
-</svg>
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index a2cbd90..0000000
--- a/pytest.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[pytest]
-pep8ignore =
- extras/* ALL
- examples/* ALL
- docs/* ALL
- * E125 E127
diff --git a/setup.py b/setup.py
index 2c6dce8..c867e50 100644
--- a/setup.py
+++ b/setup.py
@@ -4,16 +4,10 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php.
import re
-import sys
-try:
- from setuptools import setup, find_packages
- packages = find_packages(exclude=('tests',))
-except ImportError:
- if sys.version_info[0] == 3:
- raise RuntimeError('distribute is required to install this package.')
- from distutils.core import setup
- packages = ['sqlparse', 'sqlparse.engine']
+from setuptools import setup, find_packages
+
+packages = find_packages(exclude=('tests',))
def get_version():
@@ -21,7 +15,7 @@ def get_version():
see http://stackoverflow.com/questions/458550/standard-way-to-embed-version-into-python-package
"""
- VERSIONFILE='sqlparse/__init__.py'
+ VERSIONFILE = 'sqlparse/__init__.py'
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r'^__version__ = [\'"]([^\'"]*)[\'"]'
mo = re.search(VSRE, verstrline, re.M)
@@ -86,11 +80,6 @@ Parsing::
VERSION = get_version()
-kwargs = {}
-if sys.version_info[0] == 3:
- kwargs['use_2to3'] = True
-
-
setup(
name='sqlparse',
version=VERSION,
@@ -108,16 +97,13 @@ setup(
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.4',
- 'Programming Language :: Python :: 2.5',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4'
'Topic :: Database',
'Topic :: Software Development'
],
scripts=['bin/sqlformat'],
- **kwargs
)
diff --git a/sqlparse/__init__.py b/sqlparse/__init__.py
index 83bb684..d943956 100644
--- a/sqlparse/__init__.py
+++ b/sqlparse/__init__.py
@@ -8,15 +8,12 @@
__version__ = '0.1.17-dev'
-
# Setup namespace
+from sqlparse import compat
from sqlparse import engine
from sqlparse import filters
from sqlparse import formatter
-# Deprecated in 0.1.5. Will be removed in 0.2.0
-from sqlparse.exceptions import SQLParseError
-
def parse(sql, encoding=None):
"""Parse sql and return a list of statements.
@@ -67,7 +64,8 @@ def split(sql, encoding=None):
"""
stack = engine.FilterStack()
stack.split_statements = True
- return [unicode(stmt).strip() for stmt in stack.run(sql, encoding)]
+ return [compat.text_type(stmt).strip()
+ for stmt in stack.run(sql, encoding)]
from sqlparse.engine.filter import StatementFilter
diff --git a/sqlparse/compat.py b/sqlparse/compat.py
new file mode 100644
index 0000000..1849c13
--- /dev/null
+++ b/sqlparse/compat.py
@@ -0,0 +1,39 @@
+"""Python 2/3 compatibility.
+
+This module only exists to avoid a dependency on six
+for very trivial stuff. We only need to take care regarding
+string types and buffers.
+"""
+
+import sys
+
+PY2 = sys.version_info[0] == 2
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+ text_type = str
+ string_types = (str,)
+ from io import StringIO
+
+ def u(s):
+ return s
+
+elif PY2:
+ text_type = unicode
+ string_types = (basestring,)
+ from StringIO import StringIO # flake8: noqa
+
+ def u(s):
+ return unicode(s, 'unicode_escape')
+
+
+# Directly copied from six:
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ # This requires a bit of explanation: the basic idea is to make a dummy
+ # metaclass for one level of class instantiation that replaces itself with
+ # the actual metaclass.
+ class metaclass(meta):
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+ return type.__new__(metaclass, 'temporary_class', (), {})
diff --git a/sqlparse/engine/grouping.py b/sqlparse/engine/grouping.py
index a317044..12ae385 100644
--- a/sqlparse/engine/grouping.py
+++ b/sqlparse/engine/grouping.py
@@ -5,11 +5,6 @@ import itertools
from sqlparse import sql
from sqlparse import tokens as T
-try:
- next
-except NameError: # Python < 2.6
- next = lambda i: i.next()
-
def _group_left_right(tlist, ttype, value, cls,
check_right=lambda t: True,
@@ -116,7 +111,7 @@ def group_as(tlist):
def _right_valid(token):
# Currently limited to DML/DDL. Maybe additional more non SQL reserved
# keywords should appear here (see issue8).
- return not token.ttype in (T.DML, T.DDL)
+ return token.ttype not in (T.DML, T.DDL)
def _left_valid(token):
if token.ttype is T.Keyword and token.value in ('NULL',):
@@ -216,9 +211,10 @@ def group_identifier(tlist):
if identifier_tokens and identifier_tokens[-1].ttype is T.Whitespace:
identifier_tokens = identifier_tokens[:-1]
if not (len(identifier_tokens) == 1
- and (isinstance(identifier_tokens[0], (sql.Function, sql.Parenthesis))
- or identifier_tokens[0].ttype in (T.Literal.Number.Integer,
- T.Literal.Number.Float))):
+ and (isinstance(identifier_tokens[0], (sql.Function,
+ sql.Parenthesis))
+ or identifier_tokens[0].ttype in (
+ T.Literal.Number.Integer, T.Literal.Number.Float))):
group = tlist.group_tokens(sql.Identifier, identifier_tokens)
idx = tlist.token_index(group) + 1
else:
@@ -451,6 +447,5 @@ def group(tlist):
group_if,
group_for,
group_foreach,
- group_begin,
- ]:
+ group_begin]:
func(tlist)
diff --git a/sqlparse/filters.py b/sqlparse/filters.py
index 676344f..b187907 100644
--- a/sqlparse/filters.py
+++ b/sqlparse/filters.py
@@ -4,9 +4,8 @@ import re
from os.path import abspath, join
-from sqlparse import sql, tokens as T
+from sqlparse import compat, sql, tokens as T
from sqlparse.engine import FilterStack
-from sqlparse.lexer import tokenize
from sqlparse.pipeline import Pipeline
from sqlparse.tokens import (Comment, Comparison, Keyword, Name, Punctuation,
String, Whitespace)
@@ -25,7 +24,7 @@ class _CaseFilter:
if case is None:
case = 'upper'
assert case in ['lower', 'upper', 'capitalize']
- self.convert = getattr(unicode, case)
+ self.convert = getattr(compat.text_type, case)
def process(self, stack, stream):
for ttype, value in stream:
@@ -52,20 +51,20 @@ class TruncateStringFilter:
def __init__(self, width, char):
self.width = max(width, 1)
- self.char = unicode(char)
+ self.char = compat.text_type(char)
def process(self, stack, stream):
for ttype, value in stream:
if ttype is T.Literal.String.Single:
if value[:2] == '\'\'':
inner = value[2:-2]
- quote = u'\'\''
+ quote = compat.text_type('\'\'')
else:
inner = value[1:-1]
- quote = u'\''
+ quote = compat.text_type('\'')
if len(inner) > self.width:
- value = u''.join((quote, inner[:self.width], self.char,
- quote))
+ value = compat.text_type('').join(
+ (quote, inner[:self.width], self.char, quote))
yield ttype, value
@@ -143,7 +142,6 @@ class IncludeStatement:
# Found file path to include
if token_type in String.Symbol:
-# if token_type in tokens.String.Symbol:
# Get path of file to include
path = join(self.dirpath, value[1:-1])
@@ -154,13 +152,14 @@ class IncludeStatement:
f.close()
# There was a problem loading the include file
- except IOError, err:
+ except IOError as err:
# Raise the exception to the interpreter
if self.raiseexceptions:
raise
# Put the exception as a comment on the SQL code
- yield Comment, u'-- IOError: %s\n' % err
+ yield Comment, compat.text_type(
+ '-- IOError: %s\n' % err)
else:
# Create new FilterStack to parse readed file
@@ -171,13 +170,14 @@ class IncludeStatement:
self.raiseexceptions)
# Max recursion limit reached
- except ValueError, err:
+ except ValueError as err:
# Raise the exception to the interpreter
if self.raiseexceptions:
raise
# Put the exception as a comment on the SQL code
- yield Comment, u'-- ValueError: %s\n' % err
+ yield Comment, compat.text_type(
+ '-- ValueError: %s\n' % err)
stack = FilterStack()
stack.preprocess.append(filtr)
@@ -300,7 +300,7 @@ class ReindentFilter:
raise StopIteration
def _get_offset(self, token):
- raw = ''.join(map(unicode, self._flatten_up_to_token(token)))
+ raw = ''.join(map(compat.text_type, self._flatten_up_to_token(token)))
line = raw.splitlines()[-1]
# Now take current offset into account and return relative offset.
full_offset = len(line) - len(self.char * (self.width * self.indent))
@@ -340,7 +340,7 @@ class ReindentFilter:
if prev and prev.is_whitespace() and prev not in added:
tlist.tokens.pop(tlist.token_index(prev))
offset += 1
- uprev = unicode(prev)
+ uprev = compat.text_type(prev)
if (prev and (uprev.endswith('\n') or uprev.endswith('\r'))):
nl = tlist.token_next(token)
else:
@@ -462,7 +462,7 @@ class ReindentFilter:
self._process(stmt)
if isinstance(stmt, sql.Statement):
if self._last_stmt is not None:
- if unicode(self._last_stmt).endswith('\n'):
+ if compat.text_type(self._last_stmt).endswith('\n'):
nl = '\n'
else:
nl = '\n\n'
@@ -491,10 +491,10 @@ class RightMarginFilter:
else:
self.line = token.value.splitlines()[-1]
elif (token.is_group()
- and not token.__class__ in self.keep_together):
+ and token.__class__ not in self.keep_together):
token.tokens = self._process(stack, token, token.tokens)
else:
- val = unicode(token)
+ val = compat.text_type(token)
if len(self.line) + len(val) > self.width:
match = re.search('^ +', self.line)
if match is not None:
@@ -568,7 +568,7 @@ class ColumnsSelect:
class SerializerUnicode:
def process(self, stack, stmt):
- raw = unicode(stmt)
+ raw = compat.text_type(stmt)
lines = split_unquoted_newlines(raw)
res = '\n'.join(line.rstrip() for line in lines)
return res
@@ -578,7 +578,7 @@ def Tokens2Unicode(stream):
result = ""
for _, value in stream:
- result += unicode(value)
+ result += compat.text_type(value)
return result
@@ -600,7 +600,7 @@ class OutputFilter:
else:
varname = self.varname
- has_nl = len(unicode(stmt).strip().splitlines()) > 1
+ has_nl = len(compat.text_type(stmt).strip().splitlines()) > 1
stmt.tokens = self._process(stmt.tokens, varname, has_nl)
return stmt
diff --git a/sqlparse/lexer.py b/sqlparse/lexer.py
index fd29f5c..7ce6d36 100644
--- a/sqlparse/lexer.py
+++ b/sqlparse/lexer.py
@@ -15,31 +15,23 @@
import re
import sys
+from sqlparse import compat
from sqlparse import tokens
+from sqlparse.compat import StringIO
from sqlparse.keywords import KEYWORDS, KEYWORDS_COMMON
-from cStringIO import StringIO
class include(str):
pass
-class combined(tuple):
- """Indicates a state combined from multiple states."""
-
- def __new__(cls, *args):
- return tuple.__new__(cls, args)
-
- def __init__(self, *args):
- # tuple.__init__ doesn't do anything
- pass
-
-
def is_keyword(value):
test = value.upper()
return KEYWORDS_COMMON.get(test, KEYWORDS.get(test, tokens.Name)), value
+# TODO(andi): Can this be removed? If so, add_filter and Lexer.filters
+# should be removed too.
def apply_filters(stream, filters, lexer=None):
"""
Use this method to apply an iterable of filters to
@@ -81,14 +73,14 @@ class LexerMeta(type):
try:
rex = re.compile(tdef[0], rflags).match
- except Exception, err:
+ except Exception as err:
raise ValueError(("uncompilable regex %r in state"
" %r of %r: %s"
% (tdef[0], state, cls, err)))
assert type(tdef[1]) is tokens._TokenType or callable(tdef[1]), \
- ('token type must be simple type or callable, not %r'
- % (tdef[1],))
+ ('token type must be simple type or callable, not %r'
+ % (tdef[1],))
if len(tdef) == 2:
new_state = None
@@ -106,24 +98,12 @@ class LexerMeta(type):
new_state = -int(tdef2[5:])
else:
assert False, 'unknown new state %r' % tdef2
- elif isinstance(tdef2, combined):
- # combine a new state from existing ones
- new_state = '_tmp_%d' % cls._tmpname
- cls._tmpname += 1
- itokens = []
- for istate in tdef2:
- assert istate != state, \
- 'circular state ref %r' % istate
- itokens.extend(cls._process_state(unprocessed,
- processed, istate))
- processed[new_state] = itokens
- new_state = (new_state,)
elif isinstance(tdef2, tuple):
# push more than one state
for state in tdef2:
assert (state in unprocessed or
state in ('#pop', '#push')), \
- 'unknown new state ' + state
+ 'unknown new state ' + state
new_state = tdef2
else:
assert False, 'unknown new state def %r' % tdef2
@@ -134,7 +114,6 @@ class LexerMeta(type):
cls._all_tokens = {}
cls._tmpname = 0
processed = cls._all_tokens[cls.__name__] = {}
- #tokendefs = tokendefs or cls.tokens[name]
for state in cls.tokens.keys():
cls._process_state(cls.tokens, processed, state)
return processed
@@ -152,9 +131,7 @@ class LexerMeta(type):
return type.__call__(cls, *args, **kwds)
-class Lexer(object):
-
- __metaclass__ = LexerMeta
+class Lexer(compat.with_metaclass(LexerMeta)):
encoding = 'utf-8'
stripall = False
@@ -235,8 +212,8 @@ class Lexer(object):
if self.encoding == 'guess':
try:
text = text.decode('utf-8')
- if text.startswith(u'\ufeff'):
- text = text[len(u'\ufeff'):]
+ if text.startswith(compat.text_type('\ufeff')):
+ text = text[len(compat.text_type('\ufeff')):]
except UnicodeDecodeError:
text = text.decode('latin1')
else:
@@ -258,13 +235,13 @@ class Lexer(object):
Also preprocess the text, i.e. expand tabs and strip it if
wanted and applies registered filters.
"""
- if isinstance(text, basestring):
+ if isinstance(text, compat.string_types):
if self.stripall:
text = text.strip()
elif self.stripnl:
text = text.strip('\n')
- if sys.version_info[0] < 3 and isinstance(text, unicode):
+ if compat.PY2 and isinstance(text, compat.text_type):
text = StringIO(text.encode('utf-8'))
self.encoding = 'utf-8'
else:
@@ -342,7 +319,7 @@ class Lexer(object):
pos += 1
statestack = ['root']
statetokens = tokendefs['root']
- yield pos, tokens.Text, u'\n'
+ yield pos, tokens.Text, compat.text_type('\n')
continue
yield pos, tokens.Error, text[pos]
pos += 1
diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 5ecfbdc..8601537 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -5,6 +5,7 @@
import re
import sys
+from sqlparse import compat
from sqlparse import tokens as T
@@ -32,7 +33,7 @@ class Token(object):
if sys.version_info[0] == 3:
return self.value
else:
- return unicode(self).encode('utf-8')
+ return compat.text_type(self).encode('utf-8')
def __repr__(self):
short = self._get_repr_value()
@@ -51,15 +52,15 @@ class Token(object):
.. deprecated:: 0.1.5
Use ``unicode(token)`` (for Python 3: ``str(token)``) instead.
"""
- return unicode(self)
+ return compat.text_type(self)
def _get_repr_name(self):
return str(self.ttype).split('.')[-1]
def _get_repr_value(self):
- raw = unicode(self)
+ raw = compat.text_type(self)
if len(raw) > 7:
- raw = raw[:6] + u'...'
+ raw = raw[:6] + compat.text_type('...')
return re.sub('\s+', ' ', raw)
def flatten(self):
@@ -83,7 +84,7 @@ class Token(object):
return type_matched
if regex:
- if isinstance(values, basestring):
+ if isinstance(values, compat.string_types):
values = set([values])
if self.ttype is T.Keyword:
@@ -96,7 +97,7 @@ class Token(object):
return True
return False
- if isinstance(values, basestring):
+ if isinstance(values, compat.string_types):
if self.is_keyword:
return values.upper() == self.normalized
return values == self.value
@@ -172,7 +173,7 @@ class TokenList(Token):
if sys.version_info[0] == 3:
return ''.join(x.value for x in self.flatten())
else:
- return ''.join(unicode(x) for x in self.flatten())
+ return ''.join(compat.text_type(x) for x in self.flatten())
def _get_repr_name(self):
return self.__class__.__name__
@@ -185,9 +186,9 @@ class TokenList(Token):
pre = ' +-'
else:
pre = ' | '
- print '%s%s%d %s \'%s\'' % (indent, pre, idx,
+ print('%s%s%d %s \'%s\'' % (indent, pre, idx,
token._get_repr_name(),
- token._get_repr_value())
+ token._get_repr_value()))
if (token.is_group() and (max_depth is None or depth < max_depth)):
token._pprint_tree(max_depth, depth + 1)
@@ -220,18 +221,10 @@ class TokenList(Token):
else:
yield token
-# def __iter__(self):
-# return self
-#
-# def next(self):
-# for token in self.tokens:
-# yield token
-
def is_group(self):
return True
def get_sublists(self):
-# return [x for x in self.tokens if isinstance(x, TokenList)]
for x in self.tokens:
if isinstance(x, TokenList):
yield x
@@ -285,7 +278,7 @@ class TokenList(Token):
if not isinstance(idx, int):
idx = self.token_index(idx)
- for n in xrange(idx, len(self.tokens)):
+ for n in range(idx, len(self.tokens)):
token = self.tokens[n]
if token.match(ttype, value, regex):
return token
@@ -510,7 +503,7 @@ class Identifier(TokenList):
next_ = self.token_next(self.token_index(marker), False)
if next_ is None:
return None
- return unicode(next_)
+ return compat.text_type(next_)
def get_ordering(self):
"""Returns the ordering or ``None`` as uppercase string."""
diff --git a/sqlparse/tokens.py b/sqlparse/tokens.py
index 01a9b89..53c31ce 100644
--- a/sqlparse/tokens.py
+++ b/sqlparse/tokens.py
@@ -13,15 +13,6 @@
class _TokenType(tuple):
parent = None
- def split(self):
- buf = []
- node = self
- while node is not None:
- buf.append(node)
- node = node.parent
- buf.reverse()
- return buf
-
def __contains__(self, val):
return val is not None and (self is val or val[:len(self)] == self)
diff --git a/sqlparse/utils.py b/sqlparse/utils.py
index 3a49ac2..7595e9d 100644
--- a/sqlparse/utils.py
+++ b/sqlparse/utils.py
@@ -5,65 +5,42 @@ Created on 17/05/2012
'''
import re
+from collections import OrderedDict
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = None
+class Cache(OrderedDict):
+ """Cache with LRU algorithm using an OrderedDict as basis."""
+ def __init__(self, maxsize=100):
+ OrderedDict.__init__(self)
-if OrderedDict:
- class Cache(OrderedDict):
- """Cache with LRU algorithm using an OrderedDict as basis
- """
- def __init__(self, maxsize=100):
- OrderedDict.__init__(self)
+ self._maxsize = maxsize
- self._maxsize = maxsize
+ def __getitem__(self, key, *args, **kwargs):
+ # Get the key and remove it from the cache, or raise KeyError
+ value = OrderedDict.__getitem__(self, key)
+ del self[key]
- def __getitem__(self, key, *args, **kwargs):
- # Get the key and remove it from the cache, or raise KeyError
- value = OrderedDict.__getitem__(self, key)
- del self[key]
-
- # Insert the (key, value) pair on the front of the cache
- OrderedDict.__setitem__(self, key, value)
-
- # Return the value from the cache
- return value
-
- def __setitem__(self, key, value, *args, **kwargs):
- # Key was inserted before, remove it so we put it at front later
- if key in self:
- del self[key]
+ # Insert the (key, value) pair on the front of the cache
+ OrderedDict.__setitem__(self, key, value)
- # Too much items on the cache, remove the least recent used
- elif len(self) >= self._maxsize:
- self.popitem(False)
+ # Return the value from the cache
+ return value
- # Insert the (key, value) pair on the front of the cache
- OrderedDict.__setitem__(self, key, value, *args, **kwargs)
-
-else:
- class Cache(dict):
- """Cache that reset when gets full
- """
- def __init__(self, maxsize=100):
- dict.__init__(self)
-
- self._maxsize = maxsize
+ def __setitem__(self, key, value, *args, **kwargs):
+ # Key was inserted before, remove it so we put it at front later
+ if key in self:
+ del self[key]
- def __setitem__(self, key, value, *args, **kwargs):
- # Reset the cache if we have too much cached entries and start over
- if len(self) >= self._maxsize:
- self.clear()
+ # Too much items on the cache, remove the least recent used
+ elif len(self) >= self._maxsize:
+ self.popitem(False)
- # Insert the (key, value) pair on the front of the cache
- dict.__setitem__(self, key, value, *args, **kwargs)
+ # Insert the (key, value) pair on the front of the cache
+ OrderedDict.__setitem__(self, key, value, *args, **kwargs)
def memoize_generator(func):
- """Memoize decorator for generators
+ """Memoize decorator for generators.
Store `func` results in a cache according to their arguments as 'memoize'
does but instead this works on decorators instead of regular functions.
@@ -73,7 +50,6 @@ def memoize_generator(func):
cache = Cache()
def wrapped_func(*args, **kwargs):
-# params = (args, kwargs)
params = (args, tuple(sorted(kwargs.items())))
# Look if cached
@@ -120,6 +96,7 @@ SPLIT_REGEX = re.compile(r"""
LINE_MATCH = re.compile(r'(\r\n|\r|\n)')
+
def split_unquoted_newlines(text):
"""Split a string on all unquoted newlines.
@@ -134,4 +111,4 @@ def split_unquoted_newlines(text):
outputlines.append('')
else:
outputlines[-1] += line
- return outputlines \ No newline at end of file
+ return outputlines
diff --git a/tests/test_filters.py b/tests/test_filters.py
index d827454..925b0b6 100644
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -74,5 +74,4 @@ LIMIT 1"""
if __name__ == "__main__":
- #import sys;sys.argv = ['', 'Test.testName']
unittest.main()
diff --git a/tests/test_format.py b/tests/test_format.py
index a105b1c..4746358 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -92,10 +92,14 @@ class TestFormat(TestCaseBase):
f = lambda x: sqlparse.format(x)
# Because of the use of
- self.ndiffAssertEqual(f(s1), "SELECT some_column LIKE 'value\r'")
- self.ndiffAssertEqual(f(s2), "SELECT some_column LIKE 'value\r'\nWHERE id = 1\n")
- self.ndiffAssertEqual(f(s3), "SELECT some_column LIKE 'value\\'\r' WHERE id = 1\n")
- self.ndiffAssertEqual(f(s4), "SELECT some_column LIKE 'value\\\\\\'\r' WHERE id = 1\n")
+ self.ndiffAssertEqual(
+ f(s1), "SELECT some_column LIKE 'value\r'")
+ self.ndiffAssertEqual(
+ f(s2), "SELECT some_column LIKE 'value\r'\nWHERE id = 1\n")
+ self.ndiffAssertEqual(
+ f(s3), "SELECT some_column LIKE 'value\\'\r' WHERE id = 1\n")
+ self.ndiffAssertEqual(
+ f(s4), "SELECT some_column LIKE 'value\\\\\\'\r' WHERE id = 1\n")
def test_outputformat(self):
sql = 'select * from foo;'
diff --git a/tests/test_functions.py b/tests/test_functions.py
index 52e2ce7..425ab7f 100644
--- a/tests/test_functions.py
+++ b/tests/test_functions.py
@@ -160,5 +160,4 @@ class Test_IsType(Test_SQL):
if __name__ == "__main__":
- #import sys;sys.argv = ['', 'Test.testName']
main()
diff --git a/tests/test_grouping.py b/tests/test_grouping.py
index 5ade830..5b87a38 100644
--- a/tests/test_grouping.py
+++ b/tests/test_grouping.py
@@ -3,6 +3,7 @@
import pytest
import sqlparse
+from sqlparse import compat
from sqlparse import sql
from sqlparse import tokens as T
@@ -26,7 +27,7 @@ class TestGrouping(TestCaseBase):
def test_comments(self):
s = '/*\n * foo\n */ \n bar'
parsed = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(parsed))
+ self.ndiffAssertEqual(s, compat.text_type(parsed))
self.assertEqual(len(parsed.tokens), 2)
def test_assignment(self):
@@ -42,18 +43,18 @@ class TestGrouping(TestCaseBase):
def test_identifiers(self):
s = 'select foo.bar from "myscheme"."table" where fail. order'
parsed = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(parsed))
+ self.ndiffAssertEqual(s, compat.text_type(parsed))
self.assert_(isinstance(parsed.tokens[2], sql.Identifier))
self.assert_(isinstance(parsed.tokens[6], sql.Identifier))
self.assert_(isinstance(parsed.tokens[8], sql.Where))
s = 'select * from foo where foo.id = 1'
parsed = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(parsed))
+ self.ndiffAssertEqual(s, compat.text_type(parsed))
self.assert_(isinstance(parsed.tokens[-1].tokens[-1].tokens[0],
sql.Identifier))
s = 'select * from (select "foo"."id" from foo)'
parsed = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(parsed))
+ self.ndiffAssertEqual(s, compat.text_type(parsed))
self.assert_(isinstance(parsed.tokens[-1].tokens[3], sql.Identifier))
s = "INSERT INTO `test` VALUES('foo', 'bar');"
@@ -69,7 +70,7 @@ class TestGrouping(TestCaseBase):
self.assertEqual(len(parsed.tokens[2].tokens), 4)
identifiers = list(parsed.tokens[2].get_identifiers())
self.assertEqual(len(identifiers), 2)
- self.assertEquals(identifiers[0].get_alias(), u"col")
+ self.assertEquals(identifiers[0].get_alias(), 'col')
def test_identifier_wildcard(self):
p = sqlparse.parse('a.*, b.id')[0]
@@ -141,44 +142,44 @@ class TestGrouping(TestCaseBase):
def test_where(self):
s = 'select * from foo where bar = 1 order by id desc'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertTrue(len(p.tokens), 16)
s = 'select x from (select y from foo where bar = 1) z'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertTrue(isinstance(p.tokens[-1].tokens[0].tokens[-2], sql.Where))
def test_typecast(self):
s = 'select foo::integer from bar'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[2].get_typecast(), 'integer')
self.assertEqual(p.tokens[2].get_name(), 'foo')
s = 'select (current_database())::information_schema.sql_identifier'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[2].get_typecast(),
'information_schema.sql_identifier')
def test_alias(self):
s = 'select foo as bar from mytable'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[2].get_real_name(), 'foo')
self.assertEqual(p.tokens[2].get_alias(), 'bar')
s = 'select foo from mytable t1'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[6].get_real_name(), 'mytable')
self.assertEqual(p.tokens[6].get_alias(), 't1')
s = 'select foo::integer as bar from mytable'
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[2].get_alias(), 'bar')
s = ('SELECT DISTINCT '
'(current_database())::information_schema.sql_identifier AS view')
p = sqlparse.parse(s)[0]
- self.ndiffAssertEqual(s, unicode(p))
+ self.ndiffAssertEqual(s, compat.text_type(p))
self.assertEqual(p.tokens[4].get_alias(), 'view')
def test_alias_case(self): # see issue46
diff --git a/tests/test_parse.py b/tests/test_parse.py
index 6c9d6a6..bbe60df 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -8,6 +8,7 @@ from tests.utils import TestCaseBase
import sqlparse
import sqlparse.sql
+from sqlparse import compat
from sqlparse import tokens as T
@@ -30,18 +31,18 @@ class SQLParseTest(TestCaseBase):
self.assertEqual(str(stmts[1]), sql2)
def test_newlines(self):
- sql = u'select\n*from foo;'
+ sql = 'select\n*from foo;'
p = sqlparse.parse(sql)[0]
- self.assertEqual(unicode(p), sql)
- sql = u'select\r\n*from foo'
+ self.assertEqual(compat.text_type(p), sql)
+ sql = 'select\r\n*from foo'
p = sqlparse.parse(sql)[0]
- self.assertEqual(unicode(p), sql)
- sql = u'select\r*from foo'
+ self.assertEqual(compat.text_type(p), sql)
+ sql = 'select\r*from foo'
p = sqlparse.parse(sql)[0]
- self.assertEqual(unicode(p), sql)
- sql = u'select\r\n*from foo\n'
+ self.assertEqual(compat.text_type(p), sql)
+ sql = 'select\r\n*from foo\n'
p = sqlparse.parse(sql)[0]
- self.assertEqual(unicode(p), sql)
+ self.assertEqual(compat.text_type(p), sql)
def test_within(self):
sql = 'foo(col1, col2)'
diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py
index 3442a5b..0d0f360 100644
--- a/tests/test_pipeline.py
+++ b/tests/test_pipeline.py
@@ -30,7 +30,7 @@ class Test(unittest.TestCase):
FROM links
WHERE parent_dir == :parent_dir AND name == :name
LIMIT 1"""
- self.assertEqual([u'child_entry', u'inode', u'creation'],
+ self.assertEqual(['child_entry', 'inode', 'creation'],
self.pipe(sql))
def test_3(self):
@@ -64,7 +64,7 @@ WHERE dir_entries.inode == :inode
GROUP BY dir_entries.inode
LIMIT 1"""
- self.assertEqual([u'st_dev', u'st_uid', u'st_gid', u'st_mode',
- u'st_ino', u'st_nlink', u'st_ctime',
- u'st_atime', u'st_mtime', u'st_size', u'size'],
+ self.assertEqual(['st_dev', 'st_uid', 'st_gid', 'st_mode',
+ 'st_ino', 'st_nlink', 'st_ctime',
+ 'st_atime', 'st_mtime', 'st_size', 'size'],
self.pipe(sql))
diff --git a/tests/test_regressions.py b/tests/test_regressions.py
index ea8cd56..6bd198b 100644
--- a/tests/test_regressions.py
+++ b/tests/test_regressions.py
@@ -5,6 +5,7 @@ import sys
from tests.utils import TestCaseBase, load_file
import sqlparse
+from sqlparse import compat
from sqlparse import sql
from sqlparse import tokens as T
@@ -84,7 +85,7 @@ class RegressionTests(TestCaseBase):
self.assertEqual(len(p.tokens), 7)
self.assertEqual(p.tokens[2].__class__, sql.IdentifierList)
self.assertEqual(p.tokens[-1].__class__, sql.Identifier)
- self.assertEqual(p.tokens[-1].get_name(), u'foo')
+ self.assertEqual(p.tokens[-1].get_name(), 'foo')
sp = p.tokens[-1].tokens[0]
self.assertEqual(sp.tokens[3].__class__, sql.IdentifierList)
# make sure that formatting works as expected
@@ -164,7 +165,8 @@ ALTER TABLE..... ;"""
def test_comment_encoding_when_reindent():
# There was an UnicodeEncodeError in the reindent filter that
# casted every comment followed by a keyword to str.
- sql = u'select foo -- Comment containing Ümläuts\nfrom bar'
+ sql = compat.text_type(compat.u(
+ 'select foo -- Comment containing Ümläuts\nfrom bar'))
formatted = sqlparse.format(sql, reindent=True)
assert formatted == sql
@@ -194,7 +196,9 @@ def test_format_accepts_encoding(): # issue20
sql = load_file('test_cp1251.sql', 'cp1251')
formatted = sqlparse.format(sql, reindent=True, encoding='cp1251')
if sys.version_info < (3,):
- tformatted = u'insert into foo\nvalues (1); -- Песня про надежду\n'
+ tformatted = compat.text_type(
+ 'insert into foo\nvalues (1); -- Песня про надежду\n',
+ encoding='utf-8')
else:
tformatted = 'insert into foo\nvalues (1); -- Песня про надежду\n'
assert formatted == tformatted
diff --git a/tests/test_split.py b/tests/test_split.py
index 54e8d04..8b22aad 100644
--- a/tests/test_split.py
+++ b/tests/test_split.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
# Tests splitting functions.
-
-import unittest
+import types
from tests.utils import load_file, TestCaseBase
import sqlparse
+from sqlparse import compat
class SQLSplitTest(TestCaseBase):
@@ -19,8 +19,8 @@ class SQLSplitTest(TestCaseBase):
sql2 = 'select * from foo where bar = \'foo;bar\';'
stmts = sqlparse.parse(''.join([self._sql1, sql2]))
self.assertEqual(len(stmts), 2)
- self.ndiffAssertEqual(unicode(stmts[0]), self._sql1)
- self.ndiffAssertEqual(unicode(stmts[1]), sql2)
+ self.ndiffAssertEqual(compat.text_type(stmts[0]), self._sql1)
+ self.ndiffAssertEqual(compat.text_type(stmts[1]), sql2)
def test_split_backslash(self):
stmts = sqlparse.parse(r"select '\\'; select '\''; select '\\\'';")
@@ -30,31 +30,31 @@ class SQLSplitTest(TestCaseBase):
sql = load_file('function.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 1)
- self.ndiffAssertEqual(unicode(stmts[0]), sql)
+ self.ndiffAssertEqual(compat.text_type(stmts[0]), sql)
def test_create_function_psql(self):
sql = load_file('function_psql.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 1)
- self.ndiffAssertEqual(unicode(stmts[0]), sql)
+ self.ndiffAssertEqual(compat.text_type(stmts[0]), sql)
def test_create_function_psql3(self):
sql = load_file('function_psql3.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 1)
- self.ndiffAssertEqual(unicode(stmts[0]), sql)
+ self.ndiffAssertEqual(compat.text_type(stmts[0]), sql)
def test_create_function_psql2(self):
sql = load_file('function_psql2.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 1)
- self.ndiffAssertEqual(unicode(stmts[0]), sql)
+ self.ndiffAssertEqual(compat.text_type(stmts[0]), sql)
def test_dashcomments(self):
sql = load_file('dashcomment.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 3)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
def test_dashcomments_eol(self):
stmts = sqlparse.parse('select foo; -- comment\n')
@@ -70,36 +70,38 @@ class SQLSplitTest(TestCaseBase):
sql = load_file('begintag.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 3)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
def test_begintag_2(self):
sql = load_file('begintag_2.sql')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 1)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
def test_dropif(self):
sql = 'DROP TABLE IF EXISTS FOO;\n\nSELECT * FROM BAR;'
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 2)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
def test_comment_with_umlaut(self):
- sql = (u'select * from foo;\n'
- u'-- Testing an umlaut: ä\n'
- u'select * from bar;')
+ sql = (compat.u(
+ 'select * from foo;\n'
+ '-- Testing an umlaut: ä\n'
+ 'select * from bar;'))
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 2)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
def test_comment_end_of_line(self):
sql = ('select * from foo; -- foo\n'
'select * from bar;')
stmts = sqlparse.parse(sql)
self.assertEqual(len(stmts), 2)
- self.ndiffAssertEqual(''.join(unicode(q) for q in stmts), sql)
+ self.ndiffAssertEqual(''.join(compat.text_type(q) for q in stmts), sql)
# make sure the comment belongs to first query
- self.ndiffAssertEqual(unicode(stmts[0]), 'select * from foo; -- foo\n')
+ self.ndiffAssertEqual(
+ compat.text_type(stmts[0]), 'select * from foo; -- foo\n')
def test_casewhen(self):
sql = ('SELECT case when val = 1 then 2 else null end as foo;\n'
@@ -122,19 +124,15 @@ class SQLSplitTest(TestCaseBase):
self.assertEqual(len(stmts), 2)
def test_split_stream(self):
- import types
- from cStringIO import StringIO
-
- stream = StringIO("SELECT 1; SELECT 2;")
+ stream = compat.StringIO("SELECT 1; SELECT 2;")
stmts = sqlparse.parsestream(stream)
self.assertEqual(type(stmts), types.GeneratorType)
self.assertEqual(len(list(stmts)), 2)
def test_encoding_parsestream(self):
- from cStringIO import StringIO
- stream = StringIO("SELECT 1; SELECT 2;")
+ stream = compat.StringIO("SELECT 1; SELECT 2;")
stmts = list(sqlparse.parsestream(stream))
- self.assertEqual(type(stmts[0].tokens[0].value), unicode)
+ self.assertEqual(type(stmts[0].tokens[0].value), compat.text_type)
def test_split_simple():
diff --git a/tests/test_tokenize.py b/tests/test_tokenize.py
index 0b23fa8..a38e50f 100644
--- a/tests/test_tokenize.py
+++ b/tests/test_tokenize.py
@@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
-import sys
import types
import unittest
import pytest
import sqlparse
+from sqlparse import compat
from sqlparse import lexer
from sqlparse import sql
-from sqlparse.tokens import *
+from sqlparse.tokens import * # noqa
class TestTokenize(unittest.TestCase):
@@ -21,14 +21,14 @@ class TestTokenize(unittest.TestCase):
tokens = list(stream)
self.assertEqual(len(tokens), 8)
self.assertEqual(len(tokens[0]), 2)
- self.assertEqual(tokens[0], (Keyword.DML, u'select'))
- self.assertEqual(tokens[-1], (Punctuation, u';'))
+ self.assertEqual(tokens[0], (Keyword.DML, 'select'))
+ self.assertEqual(tokens[-1], (Punctuation, ';'))
def test_backticks(self):
s = '`foo`.`bar`'
tokens = list(lexer.tokenize(s))
self.assertEqual(len(tokens), 3)
- self.assertEqual(tokens[0], (Name, u'`foo`'))
+ self.assertEqual(tokens[0], (Name, '`foo`'))
def test_linebreaks(self): # issue1
s = 'foo\nbar\n'
@@ -50,7 +50,7 @@ class TestTokenize(unittest.TestCase):
self.assertEqual(len(tokens), 3)
self.assertEqual(tokens[0][0], Keyword.DDL)
self.assertEqual(tokens[2][0], Name)
- self.assertEqual(tokens[2][1], u'created_foo')
+ self.assertEqual(tokens[2][1], 'created_foo')
s = "enddate"
tokens = list(lexer.tokenize(s))
self.assertEqual(len(tokens), 1)
@@ -72,7 +72,7 @@ class TestTokenize(unittest.TestCase):
self.assertEqual(tokens[2][0], Number.Integer)
self.assertEqual(tokens[2][1], '-1')
- # Somehow this test fails on Python 3.2
+ # Somehow this test fails on Python 3
@pytest.mark.skipif('sys.version_info >= (3,0)')
def test_tab_expansion(self):
s = "\t"
@@ -132,10 +132,9 @@ class TestTokenList(unittest.TestCase):
class TestStream(unittest.TestCase):
- def test_simple(self):
- from cStringIO import StringIO
- stream = StringIO("SELECT 1; SELECT 2;")
+ def test_simple(self):
+ stream = compat.StringIO("SELECT 1; SELECT 2;")
lex = lexer.Lexer()
tokens = lex.get_tokens(stream)
@@ -152,9 +151,7 @@ class TestStream(unittest.TestCase):
self.assertEqual(len(tokens), 9)
def test_error(self):
- from cStringIO import StringIO
-
- stream = StringIO("FOOBAR{")
+ stream = compat.StringIO("FOOBAR{")
lex = lexer.Lexer()
lex.bufsize = 4
diff --git a/tests/utils.py b/tests/utils.py
index 9eb46bf..92d7a4b 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -6,8 +6,8 @@ import codecs
import difflib
import os
import unittest
-from StringIO import StringIO
+from sqlparse import compat
import sqlparse.utils
NL = '\n'
@@ -31,16 +31,16 @@ class TestCaseBase(unittest.TestCase):
def ndiffAssertEqual(self, first, second):
"""Like failUnlessEqual except use ndiff for readable output."""
if first != second:
- sfirst = unicode(first)
- ssecond = unicode(second)
+ sfirst = compat.text_type(first)
+ ssecond = compat.text_type(second)
# Using the built-in .splitlines() method here will cause incorrect
# results when splitting statements that have quoted CR/CR+LF
# characters.
sfirst = sqlparse.utils.split_unquoted_newlines(sfirst)
ssecond = sqlparse.utils.split_unquoted_newlines(ssecond)
diff = difflib.ndiff(sfirst, ssecond)
- fp = StringIO()
+ fp = compat.StringIO()
fp.write(NL)
fp.write(NL.join(diff))
- print fp.getvalue()
- raise self.failureException, fp.getvalue()
+ print(fp.getvalue())
+ raise self.failureException(fp.getvalue())
diff --git a/tox.ini b/tox.ini
index e797ca9..e9f5575 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,8 @@
[tox]
-envlist=py26,py27,py32,py33,py34,pypy
+envlist=codechecks,py27,py32,py33,py34,pypy
+
+[flake8]
+ignore = E129
[testenv]
deps=
@@ -9,29 +12,8 @@ commands=
sqlformat --version # Sanity check.
py.test --cov=sqlparse/ tests
-[testenv:py32]
-changedir={envdir}
-commands=
- sqlformat --version # Sanity check.
- rm -rf tests/
- cp -r {toxinidir}/tests/ tests/
- 2to3 -w --no-diffs -n tests/
- py.test --cov={envdir}/lib/python3.2/site-packages/sqlparse/ tests
-
-[testenv:py33]
-changedir={envdir}
-commands=
- sqlformat --version # Sanity check.
- rm -rf tests/
- cp -r {toxinidir}/tests/ tests/
- 2to3 -w --no-diffs -n tests/
- py.test --cov={envdir}/lib/python3.3/site-packages/sqlparse/ tests
-
-[testenv:py34]
-changedir={envdir}
+[testenv:codechecks]
+deps=
+ flake8
commands=
- sqlformat --version # Sanity check.
- rm -rf tests/
- cp -r {toxinidir}/tests/ tests/
- 2to3 -w --no-diffs -n tests/
- py.test --cov={envdir}/lib/python3.4/site-packages/sqlparse/ tests
+ flake8 sqlparse tests