From c918cc9dc30b3a7684a96feae95fc5c05638360e Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 20:58:14 +0200 Subject: Add parsing of MS Access column names with braces (fixes issue27). --- CHANGES | 2 ++ sqlparse/lexer.py | 1 + tests/test_parse.py | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/CHANGES b/CHANGES index 203d98c..f0af911 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,8 @@ Bug Fixes * Improve parsing of stand-alone comments (issue26). * Detection of placeholders in paramterized queries (issue22, reported by Glyph Lefkowitz). + * Add parsing of MS Access column names with braces (issue27, + reported by frankz...@gmail.com). Release 0.1.2 (Nov 23, 2010) diff --git a/sqlparse/lexer.py b/sqlparse/lexer.py index 950ef1b..ecfdbce 100644 --- a/sqlparse/lexer.py +++ b/sqlparse/lexer.py @@ -189,6 +189,7 @@ class Lexer: (r"(''|'.*?[^\\]')", tokens.String.Single), # not a real string literal in ANSI SQL: (r'(""|".*?[^\\]")', tokens.String.Symbol), + (r'(\[.*[^\]]\])', tokens.Name), (r'(LEFT |RIGHT )?(INNER |OUTER )?JOIN\b', tokens.Keyword), (r'END( IF| LOOP)?\b', tokens.Keyword), (r'NOT NULL\b', tokens.Keyword), diff --git a/tests/test_parse.py b/tests/test_parse.py index 6ff8dd8..5f9bb2d 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -95,3 +95,10 @@ class SQLParseTest(TestCaseBase): self.assert_(t[-1].ttype is sqlparse.tokens.Name.Placeholder) self.assertEqual(t[-1].value, '$a') + def test_access_symbol(self): # see issue27 + t = sqlparse.parse('select a.[foo bar] as foo')[0].tokens + self.assert_(isinstance(t[-1], sqlparse.sql.Identifier)) + self.assertEqual(t[-1].get_name(), 'foo') + self.assertEqual(t[-1].get_real_name(), '[foo bar]') + self.assertEqual(t[-1].get_parent_name(), 'a') + -- cgit v1.2.1 From 92c142623d9b4ad806f51dd79e3842396ac464d8 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 21:03:28 +0200 Subject: Replace Django by Flask in App Engine frontend (fixes issue11). --HG-- rename : extras/appengine/Makefile => extras/appengine-django/Makefile rename : extras/appengine/README => extras/appengine-django/README rename : extras/appengine/__init__.py => extras/appengine-django/__init__.py rename : extras/appengine/app.yaml => extras/appengine-django/app.yaml rename : extras/appengine/examples/customers.sql => extras/appengine-django/examples/customers.sql rename : extras/appengine/examples/multiple_inserts.sql => extras/appengine-django/examples/multiple_inserts.sql rename : extras/appengine/examples/pg_view.sql => extras/appengine-django/examples/pg_view.sql rename : extras/appengine/examples/subquery.sql => extras/appengine-django/examples/subquery.sql rename : extras/appengine/examples/subquery2.sql => extras/appengine-django/examples/subquery2.sql rename : extras/appengine/index.yaml => extras/appengine-django/index.yaml rename : extras/appengine/main.py => extras/appengine-django/main.py rename : extras/appengine/settings.py => extras/appengine-django/settings.py rename : extras/appengine/sqlformat/__init__.py => extras/appengine-django/sqlformat/__init__.py rename : extras/appengine/sqlformat/urls.py => extras/appengine-django/sqlformat/urls.py rename : extras/appengine/sqlformat/views.py => extras/appengine-django/sqlformat/views.py rename : extras/appengine/static/bg_options.png => extras/appengine-django/static/bg_options.png rename : extras/appengine/static/bgfieldset.png => extras/appengine-django/static/bgfieldset.png rename : extras/appengine/static/bgfooter.png => extras/appengine-django/static/bgfooter.png rename : extras/appengine/static/bgtop.png => extras/appengine-django/static/bgtop.png rename : extras/appengine/static/blank.gif => extras/appengine-django/static/blank.gif rename : extras/appengine/static/canvas.html => extras/appengine-django/static/canvas.html rename : extras/appengine/static/hotkeys.js => extras/appengine-django/static/hotkeys.js rename : extras/appengine/static/img_loading.gif => extras/appengine-django/static/img_loading.gif rename : extras/appengine/static/jquery.textarearesizer.compressed.js => extras/appengine-django/static/jquery.textarearesizer.compressed.js rename : extras/appengine/static/loading.gif => extras/appengine-django/static/loading.gif rename : extras/appengine/static/lynx_screenshot.png => extras/appengine-django/static/lynx_screenshot.png rename : extras/appengine/static/pygments.css => extras/appengine-django/static/pygments.css rename : extras/appengine/static/resize-grip.png => extras/appengine-django/static/resize-grip.png rename : extras/appengine/static/robots.txt => extras/appengine-django/static/robots.txt rename : extras/appengine/static/rpc_relay.html => extras/appengine-django/static/rpc_relay.html rename : extras/appengine/static/script.js => extras/appengine-django/static/script.js rename : extras/appengine/static/sitemap.xml => extras/appengine-django/static/sitemap.xml rename : extras/appengine/static/sqlformat_client_example.py => extras/appengine-django/static/sqlformat_client_example.py rename : extras/appengine/static/styles.css => extras/appengine-django/static/styles.css rename : extras/appengine/templates/404.html => extras/appengine-django/templates/404.html rename : extras/appengine/templates/500.html => extras/appengine-django/templates/500.html rename : extras/appengine/templates/about.html => extras/appengine-django/templates/about.html rename : extras/appengine/templates/api.html => extras/appengine-django/templates/api.html rename : extras/appengine/templates/index.html => extras/appengine-django/templates/index.html rename : extras/appengine/templates/master.html => extras/appengine-django/templates/master.html rename : extras/appengine/templates/python-client-example.html => extras/appengine-django/templates/python-client-example.html rename : extras/appengine/templates/source.html => extras/appengine-django/templates/source.html --- .hgignore | 2 +- CHANGES | 3 + extras/appengine-django/Makefile | 45 ++++ extras/appengine-django/README | 22 ++ extras/appengine-django/__init__.py | 0 extras/appengine-django/app.yaml | 30 +++ extras/appengine-django/examples/customers.sql | 1 + .../appengine-django/examples/multiple_inserts.sql | 1 + extras/appengine-django/examples/pg_view.sql | 1 + extras/appengine-django/examples/subquery.sql | 1 + extras/appengine-django/examples/subquery2.sql | 1 + extras/appengine-django/index.yaml | 0 extras/appengine-django/main.py | 140 ++++++++++++ extras/appengine-django/settings.py | 38 ++++ extras/appengine-django/sqlformat/__init__.py | 0 extras/appengine-django/sqlformat/urls.py | 11 + extras/appengine-django/sqlformat/views.py | 225 +++++++++++++++++++ extras/appengine-django/static/bg_options.png | Bin 0 -> 202 bytes extras/appengine-django/static/bgfieldset.png | Bin 0 -> 227 bytes extras/appengine-django/static/bgfooter.png | Bin 0 -> 434 bytes extras/appengine-django/static/bgtop.png | Bin 0 -> 430 bytes extras/appengine-django/static/blank.gif | Bin 0 -> 64 bytes extras/appengine-django/static/canvas.html | 114 ++++++++++ extras/appengine-django/static/hotkeys.js | 1 + extras/appengine-django/static/img_loading.gif | Bin 0 -> 1348 bytes .../static/jquery.textarearesizer.compressed.js | 1 + extras/appengine-django/static/loading.gif | Bin 0 -> 4331 bytes extras/appengine-django/static/lynx_screenshot.png | Bin 0 -> 66017 bytes extras/appengine-django/static/pygments.css | 59 +++++ extras/appengine-django/static/resize-grip.png | Bin 0 -> 167 bytes extras/appengine-django/static/robots.txt | 8 + extras/appengine-django/static/rpc_relay.html | 1 + extras/appengine-django/static/script.js | 103 +++++++++ extras/appengine-django/static/sitemap.xml | 25 +++ .../static/sqlformat_client_example.py | 19 ++ extras/appengine-django/static/styles.css | 245 +++++++++++++++++++++ extras/appengine-django/templates/404.html | 12 + extras/appengine-django/templates/500.html | 19 ++ extras/appengine-django/templates/about.html | 46 ++++ extras/appengine-django/templates/api.html | 52 +++++ extras/appengine-django/templates/index.html | 113 ++++++++++ extras/appengine-django/templates/master.html | 104 +++++++++ .../templates/python-client-example.html | 17 ++ extras/appengine-django/templates/source.html | 60 +++++ extras/appengine/Makefile | 45 ---- extras/appengine/README | 25 +-- extras/appengine/__init__.py | 0 extras/appengine/app.yaml | 13 +- extras/appengine/appengine_config.py | 6 + extras/appengine/bootstrap.py | 82 +++++++ extras/appengine/config.py | 7 + extras/appengine/cron.yaml | 4 + extras/appengine/index.yaml | 7 + extras/appengine/main.py | 175 ++++----------- extras/appengine/settings.py | 38 ---- extras/appengine/sqlformat/__init__.py | 24 ++ extras/appengine/sqlformat/legacy.py | 147 +++++++++++++ extras/appengine/sqlformat/templates/about.html | 46 ++++ extras/appengine/sqlformat/templates/api.html | 52 +++++ extras/appengine/sqlformat/templates/index.html | 120 ++++++++++ extras/appengine/sqlformat/templates/master.html | 103 +++++++++ .../sqlformat/templates/python-client-example.html | 17 ++ extras/appengine/sqlformat/templates/source.html | 60 +++++ extras/appengine/sqlformat/urls.py | 11 - extras/appengine/sqlformat/views.py | 225 ------------------- extras/appengine/static/blank.gif | Bin 64 -> 0 bytes extras/appengine/static/canvas.html | 114 ---------- extras/appengine/static/favicon.ico | Bin 0 -> 4162 bytes extras/appengine/static/img_loading.gif | Bin 1348 -> 0 bytes .../static/jquery.textarearesizer.compressed.js | 1 - extras/appengine/static/resize-grip.png | Bin 167 -> 0 bytes extras/appengine/static/rpc_relay.html | 1 - extras/appengine/static/script.js | 7 +- .../appengine/static/sqlformat_client_example.py | 1 + extras/appengine/templates/404.html | 12 - extras/appengine/templates/500.html | 19 -- extras/appengine/templates/about.html | 46 ---- extras/appengine/templates/api.html | 52 ----- extras/appengine/templates/index.html | 113 ---------- extras/appengine/templates/master.html | 104 --------- .../appengine/templates/python-client-example.html | 17 -- extras/appengine/templates/source.html | 60 ----- 82 files changed, 2247 insertions(+), 1027 deletions(-) create mode 100644 extras/appengine-django/Makefile create mode 100644 extras/appengine-django/README create mode 100644 extras/appengine-django/__init__.py create mode 100644 extras/appengine-django/app.yaml create mode 100644 extras/appengine-django/examples/customers.sql create mode 100644 extras/appengine-django/examples/multiple_inserts.sql create mode 100644 extras/appengine-django/examples/pg_view.sql create mode 100644 extras/appengine-django/examples/subquery.sql create mode 100644 extras/appengine-django/examples/subquery2.sql create mode 100644 extras/appengine-django/index.yaml create mode 100644 extras/appengine-django/main.py create mode 100644 extras/appengine-django/settings.py create mode 100644 extras/appengine-django/sqlformat/__init__.py create mode 100644 extras/appengine-django/sqlformat/urls.py create mode 100644 extras/appengine-django/sqlformat/views.py create mode 100644 extras/appengine-django/static/bg_options.png create mode 100644 extras/appengine-django/static/bgfieldset.png create mode 100644 extras/appengine-django/static/bgfooter.png create mode 100644 extras/appengine-django/static/bgtop.png create mode 100644 extras/appengine-django/static/blank.gif create mode 100644 extras/appengine-django/static/canvas.html create mode 100644 extras/appengine-django/static/hotkeys.js create mode 100644 extras/appengine-django/static/img_loading.gif create mode 100644 extras/appengine-django/static/jquery.textarearesizer.compressed.js create mode 100644 extras/appengine-django/static/loading.gif create mode 100644 extras/appengine-django/static/lynx_screenshot.png create mode 100644 extras/appengine-django/static/pygments.css create mode 100644 extras/appengine-django/static/resize-grip.png create mode 100644 extras/appengine-django/static/robots.txt create mode 100644 extras/appengine-django/static/rpc_relay.html create mode 100644 extras/appengine-django/static/script.js create mode 100644 extras/appengine-django/static/sitemap.xml create mode 100644 extras/appengine-django/static/sqlformat_client_example.py create mode 100644 extras/appengine-django/static/styles.css create mode 100644 extras/appengine-django/templates/404.html create mode 100644 extras/appengine-django/templates/500.html create mode 100644 extras/appengine-django/templates/about.html create mode 100644 extras/appengine-django/templates/api.html create mode 100644 extras/appengine-django/templates/index.html create mode 100644 extras/appengine-django/templates/master.html create mode 100644 extras/appengine-django/templates/python-client-example.html create mode 100644 extras/appengine-django/templates/source.html delete mode 100644 extras/appengine/Makefile delete mode 100644 extras/appengine/__init__.py create mode 100644 extras/appengine/appengine_config.py create mode 100755 extras/appengine/bootstrap.py create mode 100644 extras/appengine/config.py create mode 100644 extras/appengine/cron.yaml delete mode 100644 extras/appengine/settings.py create mode 100644 extras/appengine/sqlformat/legacy.py create mode 100644 extras/appengine/sqlformat/templates/about.html create mode 100644 extras/appengine/sqlformat/templates/api.html create mode 100644 extras/appengine/sqlformat/templates/index.html create mode 100644 extras/appengine/sqlformat/templates/master.html create mode 100644 extras/appengine/sqlformat/templates/python-client-example.html create mode 100644 extras/appengine/sqlformat/templates/source.html delete mode 100644 extras/appengine/sqlformat/urls.py delete mode 100644 extras/appengine/sqlformat/views.py delete mode 100644 extras/appengine/static/blank.gif delete mode 100644 extras/appengine/static/canvas.html create mode 100644 extras/appengine/static/favicon.ico delete mode 100644 extras/appengine/static/img_loading.gif delete mode 100644 extras/appengine/static/jquery.textarearesizer.compressed.js delete mode 100644 extras/appengine/static/resize-grip.png delete mode 100644 extras/appengine/static/rpc_relay.html delete mode 100644 extras/appengine/templates/404.html delete mode 100644 extras/appengine/templates/500.html delete mode 100644 extras/appengine/templates/about.html delete mode 100644 extras/appengine/templates/api.html delete mode 100644 extras/appengine/templates/index.html delete mode 100644 extras/appengine/templates/master.html delete mode 100644 extras/appengine/templates/python-client-example.html delete mode 100644 extras/appengine/templates/source.html diff --git a/.hgignore b/.hgignore index a28d991..7444a39 100644 --- a/.hgignore +++ b/.hgignore @@ -5,7 +5,7 @@ dist MANIFEST .coverage extras/appengine/sqlparse -extras/appengine/pygments +extras/appengine/lib/ extras/py3k/sqlparse extras/py3k/tests extras/py3k/sqlparse.diff diff --git a/CHANGES b/CHANGES index f0af911..9a19a6c 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,9 @@ Bug Fixes * Add parsing of MS Access column names with braces (issue27, reported by frankz...@gmail.com). +Other + * Replace Django by Flask in App Engine frontend (issue11). + Release 0.1.2 (Nov 23, 2010) ---------------------------- diff --git a/extras/appengine-django/Makefile b/extras/appengine-django/Makefile new file mode 100644 index 0000000..31393c1 --- /dev/null +++ b/extras/appengine-django/Makefile @@ -0,0 +1,45 @@ +# Makefile to simplify some common AppEngine actions. +# Use 'make help' for a list of commands. + +PYTHON=`which python2.5` +DEV_APPSERVER=$(PYTHON) `which dev_appserver.py` +APPCFG=$(PYTHON) `which appcfg.py` +PORT=8080 + + +default: help + +help: + @echo "Available commands:" + @sed -n '/^[a-zA-Z0-9_.]*:/s/:.*//p' 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-django/examples/subquery.sql b/extras/appengine-django/examples/subquery.sql new file mode 100644 index 0000000..dd4bbc1 --- /dev/null +++ b/extras/appengine-django/examples/subquery.sql @@ -0,0 +1 @@ +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-django/examples/subquery2.sql b/extras/appengine-django/examples/subquery2.sql new file mode 100644 index 0000000..6c00a87 --- /dev/null +++ b/extras/appengine-django/examples/subquery2.sql @@ -0,0 +1 @@ +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-django/index.yaml b/extras/appengine-django/index.yaml new file mode 100644 index 0000000..e69de29 diff --git a/extras/appengine-django/main.py b/extras/appengine-django/main.py new file mode 100644 index 0000000..5014cb9 --- /dev/null +++ b/extras/appengine-django/main.py @@ -0,0 +1,140 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Main program for Rietveld. + +This is also a template for running a Django app under Google App +Engine, especially when using a newer version of Django than provided +in the App Engine standard library. + +The site-specific code is all in other files: urls.py, models.py, +views.py, settings.py. +""" + +# Standard Python imports. +import os +import sys +import logging +import traceback + + +# Log a message each time this module get loaded. +logging.info('Loading %s, app version = %s', + __name__, os.getenv('CURRENT_VERSION_ID')) + +os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' + +from google.appengine.dist import use_library +use_library('django', '1.2') + +# Fail early if we can't import Django. Log identifying information. +import django +logging.info('django.__file__ = %r, django.VERSION = %r', + django.__file__, django.VERSION) +assert django.VERSION[0] >= 1, "This Django version is too old" + +# AppEngine imports. +from google.appengine.ext.webapp import util +from google.appengine.api import mail + + +# Helper to enter the debugger. This passes in __stdin__ and +# __stdout__, because stdin and stdout are connected to the request +# and response streams. You must import this from __main__ to use it. +# (I tried to make it universally available via __builtin__, but that +# doesn't seem to work for some reason.) +def BREAKPOINT(): + import pdb + p = pdb.Pdb(None, sys.__stdin__, sys.__stdout__) + p.set_trace() + + +# Custom Django configuration. +from django.conf import settings +settings._target = None + +# Import various parts of Django. +import django.core.handlers.wsgi +import django.core.signals +import django.db +import django.dispatch.dispatcher +import django.forms + +# Work-around to avoid warning about django.newforms in djangoforms. +django.newforms = django.forms + + +def log_exception(*args, **kwds): + """Django signal handler to log an exception.""" + excinfo = sys.exc_info() + cls, err = excinfo[:2] + subject = 'Exception in request: %s: %s' % (cls.__name__, err) + logging.exception(subject) + try: + repr_request = repr(kwds.get('request', 'Request not available.')) + except: + repr_request = 'Request repr() not available.' + msg = ('Application: %s\nVersion: %s\n\n%s\n\n%s' + % (os.getenv('APPLICATION_ID'), os.getenv('CURRENT_VERSION_ID'), + '\n'.join(traceback.format_exception(*excinfo)), + repr_request)) + mail.send_mail_to_admins('albrecht.andi@googlemail.com', + '[%s] %s' % (os.getenv('APPLICATION_ID'), subject), + msg) + + +# Log all exceptions detected by Django. +django.core.signals.got_request_exception.connect(log_exception) + +# Unregister Django's default rollback event handler. +#django.core.signals.got_request_exception.disconnect( +# django.db._rollback_on_exception) + + +def real_main(): + """Main program.""" + # Create a Django application for WSGI. + application = django.core.handlers.wsgi.WSGIHandler() + # Run the WSGI CGI handler with that application. + util.run_wsgi_app(application) + + +def profile_main(): + """Main program for profiling.""" + import cProfile + import pstats + import StringIO + + prof = cProfile.Profile() + prof = prof.runctx('real_main()', globals(), locals()) + stream = StringIO.StringIO() + stats = pstats.Stats(prof, stream=stream) + # stats.strip_dirs() # Don't; too many modules are named __init__.py. + stats.sort_stats('time') # 'time', 'cumulative' or 'calls' + stats.print_stats() # Optional arg: how many to print + # The rest is optional. + # stats.print_callees() + # stats.print_callers() + print '\n
' + print '

Profile

' + print '
'
+  print stream.getvalue()[:1000000]
+  print '
' + +# Set this to profile_main to enable profiling. +main = real_main + + +if __name__ == '__main__': + main() diff --git a/extras/appengine-django/settings.py b/extras/appengine-django/settings.py new file mode 100644 index 0000000..74af42c --- /dev/null +++ b/extras/appengine-django/settings.py @@ -0,0 +1,38 @@ +# Copyright 2008 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Minimal Django settings.""" + +import os + +APPEND_SLASH = False +DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev') +DEBUG=False +INSTALLED_APPS = ( + 'sqlformat', +) +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.middleware.http.ConditionalGetMiddleware', +# 'codereview.middleware.AddUserToRequestMiddleware', +) +ROOT_URLCONF = 'sqlformat.urls' +TEMPLATE_CONTEXT_PROCESSORS = () +TEMPLATE_DEBUG = DEBUG +TEMPLATE_DIRS = ( + os.path.join(os.path.dirname(__file__), 'templates'), + ) +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + ) diff --git a/extras/appengine-django/sqlformat/__init__.py b/extras/appengine-django/sqlformat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extras/appengine-django/sqlformat/urls.py b/extras/appengine-django/sqlformat/urls.py new file mode 100644 index 0000000..c83290e --- /dev/null +++ b/extras/appengine-django/sqlformat/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls.defaults import * + +urlpatterns = patterns( + 'sqlformat.views', + (r'^$', 'index'), + (r'^source/$', 'source'), + (r'^about/$', 'about'), + (r'^api/$', 'api'), + (r'^format/$', 'format'), + (r'^load_example', 'load_example'), +) diff --git a/extras/appengine-django/sqlformat/views.py b/extras/appengine-django/sqlformat/views.py new file mode 100644 index 0000000..806496f --- /dev/null +++ b/extras/appengine-django/sqlformat/views.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- + +import logging +import md5 +import os +import sys +import time + +from django import forms +from django.http import HttpResponse +from django.template import loader +from django.utils import simplejson as json + +from google.appengine.api import users + +from pygments import highlight +from pygments.formatters import HtmlFormatter +from pygments.lexers import SqlLexer, PythonLexer, PhpLexer + +import sqlparse + + +INITIAL_SQL = "select * from foo join bar on val1 = val2 where id = 123;" +EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), '../examples') + + +# Custom render_to_response() function to avoid loading django.shortcuts +# since django.shortcuts depends on a lot of Django modules we don't need +# here, e.g. lots of modules from django.db. +def render_to_response(template, params=None): + if params is None: + params = {} + return HttpResponse(loader.render_to_string(template, params)) + + +def _get_user_image(user): + if user is None: + return None + digest = md5.new(user.email().lower()).hexdigest() + if os.environ['SERVER_SOFTWARE'].startswith('Dev'): + host = 'localhost%3A8080' + else: + host = 'sqlformat.appspot.com' + default = 'http%3A%2F%2F'+host+'%2Fstatic%2Fblank.gif' + return 'http://gravatar.com/avatar/%s?s=32&d=%s' % (digest, default) + +def _get_examples(): + fnames = os.listdir(EXAMPLES_DIR) + fnames.sort() + return fnames + + +class FormOptions(forms.Form): + data = forms.CharField(widget=forms.Textarea({'class': 'resizable'}), + initial=INITIAL_SQL, required=False) + datafile = forms.FileField(required=False) + highlight = forms.BooleanField(initial=True, required=False, + widget=forms.CheckboxInput(), + label='Enable syntax highlighting') + remove_comments = forms.BooleanField(initial=False, required=False, + widget=forms.CheckboxInput(), + label='Remove comments') + keyword_case = forms.CharField( + widget=forms.Select(choices=(('', 'Unchanged'), + ('lower', 'Lower case'), + ('upper', 'Upper case'), + ('capitalize', 'Capitalize'))), + required=False, initial='upper', label='Keywords') + identifier_case = forms.CharField( + widget=forms.Select(choices=(('', 'Unchanged'), + ('lower', 'Lower case'), + ('upper', 'Upper case'), + ('capitalize', 'Capitalize'))), + required=False, initial='', label='Identifiers') + n_indents = forms.IntegerField(min_value=1, max_value=30, + initial=2, required=False, + label='spaces', + widget=forms.TextInput({'size': 2, + 'maxlength': 2})) +# right_margin = forms.IntegerField(min_value=10, max_value=500, +# initial=60, required=False, +# label='characters', +# widget=forms.TextInput({'size': 3, +# 'maxlength': 3})) + output_format = forms.CharField( + widget=forms.Select(choices=(('sql', 'SQL'), + ('python', 'Python'), + ('php', 'PHP'), + )), + required=False, initial='sql', label='Language') + + def clean(self): + super(FormOptions, self).clean() + data = self.cleaned_data.get('data') + logging.info(self.files) + if 'datafile' in self.files: + self._datafile = self.files['datafile'].read() + else: + self._datafile = None + if not data and not self._datafile: + raise forms.ValidationError('Whoops, I need a file or text!') + elif data and self._datafile: + raise forms.ValidationError('Whoops, I need a file OR text!') + return self.cleaned_data + + def clean_output_format(self): + frmt = self.cleaned_data.get('output_format') + if not frmt: + frmt = 'sql' + return frmt.lower() + + def get_data(self): + data = self.cleaned_data.get('data') + if self._datafile: + return self._datafile + else: + return data + + +def format_sql(form, format='html'): + data = form.cleaned_data + popts = {} + sql = form.get_data() + if data.get('remove_comments'): + popts['strip_comments'] = True + if data.get('keyword_case'): + popts['keyword_case'] = data.get('keyword_case') + if data.get('identifier_case'): + popts['identifier_case'] = data.get('identifier_case') + if data.get('n_indents', None) is not None: + popts['reindent'] = True + popts['indent_width'] = data.get('n_indents') + if data.get('right_margin', None) is not None: + popts['right_margin'] = data.get('right_margin') + if data.get('output_format', None) is not None: + popts['output_format'] = data.get('output_format') + 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 = ('' + % sql) + return sql + + +def index(request): + output = None + data = {} + proc_time = None + if request.method == 'POST': + logging.debug(request.POST) + form = FormOptions(request.POST, request.FILES) + if form.is_valid(): + start = time.time() + output = format_sql(form, + format=request.POST.get('format', 'html')) + proc_time = time.time()-start + else: + form = FormOptions() + if request.POST.get('format', None) == 'json': + logging.warning(form.errors) + data['errors'] = str(form.errors) + data['output'] = output + logging.info('%r', proc_time) + data['proc_time'] = '%.3f' % (proc_time or 0.0) + data = json.dumps(data) + return HttpResponse(data, content_type='text/x-json') + elif request.POST.get('format', None) == 'text': + if not form.is_valid(): + data = str(form.errors) # XXX convert to plain text + else: + data = output + return HttpResponse(data, content_type='text/plain') + return render_to_response('index.html', + {'form': form, 'output': output, + 'proc_time': proc_time and '%.3f' % proc_time or None, + 'user': users.get_current_user(), + 'login_url': users.create_login_url('/'), + 'logout_url': users.create_logout_url('/'), + 'userimg': _get_user_image(users.get_current_user()), + 'examples': _get_examples()}) + + +def format(request): + if request.method == 'POST': + form = FormOptions(request.POST) + if form.is_valid(): + try: + response = format_sql(form, format='text') + except: + err = sys.exc_info()[1] + response = 'ERROR: Parsing failed. %s' % str(err) + else: + response = 'ERROR: %s' % str(form.errors) + else: + response = 'POST request required' + return HttpResponse(response, content_type='text/plain') + +def source(request): + return render_to_response('source.html') + +def about(request): + return render_to_response('about.html') + +def api(request): + return render_to_response('api.html') + +def load_example(request): + fname = request.POST.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 HttpResponse(data, content_type='text/x-json') diff --git a/extras/appengine-django/static/bg_options.png b/extras/appengine-django/static/bg_options.png new file mode 100644 index 0000000..bc1a6ed Binary files /dev/null and b/extras/appengine-django/static/bg_options.png differ diff --git a/extras/appengine-django/static/bgfieldset.png b/extras/appengine-django/static/bgfieldset.png new file mode 100644 index 0000000..4d55f4a Binary files /dev/null and b/extras/appengine-django/static/bgfieldset.png differ diff --git a/extras/appengine-django/static/bgfooter.png b/extras/appengine-django/static/bgfooter.png new file mode 100644 index 0000000..9ce5bdd Binary files /dev/null and b/extras/appengine-django/static/bgfooter.png differ diff --git a/extras/appengine-django/static/bgtop.png b/extras/appengine-django/static/bgtop.png new file mode 100644 index 0000000..a0d4709 Binary files /dev/null and b/extras/appengine-django/static/bgtop.png differ diff --git a/extras/appengine-django/static/blank.gif b/extras/appengine-django/static/blank.gif new file mode 100644 index 0000000..3be2119 Binary files /dev/null and b/extras/appengine-django/static/blank.gif differ diff --git a/extras/appengine-django/static/canvas.html b/extras/appengine-django/static/canvas.html new file mode 100644 index 0000000..ab642d0 --- /dev/null +++ b/extras/appengine-django/static/canvas.html @@ -0,0 +1,114 @@ + + + + + + + +
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/extras/appengine-django/static/hotkeys.js b/extras/appengine-django/static/hotkeys.js new file mode 100644 index 0000000..0e62a92 --- /dev/null +++ b/extras/appengine-django/static/hotkeys.js @@ -0,0 +1 @@ +(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').parent().append($('
').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos \ No newline at end of file diff --git a/extras/appengine-django/static/script.js b/extras/appengine-django/static/script.js new file mode 100644 index 0000000..71bbabb --- /dev/null +++ b/extras/appengine-django/static/script.js @@ -0,0 +1,103 @@ +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.right_margin = $('#id_right_margin').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; + /* jQuery textarea resizer plugin usage */ + $(document).ready(function() { + $('textarea.resizable:not(.processed)').TextAreaResizer(); + }); +} \ No newline at end of file diff --git a/extras/appengine-django/static/sitemap.xml b/extras/appengine-django/static/sitemap.xml new file mode 100644 index 0000000..db3288e --- /dev/null +++ b/extras/appengine-django/static/sitemap.xml @@ -0,0 +1,25 @@ + + + + + + http://sqlformat.appspot.com/ + monthly + + + http://sqlformat.appspot.com/about/ + monthly + + + http://sqlformat.appspot.com/source/ + monthly + + + http://sqlformat.appspot.com/api/ + monthly + + \ No newline at end of file diff --git a/extras/appengine-django/static/sqlformat_client_example.py b/extras/appengine-django/static/sqlformat_client_example.py new file mode 100644 index 0000000..eec17b9 --- /dev/null +++ b/extras/appengine-django/static/sqlformat_client_example.py @@ -0,0 +1,19 @@ +#!/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-django/static/styles.css b/extras/appengine-django/static/styles.css new file mode 100644 index 0000000..41a540a --- /dev/null +++ b/extras/appengine-django/static/styles.css @@ -0,0 +1,245 @@ +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/appengine-django/templates/404.html b/extras/appengine-django/templates/404.html new file mode 100644 index 0000000..1eb60e8 --- /dev/null +++ b/extras/appengine-django/templates/404.html @@ -0,0 +1,12 @@ + + 404 Not Found + +

404 - Not Found.

+

+ If you think this is a bug please file an issue on the tracker: + + http://code.google.com/p/python-sqlparse/issues/list + . +

+ + diff --git a/extras/appengine-django/templates/500.html b/extras/appengine-django/templates/500.html new file mode 100644 index 0000000..8fa8f56 --- /dev/null +++ b/extras/appengine-django/templates/500.html @@ -0,0 +1,19 @@ + + 500 Internal Server Error + +

uups... 500 Internal Server Error.

+

+ Looks like you've hit a bug! Please file an issue on the tracker: + + http://code.google.com/p/python-sqlparse/issues/list + . +

+

+ Please add a short description what happened and if possible add the SQL + statement you've tried to format. +

+

+ Thanks! +

+ + diff --git a/extras/appengine-django/templates/about.html b/extras/appengine-django/templates/about.html new file mode 100644 index 0000000..2d4e03e --- /dev/null +++ b/extras/appengine-django/templates/about.html @@ -0,0 +1,46 @@ +{% extends "master.html" %} + +{% block title %}About{% endblock %} + +{% block main %} +

About this Application

+

+ This application is a online SQL formatting tool. +

+

+ 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 ;-) +

+

+ To get started, enter a SQL statement in the text box on the top, + choose some options and click on "Format SQL" (Ctrl+F) + to see the result. +

+

+ Note: The SQL formatter and parser is in an early stage + of development. If you're looking for a mature tool, try one of + these. +

+

Using it from the Command Line

+

+ There are three ways to use this SQL formatter from the command line: +

+
    +
  1. Grab the sources and use the module in your + Python scripts.
  2. +
  3. + Write a little script in your favorite language that sends a POST + request to this application.
    + Read the API Documentation for more information. +
  4. +
  5. Use + Lynx + +
  6. +
+ +{% endblock %} diff --git a/extras/appengine-django/templates/api.html b/extras/appengine-django/templates/api.html new file mode 100644 index 0000000..79bf118 --- /dev/null +++ b/extras/appengine-django/templates/api.html @@ -0,0 +1,52 @@ +{% extends "master.html" %} + +{% block title %}API{% endblock %} + +{% block main %} +

API Documentation

+ +

+ Using the API for this application is pretty simple. Just send a + POST request to +

+

+ http://sqlformat.appspot.com/format/ +

+ +

Options

+

+ The POST request accepts various options to control + formatting. Only the data option is required. All others + are optional. +

+ +
+
data
+
The SQL statement to format.
+
remove_comments
+
Set to 1 to remove comments.
+
keyword_case
+
How to convert keywords. Allowed values are 'lower', 'upper', + 'capitalize'.
+
identifier_case
+
How to convert identifiers. Allowed values are 'lower', 'upper', + 'capitalize'.
+
n_indents
+
An integer indicating the indendation depth.
+
right_margin
+
An integer indicating the maximum line length.
+
output_format
+
Transfer the statement into another programming language. + Allowed values are 'python', 'php'
+
+ +

Example

+

+ Here's a example in Python: +

+{% include "python-client-example.html" %} +

+ Download sqlformat_example_client.py +

+ +{% endblock %} diff --git a/extras/appengine-django/templates/index.html b/extras/appengine-django/templates/index.html new file mode 100644 index 0000000..3b4ea6f --- /dev/null +++ b/extras/appengine-django/templates/index.html @@ -0,0 +1,113 @@ +{% extends "master.html" %} + +{% block main %} + +{% if output %} + +{% endif %} + +
+
+ {% if form.non_field_errors %}{{form.non_field_errors}}{% endif %} +
+ Type your SQL here:
+ {{form.data}} + {% if form.data.errors %}{{form.data.errors}}{% endif %} +
+
+ ...or upload a file: + {{form.datafile}} +
+
+
+ +
+ {% if output %} +
{{output|safe}}
+ {% else %} +
+ {% endif %} +
+ {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %} +
+
+ + +
+ +
+
+

Options

+
General Options +
+ {{form.remove_comments}} + +
+ {{form.highlight}} + + {% if form.highlight.errors %} +
    {{form.highlight.errors
+ {% endif %} +
+
+
+ Keywords & Identifiers +
+ {{form.keyword_case.label}}: {{form.keyword_case}} +
+
+ {{form.identifier_case.label}}: {{form.identifier_case}} +
+
+
Indentation & Margins + +
+ + {{form.n_indents}} {{form.n_indents.label}} +
Empty field means leave indentation unchanged.
+ +
+
+
Output Format + + {{form.output_format}} +
+ +
This software is in development.
+ +
+ + Flattr this + +
+ +
+
+
+ + +{% endblock %} + diff --git a/extras/appengine-django/templates/master.html b/extras/appengine-django/templates/master.html new file mode 100644 index 0000000..ea1c662 --- /dev/null +++ b/extras/appengine-django/templates/master.html @@ -0,0 +1,104 @@ + + + {% block title %}SQLFormat - Online SQL Formatting Service{% endblock %} + + + + + + + + + + + + +
+

Keyboard Shortcuts

+

+ H - Show / hide this help window
+ Ctrl+F - Format SQL and display result
+ O - Show / hide options
+ T - Set focus on SQL input
+

+
+ + + +
+
+ {% block main %}MAIN CONTENT GOES HERE{% endblock %} +
+
+ + + + + + + + + diff --git a/extras/appengine-django/templates/python-client-example.html b/extras/appengine-django/templates/python-client-example.html new file mode 100644 index 0000000..68bf820 --- /dev/null +++ b/extras/appengine-django/templates/python-client-example.html @@ -0,0 +1,17 @@ +
#!/usr/bin/env python
+
+import urllib
+import urllib2
+
+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('http://sqlformat.appspot.com/format/',
+                           urllib.urlencode(payload))
+print response.read()
+
diff --git a/extras/appengine-django/templates/source.html b/extras/appengine-django/templates/source.html new file mode 100644 index 0000000..a0ed89d --- /dev/null +++ b/extras/appengine-django/templates/source.html @@ -0,0 +1,60 @@ +{% extends "master.html" %} + +{% block title %}Source code{% endblock %} + +{% block main %} +
+

Source Code

+ +

Python Module

+

+ The sources for the SQL parser and formatter module are + hosted on Google Code. + To clone the repository run: +

+ hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse +

+

+ Visit the project page + | + Browse the sources online + | + API Documentation +

+

+ Some relevant parts of the Python module contain code from the + pygments syntax highlighter. + The underlying Python module uses a non-validating SQL parser. + This approach makes it possible to parse even syntactically incorrect + SQL statements. +

+ +

+ Currently the parser module is used by + CrunchyFrog - a + database front-end for Gnome. +

+ +

+ The sqlparse module is released under the terms of the + New BSD License. +

+ +

App Engine Application

+

+ The source code for this App Engine application is available in the + examples directory of the Python module + (but it's really nothing special ;-). +

+ +

Contributing

+

+ Please file bug reports and feature requests on the project site at + http://code.google.com/p/python-sqlparse/issues/entry + or if you have code to contribute upload it to + http://codereview.appspot.com + and add albrecht.andi@googlemail.com as reviewer. +

+ +
+{% endblock %} diff --git a/extras/appengine/Makefile b/extras/appengine/Makefile deleted file mode 100644 index 31393c1..0000000 --- a/extras/appengine/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# Makefile to simplify some common AppEngine actions. -# Use 'make help' for a list of commands. - -PYTHON=`which python2.5` -DEV_APPSERVER=$(PYTHON) `which dev_appserver.py` -APPCFG=$(PYTHON) `which appcfg.py` -PORT=8080 - - -default: help - -help: - @echo "Available commands:" - @sed -n '/^[a-zA-Z0-9_.]*:/s/:.*//p' = 1, "This Django version is too old" - -# AppEngine imports. -from google.appengine.ext.webapp import util -from google.appengine.api import mail - - -# Helper to enter the debugger. This passes in __stdin__ and -# __stdout__, because stdin and stdout are connected to the request -# and response streams. You must import this from __main__ to use it. -# (I tried to make it universally available via __builtin__, but that -# doesn't seem to work for some reason.) -def BREAKPOINT(): - import pdb - p = pdb.Pdb(None, sys.__stdin__, sys.__stdout__) - p.set_trace() - - -# Custom Django configuration. -from django.conf import settings -settings._target = None - -# Import various parts of Django. -import django.core.handlers.wsgi -import django.core.signals -import django.db -import django.dispatch.dispatcher -import django.forms - -# Work-around to avoid warning about django.newforms in djangoforms. -django.newforms = django.forms - - -def log_exception(*args, **kwds): - """Django signal handler to log an exception.""" - excinfo = sys.exc_info() - cls, err = excinfo[:2] - subject = 'Exception in request: %s: %s' % (cls.__name__, err) - logging.exception(subject) - try: - repr_request = repr(kwds.get('request', 'Request not available.')) - except: - repr_request = 'Request repr() not available.' - msg = ('Application: %s\nVersion: %s\n\n%s\n\n%s' - % (os.getenv('APPLICATION_ID'), os.getenv('CURRENT_VERSION_ID'), - '\n'.join(traceback.format_exception(*excinfo)), - repr_request)) - mail.send_mail_to_admins('albrecht.andi@googlemail.com', - '[%s] %s' % (os.getenv('APPLICATION_ID'), subject), - msg) - - -# Log all exceptions detected by Django. -django.core.signals.got_request_exception.connect(log_exception) - -# Unregister Django's default rollback event handler. -#django.core.signals.got_request_exception.disconnect( -# django.db._rollback_on_exception) - - -def real_main(): - """Main program.""" - # Create a Django application for WSGI. - application = django.core.handlers.wsgi.WSGIHandler() - # Run the WSGI CGI handler with that application. - util.run_wsgi_app(application) - - -def profile_main(): - """Main program for profiling.""" - import cProfile - import pstats - import StringIO - - prof = cProfile.Profile() - prof = prof.runctx('real_main()', globals(), locals()) - stream = StringIO.StringIO() - stats = pstats.Stats(prof, stream=stream) - # stats.strip_dirs() # Don't; too many modules are named __init__.py. - stats.sort_stats('time') # 'time', 'cumulative' or 'calls' - stats.print_stats() # Optional arg: how many to print - # The rest is optional. - # stats.print_callees() - # stats.print_callers() - print '\n
' - print '

Profile

' - print '
'
-  print stream.getvalue()[:1000000]
-  print '
' - -# Set this to profile_main to enable profiling. -main = real_main - - -if __name__ == '__main__': - main() +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) + +run_wsgi_app(app) diff --git a/extras/appengine/settings.py b/extras/appengine/settings.py deleted file mode 100644 index 74af42c..0000000 --- a/extras/appengine/settings.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Minimal Django settings.""" - -import os - -APPEND_SLASH = False -DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev') -DEBUG=False -INSTALLED_APPS = ( - 'sqlformat', -) -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.middleware.http.ConditionalGetMiddleware', -# 'codereview.middleware.AddUserToRequestMiddleware', -) -ROOT_URLCONF = 'sqlformat.urls' -TEMPLATE_CONTEXT_PROCESSORS = () -TEMPLATE_DEBUG = DEBUG -TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(__file__), 'templates'), - ) -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - ) diff --git a/extras/appengine/sqlformat/__init__.py b/extras/appengine/sqlformat/__init__.py index e69de29..db9c132 100644 --- a/extras/appengine/sqlformat/__init__.py +++ b/extras/appengine/sqlformat/__init__.py @@ -0,0 +1,24 @@ +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') + +@app.route('/fail') +def fail(): + # test URL for failure handling + raise AssertionError('You shouldn\'t be here!') + + +# 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 new file mode 100644 index 0000000..bf137fb --- /dev/null +++ b/extras/appengine/sqlformat/legacy.py @@ -0,0 +1,147 @@ +"""Legacy URLs.""" + +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']) +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: + sql = files['datafile'].read() + 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 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 = ('' + % sql) + return sql diff --git a/extras/appengine/sqlformat/templates/about.html b/extras/appengine/sqlformat/templates/about.html new file mode 100644 index 0000000..2d4e03e --- /dev/null +++ b/extras/appengine/sqlformat/templates/about.html @@ -0,0 +1,46 @@ +{% extends "master.html" %} + +{% block title %}About{% endblock %} + +{% block main %} +

About this Application

+

+ This application is a online SQL formatting tool. +

+

+ 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 ;-) +

+

+ To get started, enter a SQL statement in the text box on the top, + choose some options and click on "Format SQL" (Ctrl+F) + to see the result. +

+

+ Note: The SQL formatter and parser is in an early stage + of development. If you're looking for a mature tool, try one of + these. +

+

Using it from the Command Line

+

+ There are three ways to use this SQL formatter from the command line: +

+
    +
  1. Grab the sources and use the module in your + Python scripts.
  2. +
  3. + Write a little script in your favorite language that sends a POST + request to this application.
    + Read the API Documentation for more information. +
  4. +
  5. Use + Lynx + +
  6. +
+ +{% endblock %} diff --git a/extras/appengine/sqlformat/templates/api.html b/extras/appengine/sqlformat/templates/api.html new file mode 100644 index 0000000..79bf118 --- /dev/null +++ b/extras/appengine/sqlformat/templates/api.html @@ -0,0 +1,52 @@ +{% extends "master.html" %} + +{% block title %}API{% endblock %} + +{% block main %} +

API Documentation

+ +

+ Using the API for this application is pretty simple. Just send a + POST request to +

+

+ http://sqlformat.appspot.com/format/ +

+ +

Options

+

+ The POST request accepts various options to control + formatting. Only the data option is required. All others + are optional. +

+ +
+
data
+
The SQL statement to format.
+
remove_comments
+
Set to 1 to remove comments.
+
keyword_case
+
How to convert keywords. Allowed values are 'lower', 'upper', + 'capitalize'.
+
identifier_case
+
How to convert identifiers. Allowed values are 'lower', 'upper', + 'capitalize'.
+
n_indents
+
An integer indicating the indendation depth.
+
right_margin
+
An integer indicating the maximum line length.
+
output_format
+
Transfer the statement into another programming language. + Allowed values are 'python', 'php'
+
+ +

Example

+

+ Here's a example in Python: +

+{% include "python-client-example.html" %} +

+ Download sqlformat_example_client.py +

+ +{% endblock %} diff --git a/extras/appengine/sqlformat/templates/index.html b/extras/appengine/sqlformat/templates/index.html new file mode 100644 index 0000000..22d6fdb --- /dev/null +++ b/extras/appengine/sqlformat/templates/index.html @@ -0,0 +1,120 @@ +{% extends "master.html" %} + +{% block main %} + +{% if output %} + +{% endif %} + +
+
+
+ Type your SQL here:
+ +
+
+ ...or upload a file: + +
+
+
+ +
+ {% if output %} +
{{output|safe}}
+ {% else %} +
+ {% endif %} +
+ {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %} +
+
+ + +
+ +
+
+

Options

+
General Options +
+ + +
+ + +
+
+
+ Keywords & Identifiers +
+ Keywords: +
+
+ Identifiers: +
+
+
Indentation & Margins + +
+ + spaces +
Empty field means leave indentation unchanged.
+
+
+
Output Format + + +
+ +
This software is in development.
+ +
+ + + Flattr this + +
+
+ +
+
+
+
+ + +{% endblock %} + diff --git a/extras/appengine/sqlformat/templates/master.html b/extras/appengine/sqlformat/templates/master.html new file mode 100644 index 0000000..88a9d36 --- /dev/null +++ b/extras/appengine/sqlformat/templates/master.html @@ -0,0 +1,103 @@ + + + {% block title %}SQLFormat - Online SQL Formatter{% endblock %} + + + + + + + + + + + +
+

Keyboard Shortcuts

+

+ H - Show / hide this help window
+ Ctrl+F - Format SQL and display result
+ O - Show / hide options
+ T - Set focus on SQL input
+

+
+ + + +
+
+ {% block main %}MAIN CONTENT GOES HERE{% endblock %} +
+
+ + + + + + + + + + diff --git a/extras/appengine/sqlformat/templates/python-client-example.html b/extras/appengine/sqlformat/templates/python-client-example.html new file mode 100644 index 0000000..68bf820 --- /dev/null +++ b/extras/appengine/sqlformat/templates/python-client-example.html @@ -0,0 +1,17 @@ +
#!/usr/bin/env python
+
+import urllib
+import urllib2
+
+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('http://sqlformat.appspot.com/format/',
+                           urllib.urlencode(payload))
+print response.read()
+
diff --git a/extras/appengine/sqlformat/templates/source.html b/extras/appengine/sqlformat/templates/source.html new file mode 100644 index 0000000..a0ed89d --- /dev/null +++ b/extras/appengine/sqlformat/templates/source.html @@ -0,0 +1,60 @@ +{% extends "master.html" %} + +{% block title %}Source code{% endblock %} + +{% block main %} +
+

Source Code

+ +

Python Module

+

+ The sources for the SQL parser and formatter module are + hosted on Google Code. + To clone the repository run: +

+ hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse +

+

+ Visit the project page + | + Browse the sources online + | + API Documentation +

+

+ Some relevant parts of the Python module contain code from the + pygments syntax highlighter. + The underlying Python module uses a non-validating SQL parser. + This approach makes it possible to parse even syntactically incorrect + SQL statements. +

+ +

+ Currently the parser module is used by + CrunchyFrog - a + database front-end for Gnome. +

+ +

+ The sqlparse module is released under the terms of the + New BSD License. +

+ +

App Engine Application

+

+ The source code for this App Engine application is available in the + examples directory of the Python module + (but it's really nothing special ;-). +

+ +

Contributing

+

+ Please file bug reports and feature requests on the project site at + http://code.google.com/p/python-sqlparse/issues/entry + or if you have code to contribute upload it to + http://codereview.appspot.com + and add albrecht.andi@googlemail.com as reviewer. +

+ +
+{% endblock %} diff --git a/extras/appengine/sqlformat/urls.py b/extras/appengine/sqlformat/urls.py deleted file mode 100644 index c83290e..0000000 --- a/extras/appengine/sqlformat/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns( - 'sqlformat.views', - (r'^$', 'index'), - (r'^source/$', 'source'), - (r'^about/$', 'about'), - (r'^api/$', 'api'), - (r'^format/$', 'format'), - (r'^load_example', 'load_example'), -) diff --git a/extras/appengine/sqlformat/views.py b/extras/appengine/sqlformat/views.py deleted file mode 100644 index 806496f..0000000 --- a/extras/appengine/sqlformat/views.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- coding: utf-8 -*- - -import logging -import md5 -import os -import sys -import time - -from django import forms -from django.http import HttpResponse -from django.template import loader -from django.utils import simplejson as json - -from google.appengine.api import users - -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import SqlLexer, PythonLexer, PhpLexer - -import sqlparse - - -INITIAL_SQL = "select * from foo join bar on val1 = val2 where id = 123;" -EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), '../examples') - - -# Custom render_to_response() function to avoid loading django.shortcuts -# since django.shortcuts depends on a lot of Django modules we don't need -# here, e.g. lots of modules from django.db. -def render_to_response(template, params=None): - if params is None: - params = {} - return HttpResponse(loader.render_to_string(template, params)) - - -def _get_user_image(user): - if user is None: - return None - digest = md5.new(user.email().lower()).hexdigest() - if os.environ['SERVER_SOFTWARE'].startswith('Dev'): - host = 'localhost%3A8080' - else: - host = 'sqlformat.appspot.com' - default = 'http%3A%2F%2F'+host+'%2Fstatic%2Fblank.gif' - return 'http://gravatar.com/avatar/%s?s=32&d=%s' % (digest, default) - -def _get_examples(): - fnames = os.listdir(EXAMPLES_DIR) - fnames.sort() - return fnames - - -class FormOptions(forms.Form): - data = forms.CharField(widget=forms.Textarea({'class': 'resizable'}), - initial=INITIAL_SQL, required=False) - datafile = forms.FileField(required=False) - highlight = forms.BooleanField(initial=True, required=False, - widget=forms.CheckboxInput(), - label='Enable syntax highlighting') - remove_comments = forms.BooleanField(initial=False, required=False, - widget=forms.CheckboxInput(), - label='Remove comments') - keyword_case = forms.CharField( - widget=forms.Select(choices=(('', 'Unchanged'), - ('lower', 'Lower case'), - ('upper', 'Upper case'), - ('capitalize', 'Capitalize'))), - required=False, initial='upper', label='Keywords') - identifier_case = forms.CharField( - widget=forms.Select(choices=(('', 'Unchanged'), - ('lower', 'Lower case'), - ('upper', 'Upper case'), - ('capitalize', 'Capitalize'))), - required=False, initial='', label='Identifiers') - n_indents = forms.IntegerField(min_value=1, max_value=30, - initial=2, required=False, - label='spaces', - widget=forms.TextInput({'size': 2, - 'maxlength': 2})) -# right_margin = forms.IntegerField(min_value=10, max_value=500, -# initial=60, required=False, -# label='characters', -# widget=forms.TextInput({'size': 3, -# 'maxlength': 3})) - output_format = forms.CharField( - widget=forms.Select(choices=(('sql', 'SQL'), - ('python', 'Python'), - ('php', 'PHP'), - )), - required=False, initial='sql', label='Language') - - def clean(self): - super(FormOptions, self).clean() - data = self.cleaned_data.get('data') - logging.info(self.files) - if 'datafile' in self.files: - self._datafile = self.files['datafile'].read() - else: - self._datafile = None - if not data and not self._datafile: - raise forms.ValidationError('Whoops, I need a file or text!') - elif data and self._datafile: - raise forms.ValidationError('Whoops, I need a file OR text!') - return self.cleaned_data - - def clean_output_format(self): - frmt = self.cleaned_data.get('output_format') - if not frmt: - frmt = 'sql' - return frmt.lower() - - def get_data(self): - data = self.cleaned_data.get('data') - if self._datafile: - return self._datafile - else: - return data - - -def format_sql(form, format='html'): - data = form.cleaned_data - popts = {} - sql = form.get_data() - if data.get('remove_comments'): - popts['strip_comments'] = True - if data.get('keyword_case'): - popts['keyword_case'] = data.get('keyword_case') - if data.get('identifier_case'): - popts['identifier_case'] = data.get('identifier_case') - if data.get('n_indents', None) is not None: - popts['reindent'] = True - popts['indent_width'] = data.get('n_indents') - if data.get('right_margin', None) is not None: - popts['right_margin'] = data.get('right_margin') - if data.get('output_format', None) is not None: - popts['output_format'] = data.get('output_format') - 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 = ('' - % sql) - return sql - - -def index(request): - output = None - data = {} - proc_time = None - if request.method == 'POST': - logging.debug(request.POST) - form = FormOptions(request.POST, request.FILES) - if form.is_valid(): - start = time.time() - output = format_sql(form, - format=request.POST.get('format', 'html')) - proc_time = time.time()-start - else: - form = FormOptions() - if request.POST.get('format', None) == 'json': - logging.warning(form.errors) - data['errors'] = str(form.errors) - data['output'] = output - logging.info('%r', proc_time) - data['proc_time'] = '%.3f' % (proc_time or 0.0) - data = json.dumps(data) - return HttpResponse(data, content_type='text/x-json') - elif request.POST.get('format', None) == 'text': - if not form.is_valid(): - data = str(form.errors) # XXX convert to plain text - else: - data = output - return HttpResponse(data, content_type='text/plain') - return render_to_response('index.html', - {'form': form, 'output': output, - 'proc_time': proc_time and '%.3f' % proc_time or None, - 'user': users.get_current_user(), - 'login_url': users.create_login_url('/'), - 'logout_url': users.create_logout_url('/'), - 'userimg': _get_user_image(users.get_current_user()), - 'examples': _get_examples()}) - - -def format(request): - if request.method == 'POST': - form = FormOptions(request.POST) - if form.is_valid(): - try: - response = format_sql(form, format='text') - except: - err = sys.exc_info()[1] - response = 'ERROR: Parsing failed. %s' % str(err) - else: - response = 'ERROR: %s' % str(form.errors) - else: - response = 'POST request required' - return HttpResponse(response, content_type='text/plain') - -def source(request): - return render_to_response('source.html') - -def about(request): - return render_to_response('about.html') - -def api(request): - return render_to_response('api.html') - -def load_example(request): - fname = request.POST.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 HttpResponse(data, content_type='text/x-json') diff --git a/extras/appengine/static/blank.gif b/extras/appengine/static/blank.gif deleted file mode 100644 index 3be2119..0000000 Binary files a/extras/appengine/static/blank.gif and /dev/null differ diff --git a/extras/appengine/static/canvas.html b/extras/appengine/static/canvas.html deleted file mode 100644 index ab642d0..0000000 --- a/extras/appengine/static/canvas.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - -
- - - - - -
- - -
- - \ No newline at end of file diff --git a/extras/appengine/static/favicon.ico b/extras/appengine/static/favicon.ico new file mode 100644 index 0000000..1372520 Binary files /dev/null and b/extras/appengine/static/favicon.ico differ diff --git a/extras/appengine/static/img_loading.gif b/extras/appengine/static/img_loading.gif deleted file mode 100644 index 6465823..0000000 Binary files a/extras/appengine/static/img_loading.gif and /dev/null differ diff --git a/extras/appengine/static/jquery.textarearesizer.compressed.js b/extras/appengine/static/jquery.textarearesizer.compressed.js deleted file mode 100644 index 5464ae6..0000000 --- a/extras/appengine/static/jquery.textarearesizer.compressed.js +++ /dev/null @@ -1 +0,0 @@ -(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('
').parent().append($('
').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos \ No newline at end of file diff --git a/extras/appengine/static/script.js b/extras/appengine/static/script.js index 71bbabb..8bdf271 100644 --- a/extras/appengine/static/script.js +++ b/extras/appengine/static/script.js @@ -11,7 +11,6 @@ function update_output() { data.keyword_case = $('#id_keyword_case').val(); data.identifier_case = $('#id_identifier_case').val(); data.n_indents = $('#id_n_indents').val(); - data.right_margin = $('#id_right_margin').val(); data.output_format = $('#id_output_format').val(); form = document.getElementById('form_options'); $(form.elements).attr('disabled', 'disabled'); @@ -72,7 +71,7 @@ function load_example() { fname = $('#sel_example').val(); data = {fname: fname}; $.post('/load_example', data, - function(data) { + function(data) { $('#id_data').val(data.answer); }, 'json'); } @@ -96,8 +95,4 @@ function init() { $(document).bind('keydown', {combi: 't', disableInInput: true}, textarea_grab_focus); initialized = true; - /* jQuery textarea resizer plugin usage */ - $(document).ready(function() { - $('textarea.resizable:not(.processed)').TextAreaResizer(); - }); } \ No newline at end of file diff --git a/extras/appengine/static/sqlformat_client_example.py b/extras/appengine/static/sqlformat_client_example.py index eec17b9..8b2a9e9 100644 --- a/extras/appengine/static/sqlformat_client_example.py +++ b/extras/appengine/static/sqlformat_client_example.py @@ -13,6 +13,7 @@ payload = ( ('n_indents', 2), ) + response = urllib2.urlopen(REMOTE_API, urllib.urlencode(payload)) print response.read() diff --git a/extras/appengine/templates/404.html b/extras/appengine/templates/404.html deleted file mode 100644 index 1eb60e8..0000000 --- a/extras/appengine/templates/404.html +++ /dev/null @@ -1,12 +0,0 @@ - - 404 Not Found - -

404 - Not Found.

-

- If you think this is a bug please file an issue on the tracker: - - http://code.google.com/p/python-sqlparse/issues/list - . -

- - diff --git a/extras/appengine/templates/500.html b/extras/appengine/templates/500.html deleted file mode 100644 index 8fa8f56..0000000 --- a/extras/appengine/templates/500.html +++ /dev/null @@ -1,19 +0,0 @@ - - 500 Internal Server Error - -

uups... 500 Internal Server Error.

-

- Looks like you've hit a bug! Please file an issue on the tracker: - - http://code.google.com/p/python-sqlparse/issues/list - . -

-

- Please add a short description what happened and if possible add the SQL - statement you've tried to format. -

-

- Thanks! -

- - diff --git a/extras/appengine/templates/about.html b/extras/appengine/templates/about.html deleted file mode 100644 index 2d4e03e..0000000 --- a/extras/appengine/templates/about.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "master.html" %} - -{% block title %}About{% endblock %} - -{% block main %} -

About this Application

-

- This application is a online SQL formatting tool. -

-

- 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 ;-) -

-

- To get started, enter a SQL statement in the text box on the top, - choose some options and click on "Format SQL" (Ctrl+F) - to see the result. -

-

- Note: The SQL formatter and parser is in an early stage - of development. If you're looking for a mature tool, try one of - these. -

-

Using it from the Command Line

-

- There are three ways to use this SQL formatter from the command line: -

-
    -
  1. Grab the sources and use the module in your - Python scripts.
  2. -
  3. - Write a little script in your favorite language that sends a POST - request to this application.
    - Read the API Documentation for more information. -
  4. -
  5. Use - Lynx - -
  6. -
- -{% endblock %} diff --git a/extras/appengine/templates/api.html b/extras/appengine/templates/api.html deleted file mode 100644 index 79bf118..0000000 --- a/extras/appengine/templates/api.html +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "master.html" %} - -{% block title %}API{% endblock %} - -{% block main %} -

API Documentation

- -

- Using the API for this application is pretty simple. Just send a - POST request to -

-

- http://sqlformat.appspot.com/format/ -

- -

Options

-

- The POST request accepts various options to control - formatting. Only the data option is required. All others - are optional. -

- -
-
data
-
The SQL statement to format.
-
remove_comments
-
Set to 1 to remove comments.
-
keyword_case
-
How to convert keywords. Allowed values are 'lower', 'upper', - 'capitalize'.
-
identifier_case
-
How to convert identifiers. Allowed values are 'lower', 'upper', - 'capitalize'.
-
n_indents
-
An integer indicating the indendation depth.
-
right_margin
-
An integer indicating the maximum line length.
-
output_format
-
Transfer the statement into another programming language. - Allowed values are 'python', 'php'
-
- -

Example

-

- Here's a example in Python: -

-{% include "python-client-example.html" %} -

- Download sqlformat_example_client.py -

- -{% endblock %} diff --git a/extras/appengine/templates/index.html b/extras/appengine/templates/index.html deleted file mode 100644 index 3b4ea6f..0000000 --- a/extras/appengine/templates/index.html +++ /dev/null @@ -1,113 +0,0 @@ -{% extends "master.html" %} - -{% block main %} - -{% if output %} - -{% endif %} - -
-
- {% if form.non_field_errors %}{{form.non_field_errors}}{% endif %} -
- Type your SQL here:
- {{form.data}} - {% if form.data.errors %}{{form.data.errors}}{% endif %} -
-
- ...or upload a file: - {{form.datafile}} -
-
-
- -
- {% if output %} -
{{output|safe}}
- {% else %} -
- {% endif %} -
- {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %} -
-
- - -
- -
-
-

Options

-
General Options -
- {{form.remove_comments}} - -
- {{form.highlight}} - - {% if form.highlight.errors %} -
    {{form.highlight.errors
- {% endif %} -
-
-
- Keywords & Identifiers -
- {{form.keyword_case.label}}: {{form.keyword_case}} -
-
- {{form.identifier_case.label}}: {{form.identifier_case}} -
-
-
Indentation & Margins - -
- - {{form.n_indents}} {{form.n_indents.label}} -
Empty field means leave indentation unchanged.
- -
-
-
Output Format - - {{form.output_format}} -
- -
This software is in development.
- -
- - Flattr this - -
- -
-
-
- - -{% endblock %} - diff --git a/extras/appengine/templates/master.html b/extras/appengine/templates/master.html deleted file mode 100644 index ea1c662..0000000 --- a/extras/appengine/templates/master.html +++ /dev/null @@ -1,104 +0,0 @@ - - - {% block title %}SQLFormat - Online SQL Formatting Service{% endblock %} - - - - - - - - - - - - -
-

Keyboard Shortcuts

-

- H - Show / hide this help window
- Ctrl+F - Format SQL and display result
- O - Show / hide options
- T - Set focus on SQL input
-

-
- - - -
-
- {% block main %}MAIN CONTENT GOES HERE{% endblock %} -
-
- - - - - - - - - diff --git a/extras/appengine/templates/python-client-example.html b/extras/appengine/templates/python-client-example.html deleted file mode 100644 index 68bf820..0000000 --- a/extras/appengine/templates/python-client-example.html +++ /dev/null @@ -1,17 +0,0 @@ -
#!/usr/bin/env python
-
-import urllib
-import urllib2
-
-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('http://sqlformat.appspot.com/format/',
-                           urllib.urlencode(payload))
-print response.read()
-
diff --git a/extras/appengine/templates/source.html b/extras/appengine/templates/source.html deleted file mode 100644 index a0ed89d..0000000 --- a/extras/appengine/templates/source.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "master.html" %} - -{% block title %}Source code{% endblock %} - -{% block main %} -
-

Source Code

- -

Python Module

-

- The sources for the SQL parser and formatter module are - hosted on Google Code. - To clone the repository run: -

- hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse -

-

- Visit the project page - | - Browse the sources online - | - API Documentation -

-

- Some relevant parts of the Python module contain code from the - pygments syntax highlighter. - The underlying Python module uses a non-validating SQL parser. - This approach makes it possible to parse even syntactically incorrect - SQL statements. -

- -

- Currently the parser module is used by - CrunchyFrog - a - database front-end for Gnome. -

- -

- The sqlparse module is released under the terms of the - New BSD License. -

- -

App Engine Application

-

- The source code for this App Engine application is available in the - examples directory of the Python module - (but it's really nothing special ;-). -

- -

Contributing

-

- Please file bug reports and feature requests on the project site at - http://code.google.com/p/python-sqlparse/issues/entry - or if you have code to contribute upload it to - http://codereview.appspot.com - and add albrecht.andi@googlemail.com as reviewer. -

- -
-{% endblock %} -- cgit v1.2.1 From d83aaa24369e9a4b5531ffb90379c02a52025544 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 21:05:15 +0200 Subject: Remove obsolete Django version of web application. --- extras/appengine-django/Makefile | 45 ---- extras/appengine-django/README | 22 -- extras/appengine-django/__init__.py | 0 extras/appengine-django/app.yaml | 30 --- extras/appengine-django/examples/customers.sql | 1 - .../appengine-django/examples/multiple_inserts.sql | 1 - extras/appengine-django/examples/pg_view.sql | 1 - extras/appengine-django/examples/subquery.sql | 1 - extras/appengine-django/examples/subquery2.sql | 1 - extras/appengine-django/index.yaml | 0 extras/appengine-django/main.py | 140 ------------ extras/appengine-django/settings.py | 38 ---- extras/appengine-django/sqlformat/__init__.py | 0 extras/appengine-django/sqlformat/urls.py | 11 - extras/appengine-django/sqlformat/views.py | 225 ------------------- extras/appengine-django/static/bg_options.png | Bin 202 -> 0 bytes extras/appengine-django/static/bgfieldset.png | Bin 227 -> 0 bytes extras/appengine-django/static/bgfooter.png | Bin 434 -> 0 bytes extras/appengine-django/static/bgtop.png | Bin 430 -> 0 bytes extras/appengine-django/static/blank.gif | Bin 64 -> 0 bytes extras/appengine-django/static/canvas.html | 114 ---------- extras/appengine-django/static/hotkeys.js | 1 - extras/appengine-django/static/img_loading.gif | Bin 1348 -> 0 bytes .../static/jquery.textarearesizer.compressed.js | 1 - extras/appengine-django/static/loading.gif | Bin 4331 -> 0 bytes extras/appengine-django/static/lynx_screenshot.png | Bin 66017 -> 0 bytes extras/appengine-django/static/pygments.css | 59 ----- extras/appengine-django/static/resize-grip.png | Bin 167 -> 0 bytes extras/appengine-django/static/robots.txt | 8 - extras/appengine-django/static/rpc_relay.html | 1 - extras/appengine-django/static/script.js | 103 --------- extras/appengine-django/static/sitemap.xml | 25 --- .../static/sqlformat_client_example.py | 19 -- extras/appengine-django/static/styles.css | 245 --------------------- extras/appengine-django/templates/404.html | 12 - extras/appengine-django/templates/500.html | 19 -- extras/appengine-django/templates/about.html | 46 ---- extras/appengine-django/templates/api.html | 52 ----- extras/appengine-django/templates/index.html | 113 ---------- extras/appengine-django/templates/master.html | 104 --------- .../templates/python-client-example.html | 17 -- extras/appengine-django/templates/source.html | 60 ----- 42 files changed, 1515 deletions(-) delete mode 100644 extras/appengine-django/Makefile delete mode 100644 extras/appengine-django/README delete mode 100644 extras/appengine-django/__init__.py delete mode 100644 extras/appengine-django/app.yaml delete mode 100644 extras/appengine-django/examples/customers.sql delete mode 100644 extras/appengine-django/examples/multiple_inserts.sql delete mode 100644 extras/appengine-django/examples/pg_view.sql delete mode 100644 extras/appengine-django/examples/subquery.sql delete mode 100644 extras/appengine-django/examples/subquery2.sql delete mode 100644 extras/appengine-django/index.yaml delete mode 100644 extras/appengine-django/main.py delete mode 100644 extras/appengine-django/settings.py delete mode 100644 extras/appengine-django/sqlformat/__init__.py delete mode 100644 extras/appengine-django/sqlformat/urls.py delete mode 100644 extras/appengine-django/sqlformat/views.py delete mode 100644 extras/appengine-django/static/bg_options.png delete mode 100644 extras/appengine-django/static/bgfieldset.png delete mode 100644 extras/appengine-django/static/bgfooter.png delete mode 100644 extras/appengine-django/static/bgtop.png delete mode 100644 extras/appengine-django/static/blank.gif delete mode 100644 extras/appengine-django/static/canvas.html delete mode 100644 extras/appengine-django/static/hotkeys.js delete mode 100644 extras/appengine-django/static/img_loading.gif delete mode 100644 extras/appengine-django/static/jquery.textarearesizer.compressed.js delete mode 100644 extras/appengine-django/static/loading.gif delete mode 100644 extras/appengine-django/static/lynx_screenshot.png delete mode 100644 extras/appengine-django/static/pygments.css delete mode 100644 extras/appengine-django/static/resize-grip.png delete mode 100644 extras/appengine-django/static/robots.txt delete mode 100644 extras/appengine-django/static/rpc_relay.html delete mode 100644 extras/appengine-django/static/script.js delete mode 100644 extras/appengine-django/static/sitemap.xml delete mode 100644 extras/appengine-django/static/sqlformat_client_example.py delete mode 100644 extras/appengine-django/static/styles.css delete mode 100644 extras/appengine-django/templates/404.html delete mode 100644 extras/appengine-django/templates/500.html delete mode 100644 extras/appengine-django/templates/about.html delete mode 100644 extras/appengine-django/templates/api.html delete mode 100644 extras/appengine-django/templates/index.html delete mode 100644 extras/appengine-django/templates/master.html delete mode 100644 extras/appengine-django/templates/python-client-example.html delete mode 100644 extras/appengine-django/templates/source.html diff --git a/extras/appengine-django/Makefile b/extras/appengine-django/Makefile deleted file mode 100644 index 31393c1..0000000 --- a/extras/appengine-django/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# Makefile to simplify some common AppEngine actions. -# Use 'make help' for a list of commands. - -PYTHON=`which python2.5` -DEV_APPSERVER=$(PYTHON) `which dev_appserver.py` -APPCFG=$(PYTHON) `which appcfg.py` -PORT=8080 - - -default: help - -help: - @echo "Available commands:" - @sed -n '/^[a-zA-Z0-9_.]*:/s/:.*//p' 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-django/examples/subquery.sql b/extras/appengine-django/examples/subquery.sql deleted file mode 100644 index dd4bbc1..0000000 --- a/extras/appengine-django/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-django/examples/subquery2.sql b/extras/appengine-django/examples/subquery2.sql deleted file mode 100644 index 6c00a87..0000000 --- a/extras/appengine-django/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-django/index.yaml b/extras/appengine-django/index.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/extras/appengine-django/main.py b/extras/appengine-django/main.py deleted file mode 100644 index 5014cb9..0000000 --- a/extras/appengine-django/main.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Main program for Rietveld. - -This is also a template for running a Django app under Google App -Engine, especially when using a newer version of Django than provided -in the App Engine standard library. - -The site-specific code is all in other files: urls.py, models.py, -views.py, settings.py. -""" - -# Standard Python imports. -import os -import sys -import logging -import traceback - - -# Log a message each time this module get loaded. -logging.info('Loading %s, app version = %s', - __name__, os.getenv('CURRENT_VERSION_ID')) - -os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' - -from google.appengine.dist import use_library -use_library('django', '1.2') - -# Fail early if we can't import Django. Log identifying information. -import django -logging.info('django.__file__ = %r, django.VERSION = %r', - django.__file__, django.VERSION) -assert django.VERSION[0] >= 1, "This Django version is too old" - -# AppEngine imports. -from google.appengine.ext.webapp import util -from google.appengine.api import mail - - -# Helper to enter the debugger. This passes in __stdin__ and -# __stdout__, because stdin and stdout are connected to the request -# and response streams. You must import this from __main__ to use it. -# (I tried to make it universally available via __builtin__, but that -# doesn't seem to work for some reason.) -def BREAKPOINT(): - import pdb - p = pdb.Pdb(None, sys.__stdin__, sys.__stdout__) - p.set_trace() - - -# Custom Django configuration. -from django.conf import settings -settings._target = None - -# Import various parts of Django. -import django.core.handlers.wsgi -import django.core.signals -import django.db -import django.dispatch.dispatcher -import django.forms - -# Work-around to avoid warning about django.newforms in djangoforms. -django.newforms = django.forms - - -def log_exception(*args, **kwds): - """Django signal handler to log an exception.""" - excinfo = sys.exc_info() - cls, err = excinfo[:2] - subject = 'Exception in request: %s: %s' % (cls.__name__, err) - logging.exception(subject) - try: - repr_request = repr(kwds.get('request', 'Request not available.')) - except: - repr_request = 'Request repr() not available.' - msg = ('Application: %s\nVersion: %s\n\n%s\n\n%s' - % (os.getenv('APPLICATION_ID'), os.getenv('CURRENT_VERSION_ID'), - '\n'.join(traceback.format_exception(*excinfo)), - repr_request)) - mail.send_mail_to_admins('albrecht.andi@googlemail.com', - '[%s] %s' % (os.getenv('APPLICATION_ID'), subject), - msg) - - -# Log all exceptions detected by Django. -django.core.signals.got_request_exception.connect(log_exception) - -# Unregister Django's default rollback event handler. -#django.core.signals.got_request_exception.disconnect( -# django.db._rollback_on_exception) - - -def real_main(): - """Main program.""" - # Create a Django application for WSGI. - application = django.core.handlers.wsgi.WSGIHandler() - # Run the WSGI CGI handler with that application. - util.run_wsgi_app(application) - - -def profile_main(): - """Main program for profiling.""" - import cProfile - import pstats - import StringIO - - prof = cProfile.Profile() - prof = prof.runctx('real_main()', globals(), locals()) - stream = StringIO.StringIO() - stats = pstats.Stats(prof, stream=stream) - # stats.strip_dirs() # Don't; too many modules are named __init__.py. - stats.sort_stats('time') # 'time', 'cumulative' or 'calls' - stats.print_stats() # Optional arg: how many to print - # The rest is optional. - # stats.print_callees() - # stats.print_callers() - print '\n
' - print '

Profile

' - print '
'
-  print stream.getvalue()[:1000000]
-  print '
' - -# Set this to profile_main to enable profiling. -main = real_main - - -if __name__ == '__main__': - main() diff --git a/extras/appengine-django/settings.py b/extras/appengine-django/settings.py deleted file mode 100644 index 74af42c..0000000 --- a/extras/appengine-django/settings.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Minimal Django settings.""" - -import os - -APPEND_SLASH = False -DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev') -DEBUG=False -INSTALLED_APPS = ( - 'sqlformat', -) -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.middleware.http.ConditionalGetMiddleware', -# 'codereview.middleware.AddUserToRequestMiddleware', -) -ROOT_URLCONF = 'sqlformat.urls' -TEMPLATE_CONTEXT_PROCESSORS = () -TEMPLATE_DEBUG = DEBUG -TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(__file__), 'templates'), - ) -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - ) diff --git a/extras/appengine-django/sqlformat/__init__.py b/extras/appengine-django/sqlformat/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/extras/appengine-django/sqlformat/urls.py b/extras/appengine-django/sqlformat/urls.py deleted file mode 100644 index c83290e..0000000 --- a/extras/appengine-django/sqlformat/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns( - 'sqlformat.views', - (r'^$', 'index'), - (r'^source/$', 'source'), - (r'^about/$', 'about'), - (r'^api/$', 'api'), - (r'^format/$', 'format'), - (r'^load_example', 'load_example'), -) diff --git a/extras/appengine-django/sqlformat/views.py b/extras/appengine-django/sqlformat/views.py deleted file mode 100644 index 806496f..0000000 --- a/extras/appengine-django/sqlformat/views.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- coding: utf-8 -*- - -import logging -import md5 -import os -import sys -import time - -from django import forms -from django.http import HttpResponse -from django.template import loader -from django.utils import simplejson as json - -from google.appengine.api import users - -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import SqlLexer, PythonLexer, PhpLexer - -import sqlparse - - -INITIAL_SQL = "select * from foo join bar on val1 = val2 where id = 123;" -EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), '../examples') - - -# Custom render_to_response() function to avoid loading django.shortcuts -# since django.shortcuts depends on a lot of Django modules we don't need -# here, e.g. lots of modules from django.db. -def render_to_response(template, params=None): - if params is None: - params = {} - return HttpResponse(loader.render_to_string(template, params)) - - -def _get_user_image(user): - if user is None: - return None - digest = md5.new(user.email().lower()).hexdigest() - if os.environ['SERVER_SOFTWARE'].startswith('Dev'): - host = 'localhost%3A8080' - else: - host = 'sqlformat.appspot.com' - default = 'http%3A%2F%2F'+host+'%2Fstatic%2Fblank.gif' - return 'http://gravatar.com/avatar/%s?s=32&d=%s' % (digest, default) - -def _get_examples(): - fnames = os.listdir(EXAMPLES_DIR) - fnames.sort() - return fnames - - -class FormOptions(forms.Form): - data = forms.CharField(widget=forms.Textarea({'class': 'resizable'}), - initial=INITIAL_SQL, required=False) - datafile = forms.FileField(required=False) - highlight = forms.BooleanField(initial=True, required=False, - widget=forms.CheckboxInput(), - label='Enable syntax highlighting') - remove_comments = forms.BooleanField(initial=False, required=False, - widget=forms.CheckboxInput(), - label='Remove comments') - keyword_case = forms.CharField( - widget=forms.Select(choices=(('', 'Unchanged'), - ('lower', 'Lower case'), - ('upper', 'Upper case'), - ('capitalize', 'Capitalize'))), - required=False, initial='upper', label='Keywords') - identifier_case = forms.CharField( - widget=forms.Select(choices=(('', 'Unchanged'), - ('lower', 'Lower case'), - ('upper', 'Upper case'), - ('capitalize', 'Capitalize'))), - required=False, initial='', label='Identifiers') - n_indents = forms.IntegerField(min_value=1, max_value=30, - initial=2, required=False, - label='spaces', - widget=forms.TextInput({'size': 2, - 'maxlength': 2})) -# right_margin = forms.IntegerField(min_value=10, max_value=500, -# initial=60, required=False, -# label='characters', -# widget=forms.TextInput({'size': 3, -# 'maxlength': 3})) - output_format = forms.CharField( - widget=forms.Select(choices=(('sql', 'SQL'), - ('python', 'Python'), - ('php', 'PHP'), - )), - required=False, initial='sql', label='Language') - - def clean(self): - super(FormOptions, self).clean() - data = self.cleaned_data.get('data') - logging.info(self.files) - if 'datafile' in self.files: - self._datafile = self.files['datafile'].read() - else: - self._datafile = None - if not data and not self._datafile: - raise forms.ValidationError('Whoops, I need a file or text!') - elif data and self._datafile: - raise forms.ValidationError('Whoops, I need a file OR text!') - return self.cleaned_data - - def clean_output_format(self): - frmt = self.cleaned_data.get('output_format') - if not frmt: - frmt = 'sql' - return frmt.lower() - - def get_data(self): - data = self.cleaned_data.get('data') - if self._datafile: - return self._datafile - else: - return data - - -def format_sql(form, format='html'): - data = form.cleaned_data - popts = {} - sql = form.get_data() - if data.get('remove_comments'): - popts['strip_comments'] = True - if data.get('keyword_case'): - popts['keyword_case'] = data.get('keyword_case') - if data.get('identifier_case'): - popts['identifier_case'] = data.get('identifier_case') - if data.get('n_indents', None) is not None: - popts['reindent'] = True - popts['indent_width'] = data.get('n_indents') - if data.get('right_margin', None) is not None: - popts['right_margin'] = data.get('right_margin') - if data.get('output_format', None) is not None: - popts['output_format'] = data.get('output_format') - 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 = ('' - % sql) - return sql - - -def index(request): - output = None - data = {} - proc_time = None - if request.method == 'POST': - logging.debug(request.POST) - form = FormOptions(request.POST, request.FILES) - if form.is_valid(): - start = time.time() - output = format_sql(form, - format=request.POST.get('format', 'html')) - proc_time = time.time()-start - else: - form = FormOptions() - if request.POST.get('format', None) == 'json': - logging.warning(form.errors) - data['errors'] = str(form.errors) - data['output'] = output - logging.info('%r', proc_time) - data['proc_time'] = '%.3f' % (proc_time or 0.0) - data = json.dumps(data) - return HttpResponse(data, content_type='text/x-json') - elif request.POST.get('format', None) == 'text': - if not form.is_valid(): - data = str(form.errors) # XXX convert to plain text - else: - data = output - return HttpResponse(data, content_type='text/plain') - return render_to_response('index.html', - {'form': form, 'output': output, - 'proc_time': proc_time and '%.3f' % proc_time or None, - 'user': users.get_current_user(), - 'login_url': users.create_login_url('/'), - 'logout_url': users.create_logout_url('/'), - 'userimg': _get_user_image(users.get_current_user()), - 'examples': _get_examples()}) - - -def format(request): - if request.method == 'POST': - form = FormOptions(request.POST) - if form.is_valid(): - try: - response = format_sql(form, format='text') - except: - err = sys.exc_info()[1] - response = 'ERROR: Parsing failed. %s' % str(err) - else: - response = 'ERROR: %s' % str(form.errors) - else: - response = 'POST request required' - return HttpResponse(response, content_type='text/plain') - -def source(request): - return render_to_response('source.html') - -def about(request): - return render_to_response('about.html') - -def api(request): - return render_to_response('api.html') - -def load_example(request): - fname = request.POST.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 HttpResponse(data, content_type='text/x-json') diff --git a/extras/appengine-django/static/bg_options.png b/extras/appengine-django/static/bg_options.png deleted file mode 100644 index bc1a6ed..0000000 Binary files a/extras/appengine-django/static/bg_options.png and /dev/null differ diff --git a/extras/appengine-django/static/bgfieldset.png b/extras/appengine-django/static/bgfieldset.png deleted file mode 100644 index 4d55f4a..0000000 Binary files a/extras/appengine-django/static/bgfieldset.png and /dev/null differ diff --git a/extras/appengine-django/static/bgfooter.png b/extras/appengine-django/static/bgfooter.png deleted file mode 100644 index 9ce5bdd..0000000 Binary files a/extras/appengine-django/static/bgfooter.png and /dev/null differ diff --git a/extras/appengine-django/static/bgtop.png b/extras/appengine-django/static/bgtop.png deleted file mode 100644 index a0d4709..0000000 Binary files a/extras/appengine-django/static/bgtop.png and /dev/null differ diff --git a/extras/appengine-django/static/blank.gif b/extras/appengine-django/static/blank.gif deleted file mode 100644 index 3be2119..0000000 Binary files a/extras/appengine-django/static/blank.gif and /dev/null differ diff --git a/extras/appengine-django/static/canvas.html b/extras/appengine-django/static/canvas.html deleted file mode 100644 index ab642d0..0000000 --- a/extras/appengine-django/static/canvas.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - -
- - - - - -
- - -
- - \ No newline at end of file diff --git a/extras/appengine-django/static/hotkeys.js b/extras/appengine-django/static/hotkeys.js deleted file mode 100644 index 0e62a92..0000000 --- a/extras/appengine-django/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').parent().append($('
').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos \ No newline at end of file diff --git a/extras/appengine-django/static/script.js b/extras/appengine-django/static/script.js deleted file mode 100644 index 71bbabb..0000000 --- a/extras/appengine-django/static/script.js +++ /dev/null @@ -1,103 +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.right_margin = $('#id_right_margin').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; - /* jQuery textarea resizer plugin usage */ - $(document).ready(function() { - $('textarea.resizable:not(.processed)').TextAreaResizer(); - }); -} \ No newline at end of file diff --git a/extras/appengine-django/static/sitemap.xml b/extras/appengine-django/static/sitemap.xml deleted file mode 100644 index db3288e..0000000 --- a/extras/appengine-django/static/sitemap.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - http://sqlformat.appspot.com/ - monthly - - - http://sqlformat.appspot.com/about/ - monthly - - - http://sqlformat.appspot.com/source/ - monthly - - - http://sqlformat.appspot.com/api/ - monthly - - \ No newline at end of file diff --git a/extras/appengine-django/static/sqlformat_client_example.py b/extras/appengine-django/static/sqlformat_client_example.py deleted file mode 100644 index eec17b9..0000000 --- a/extras/appengine-django/static/sqlformat_client_example.py +++ /dev/null @@ -1,19 +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-django/static/styles.css b/extras/appengine-django/static/styles.css deleted file mode 100644 index 41a540a..0000000 --- a/extras/appengine-django/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/appengine-django/templates/404.html b/extras/appengine-django/templates/404.html deleted file mode 100644 index 1eb60e8..0000000 --- a/extras/appengine-django/templates/404.html +++ /dev/null @@ -1,12 +0,0 @@ - - 404 Not Found - -

404 - Not Found.

-

- If you think this is a bug please file an issue on the tracker: - - http://code.google.com/p/python-sqlparse/issues/list - . -

- - diff --git a/extras/appengine-django/templates/500.html b/extras/appengine-django/templates/500.html deleted file mode 100644 index 8fa8f56..0000000 --- a/extras/appengine-django/templates/500.html +++ /dev/null @@ -1,19 +0,0 @@ - - 500 Internal Server Error - -

uups... 500 Internal Server Error.

-

- Looks like you've hit a bug! Please file an issue on the tracker: - - http://code.google.com/p/python-sqlparse/issues/list - . -

-

- Please add a short description what happened and if possible add the SQL - statement you've tried to format. -

-

- Thanks! -

- - diff --git a/extras/appengine-django/templates/about.html b/extras/appengine-django/templates/about.html deleted file mode 100644 index 2d4e03e..0000000 --- a/extras/appengine-django/templates/about.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "master.html" %} - -{% block title %}About{% endblock %} - -{% block main %} -

About this Application

-

- This application is a online SQL formatting tool. -

-

- 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 ;-) -

-

- To get started, enter a SQL statement in the text box on the top, - choose some options and click on "Format SQL" (Ctrl+F) - to see the result. -

-

- Note: The SQL formatter and parser is in an early stage - of development. If you're looking for a mature tool, try one of - these. -

-

Using it from the Command Line

-

- There are three ways to use this SQL formatter from the command line: -

-
    -
  1. Grab the sources and use the module in your - Python scripts.
  2. -
  3. - Write a little script in your favorite language that sends a POST - request to this application.
    - Read the API Documentation for more information. -
  4. -
  5. Use - Lynx - -
  6. -
- -{% endblock %} diff --git a/extras/appengine-django/templates/api.html b/extras/appengine-django/templates/api.html deleted file mode 100644 index 79bf118..0000000 --- a/extras/appengine-django/templates/api.html +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "master.html" %} - -{% block title %}API{% endblock %} - -{% block main %} -

API Documentation

- -

- Using the API for this application is pretty simple. Just send a - POST request to -

-

- http://sqlformat.appspot.com/format/ -

- -

Options

-

- The POST request accepts various options to control - formatting. Only the data option is required. All others - are optional. -

- -
-
data
-
The SQL statement to format.
-
remove_comments
-
Set to 1 to remove comments.
-
keyword_case
-
How to convert keywords. Allowed values are 'lower', 'upper', - 'capitalize'.
-
identifier_case
-
How to convert identifiers. Allowed values are 'lower', 'upper', - 'capitalize'.
-
n_indents
-
An integer indicating the indendation depth.
-
right_margin
-
An integer indicating the maximum line length.
-
output_format
-
Transfer the statement into another programming language. - Allowed values are 'python', 'php'
-
- -

Example

-

- Here's a example in Python: -

-{% include "python-client-example.html" %} -

- Download sqlformat_example_client.py -

- -{% endblock %} diff --git a/extras/appengine-django/templates/index.html b/extras/appengine-django/templates/index.html deleted file mode 100644 index 3b4ea6f..0000000 --- a/extras/appengine-django/templates/index.html +++ /dev/null @@ -1,113 +0,0 @@ -{% extends "master.html" %} - -{% block main %} - -{% if output %} - -{% endif %} - -
-
- {% if form.non_field_errors %}{{form.non_field_errors}}{% endif %} -
- Type your SQL here:
- {{form.data}} - {% if form.data.errors %}{{form.data.errors}}{% endif %} -
-
- ...or upload a file: - {{form.datafile}} -
-
-
- -
- {% if output %} -
{{output|safe}}
- {% else %} -
- {% endif %} -
- {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %} -
-
- - -
- -
-
-

Options

-
General Options -
- {{form.remove_comments}} - -
- {{form.highlight}} - - {% if form.highlight.errors %} -
    {{form.highlight.errors
- {% endif %} -
-
-
- Keywords & Identifiers -
- {{form.keyword_case.label}}: {{form.keyword_case}} -
-
- {{form.identifier_case.label}}: {{form.identifier_case}} -
-
-
Indentation & Margins - -
- - {{form.n_indents}} {{form.n_indents.label}} -
Empty field means leave indentation unchanged.
- -
-
-
Output Format - - {{form.output_format}} -
- -
This software is in development.
- -
- - Flattr this - -
- -
-
-
- - -{% endblock %} - diff --git a/extras/appengine-django/templates/master.html b/extras/appengine-django/templates/master.html deleted file mode 100644 index ea1c662..0000000 --- a/extras/appengine-django/templates/master.html +++ /dev/null @@ -1,104 +0,0 @@ - - - {% block title %}SQLFormat - Online SQL Formatting Service{% endblock %} - - - - - - - - - - - - -
-

Keyboard Shortcuts

-

- H - Show / hide this help window
- Ctrl+F - Format SQL and display result
- O - Show / hide options
- T - Set focus on SQL input
-

-
- - - -
-
- {% block main %}MAIN CONTENT GOES HERE{% endblock %} -
-
- - - - - - - - - diff --git a/extras/appengine-django/templates/python-client-example.html b/extras/appengine-django/templates/python-client-example.html deleted file mode 100644 index 68bf820..0000000 --- a/extras/appengine-django/templates/python-client-example.html +++ /dev/null @@ -1,17 +0,0 @@ -
#!/usr/bin/env python
-
-import urllib
-import urllib2
-
-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('http://sqlformat.appspot.com/format/',
-                           urllib.urlencode(payload))
-print response.read()
-
diff --git a/extras/appengine-django/templates/source.html b/extras/appengine-django/templates/source.html deleted file mode 100644 index a0ed89d..0000000 --- a/extras/appengine-django/templates/source.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "master.html" %} - -{% block title %}Source code{% endblock %} - -{% block main %} -
-

Source Code

- -

Python Module

-

- The sources for the SQL parser and formatter module are - hosted on Google Code. - To clone the repository run: -

- hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse -

-

- Visit the project page - | - Browse the sources online - | - API Documentation -

-

- Some relevant parts of the Python module contain code from the - pygments syntax highlighter. - The underlying Python module uses a non-validating SQL parser. - This approach makes it possible to parse even syntactically incorrect - SQL statements. -

- -

- Currently the parser module is used by - CrunchyFrog - a - database front-end for Gnome. -

- -

- The sqlparse module is released under the terms of the - New BSD License. -

- -

App Engine Application

-

- The source code for this App Engine application is available in the - examples directory of the Python module - (but it's really nothing special ;-). -

- -

Contributing

-

- Please file bug reports and feature requests on the project site at - http://code.google.com/p/python-sqlparse/issues/entry - or if you have code to contribute upload it to - http://codereview.appspot.com - and add albrecht.andi@googlemail.com as reviewer. -

- -
-{% endblock %} -- cgit v1.2.1 From 0058f06ba2309b3d7851e6509f70bf533258795c Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 21:19:04 +0200 Subject: Minor fixes to make the py3k version work again. --- sqlparse/lexer.py | 2 +- tests/utils.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sqlparse/lexer.py b/sqlparse/lexer.py index ecfdbce..8929e3e 100644 --- a/sqlparse/lexer.py +++ b/sqlparse/lexer.py @@ -150,7 +150,7 @@ class LexerMeta(type): return type.__call__(cls, *args, **kwds) -class Lexer: +class Lexer(object): __metaclass__ = LexerMeta diff --git a/tests/utils.py b/tests/utils.py index 6135dc3..e2c01a3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -33,6 +33,7 @@ class TestCaseBase(unittest.TestCase): ssecond = unicode(second) diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines()) fp = StringIO() - print >> fp, NL, NL.join(diff) + fp.write(NL) + fp.write(NL.join(diff)) print fp.getvalue() raise self.failureException, fp.getvalue() -- cgit v1.2.1 From 5adefeeaa6df776d76ee62df824eecbc5ed31545 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 21:59:59 +0200 Subject: Update version. --- CHANGES | 4 ++-- sqlparse/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 9a19a6c..2b3d88a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -In Development --------------- +Release 0.1.3 (Jul 29, 2011) +---------------------------- Bug Fixes * Improve parsing of floats (thanks to Kris). diff --git a/sqlparse/__init__.py b/sqlparse/__init__.py index 903fdd1..7698e46 100644 --- a/sqlparse/__init__.py +++ b/sqlparse/__init__.py @@ -6,7 +6,7 @@ """Parse SQL statements.""" -__version__ = '0.1.2' +__version__ = '0.1.3' class SQLParseError(Exception): -- cgit v1.2.1 From 9030635cce5346a1c6de844f6bc22283d2da6f06 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Fri, 29 Jul 2011 22:00:32 +0200 Subject: This is 0.1.3 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index fea6495..1cdbba6 100644 --- a/.hgtags +++ b/.hgtags @@ -1,3 +1,4 @@ 49f461d2899eb3175ba7d935337e5938403372d4 0.1.0 294617d5c43131aacd11ddccc9ccb238a41bf563 0.1.1 079b282ad3ee0d620128ee64e2bba5791e733b62 0.1.2 +ac9ea581527a4540d46d766c07b23a88dd04704c 0.1.3 -- cgit v1.2.1 From 718616c4123fcdac4ec2d15eed641f6f80da9600 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Sat, 30 Jul 2011 21:46:51 +0200 Subject: Don't write diffs when generating py3k version. Since the diff contains non-ascii chars it causes an error on buildbot. See http://bugs.python.org/issue7922 --- extras/py3k/Makefile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/extras/py3k/Makefile b/extras/py3k/Makefile index 499f2bf..57fcaeb 100644 --- a/extras/py3k/Makefile +++ b/extras/py3k/Makefile @@ -1,17 +1,16 @@ -2TO3=2to3-3.1 +2TO3=2to3 +2TO3OPTS=--no-diffs -w -n all: sqlparse tests sqlparse: cp -r ../../sqlparse . - $(2TO3) sqlparse > sqlparse.diff - patch -p0 < sqlparse.diff + $(2TO3) $(2TO3OPTS) sqlparse patch -p0 < fixes.diff tests: cp -r ../../tests . - $(2TO3) tests > tests.diff - patch -p0 < tests.diff + $(2TO3) $(2TO3OPTS) tests clean: rm -rf sqlparse -- cgit v1.2.1 From 4563cc1468f9ce313cfaa535f709711c3763a46d Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Tue, 2 Aug 2011 10:12:20 +0200 Subject: Decode uploaded files data. There were some UnicodeDecodeErrors happening when a file with non-ascii chars was uploaded. files[..].read() returns a string. --- extras/appengine/sqlformat/legacy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/appengine/sqlformat/legacy.py b/extras/appengine/sqlformat/legacy.py index bf137fb..9d53479 100644 --- a/extras/appengine/sqlformat/legacy.py +++ b/extras/appengine/sqlformat/legacy.py @@ -105,7 +105,7 @@ def _get_examples(): def _get_sql(data, files=None): sql = None if files is not None and 'datafile' in files: - sql = files['datafile'].read() + sql = files['datafile'].read().decode('utf-8') if not sql: sql = data.get('data') return sql or '' -- cgit v1.2.1 From 530da46905753a1e950bcc7e736d72a7309033c6 Mon Sep 17 00:00:00 2001 From: Andi Albrecht Date: Thu, 4 Aug 2011 10:05:11 +0200 Subject: Silence UnicodeDecodeErrors, but try to collect some demo data. --- extras/appengine/sqlformat/legacy.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/extras/appengine/sqlformat/legacy.py b/extras/appengine/sqlformat/legacy.py index 9d53479..6d3aaf8 100644 --- a/extras/appengine/sqlformat/legacy.py +++ b/extras/appengine/sqlformat/legacy.py @@ -105,7 +105,18 @@ def _get_examples(): def _get_sql(data, files=None): sql = None if files is not None and 'datafile' in files: - sql = files['datafile'].read().decode('utf-8') + 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 '' -- cgit v1.2.1