diff options
Diffstat (limited to 'extras/appengine/sqlformat')
| -rw-r--r-- | extras/appengine/sqlformat/__init__.py | 24 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/legacy.py | 158 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/about.html | 46 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/api.html | 52 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/index.html | 120 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/master.html | 103 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/python-client-example.html | 17 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/templates/source.html | 60 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/urls.py | 11 | ||||
| -rw-r--r-- | extras/appengine/sqlformat/views.py | 225 |
10 files changed, 580 insertions, 236 deletions
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..6d3aaf8 --- /dev/null +++ b/extras/appengine/sqlformat/legacy.py @@ -0,0 +1,158 @@ +"""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: + raw = files['datafile'].read() + try: + sql = raw.decode('utf-8') + except UnicodeDecodeError, err: + logging.error(err) + logging.debug(repr(raw)) + sql = (u'-- UnicodeDecodeError: %s\n' + u'-- Please make sure to upload UTF-8 encoded data for now.\n' + u'-- If you want to help improving this part of the application\n' + u'-- please file a bug with some demo data at:\n' + u'-- http://code.google.com/p/python-sqlparse/issues/entry\n' + u'-- Thanks!\n' % err) + if not sql: + sql = data.get('data') + return sql or '' + + +def _format_sql(sql, data, format='html'): + popts = {} + if data.get('remove_comments'): + popts['strip_comments'] = True + if data.get('keyword_case', 'undefined') not in ('undefined', ''): + popts['keyword_case'] = data.get('keyword_case') + if data.get('identifier_case', 'undefined') not in ('undefined', ''): + popts['identifier_case'] = data.get('identifier_case') + if data.get('n_indents', None) is not None: + val = data.get('n_indents') + try: + popts['indent_width'] = max(1, min(1000, int(val))) + popts['reindent'] = True + except (ValueError, TypeError): + pass + if data.get('output_format', None) is not None: + popts['output_format'] = data.get('output_format') + logging.debug('Format: %s, POPTS: %r', format, popts) + logging.debug(sql) + sql = sqlparse.format(sql, **popts) + if format in ('html', 'json'): + if data.get('highlight', False): + if popts['output_format'] == 'python': + lexer = PythonLexer() + elif popts['output_format'] == 'php': + lexer = PhpLexer() + else: + lexer = SqlLexer() + sql = highlight(sql, lexer, HtmlFormatter()) + else: + sql = ('<textarea class="resizable" ' + 'style="height: 350px; margin-top: 1em;">%s</textarea>' + % sql) + return sql diff --git a/extras/appengine/sqlformat/templates/about.html b/extras/appengine/sqlformat/templates/about.html 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 %} +<h1>About this Application</h1> +<p> + This application is a online SQL formatting tool. +</p> +<p> + Basically it's a playground for a Python module to parse and format + SQL statements. Sometimes it's easier to combine the available + options and to see the resulting output using a web front-end than + on the command line ;-) +</p> +<p> + To get started, enter a SQL statement in the text box on the top, + choose some options and click on "Format SQL" (Ctrl+F) + to see the result. +</p> +<p> + <em>Note:</em> The SQL formatter and parser is in an early stage + of development. If you're looking for a mature tool, try one of + <a href="http://www.google.com/search?q=online+sql+formatter">these</a>. +</p> +<h2>Using it from the Command Line</h2> +<p> + There are three ways to use this SQL formatter from the command line: +</p> +<ol> + <li>Grab the <a href="/source/">sources</a> and use the module in your + Python scripts.</li> + <li> + Write a little script in your favorite language that sends a POST + request to this application.<br/> + Read the <a href="/api/">API Documentation</a> for more information. + </li> + <li>Use + <a href="/static/lynx_screenshot.png" + alt="Lynx Screenshot" target="_blank" + title="Screenshot: sqlformat.appspot.com on Lynx">Lynx + </a> + </li> +</ol> + +{% endblock %} diff --git a/extras/appengine/sqlformat/templates/api.html b/extras/appengine/sqlformat/templates/api.html 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 %} +<h1>API Documentation</h1> + +<p> + Using the API for this application is pretty simple. Just send a + <code>POST</code> request to +</p> +<p> + <code>http://sqlformat.appspot.com/format/</code> +</p> + +<h2>Options</h2> +<p> + The <code>POST</code> request accepts various options to control + formatting. Only the <em>data</em> option is required. All others + are optional. +</p> + +<dl> + <dt>data</dt> + <dd>The SQL statement to format.</dd> + <dt>remove_comments</dt> + <dd>Set to 1 to remove comments.</dd> + <dt>keyword_case</dt> + <dd>How to convert keywords. Allowed values are 'lower', 'upper', + 'capitalize'.</dd> + <dt>identifier_case</dt> + <dd>How to convert identifiers. Allowed values are 'lower', 'upper', + 'capitalize'.</dd> + <dt>n_indents</dt> + <dd>An integer indicating the indendation depth.</dd> + <dt>right_margin</dt> + <dd>An integer indicating the maximum line length.</dd> + <dt>output_format</dt> + <dd>Transfer the statement into another programming language. + Allowed values are 'python', 'php'</dd> +</dl> + +<h2>Example</h2> +<p> + Here's a example in Python: +</p> +{% include "python-client-example.html" %} +<p> + <a href="/static/sqlformat_client_example.py">Download sqlformat_example_client.py</a> +</p> + +{% 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 %} + <a href="#output" class="skip">Jump to formatted query</a> +{% endif %} + +<form method="post" action="" id="form_options" enctype="multipart/form-data"> + <div id="input"> + <div> + <strong>Type your SQL here:</strong><br /> + <textarea id="id_data" rows="10" cols="40" name="data" class="resizable">{{ sql_orig }}</textarea> + </div> + <div style="margin-top: .5em;"> + <strong>...or upload a file:</strong> + <input type="file" name="datafile" id="id_datafile" /> + </div> + <div id="examples" style="margin-top: .5em;"></div> + <div id="actions" style="margin-top: .5em;"> + <input type="submit" value="Format SQL" id="btn_format" /> + </div> + {% if output %}<a name="output"></a> + <div id="response">{{output|safe}}</div> + {% else %} + <div id="response"></div> + {% endif %} + <div id="proc_time"> + {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %} + </div> + <div style="margin-top: 1em;"> + <script type="text/javascript"> + <!-- + google_ad_client = "pub-8870624642249726"; + /* 468x60, Erstellt 07.03.09 */ + google_ad_slot = "9840041509"; + google_ad_width = 468; + google_ad_height = 60; + //--> + </script> + <script type="text/javascript" + src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> + </script> + </div> + + </div> + <div id="options"> + <h1 class="skip">Options</h1> + <fieldset><legend id="general"><strong>General Options</strong></legend> + <div id="general_content" class="content"> + <input type="checkbox" id="id_remove_comments" name="remove_comments" value="1" {% if extra.comments %}checked="checked"{% endif %}/> + <label for="id_remove_comments">Remove comments</label> + <br /> + <input type="checkbox" id="id_highlight" name="highlight" value="1" {% if extra.highlight %}checked="checked"{% endif %} /> + <label for="id_highlight">Enable syntax highlighting</label> + </div> + </fieldset> + <fieldset><legend id="kwcase"> + <strong>Keywords & Identifiers</strong></legend> + <div> + Keywords: <select id="id_keyword_case" name="keyword_case"> + <option value="">Unchanged</option> + <option value="lower" {% if extra.keywords == 'lower' %}selected="selected"{% endif %}>Lower case</option> + <option value="upper" {% if extra.keywords == 'upper' %}selected="selected"{% endif %}>Upper case</option> + <option value="capitalize" {% if extra.keywords == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option> + </select> + </div> + <div> + Identifiers: <select name="identifier_case" id="id_identifier_case"> + <option value="">Unchanged</option> + <option value="lower" {% if extra.idcase == 'lower' %}selected="selected"{% endif %}>Lower case</option> + <option value="upper" {% if extra.idcase == 'upper' %}selected="selected"{% endif %}>Upper case</option> + <option value="capitalize" {% if extra.idcase == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option> + </select> + </div> + </fieldset> + <fieldset><legend id="indent"><strong>Indentation & Margins</strong> + </legend> + <div id="indent_content" class="content"> + <label for="id_n_indents">Indentation: </label> + <input name="n_indents" value="{{extra.n_indents}}" maxlength="2" type="text" id="id_n_indents" size="2" /> spaces + <div class="help">Empty field means leave indentation unchanged.</div> + </div> + </fieldset> + <fieldset><legend id="output"><strong>Output Format</strong></legend> + <label for="id_output_format">Language: </label> + <select name="output_format" id="id_output_format"> + <option value="sql" {% if extra.lang == 'sql' %}selected="selected"{% endif %}>SQL</option> + <option value="python" {% if extra.lang == 'python' %}selected="selected"{% endif %}>Python</option> + <option value="php" {% if extra.lang == 'php' %}selected="selected"{% endif %}>PHP</option> + </select> + </fieldset> + + <div class="dev">This software is in development.</div> + + <div> + <g:plusone size="medium"></g:plusone> + <a href="http://flattr.com/thing/350724/SQLFormat-Online-SQL-formatting-service" target="_blank"> + <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /> + </a> + </div> + <div style="padding-top: 15px;"> + <a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="andialbrecht">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script> + </div> + </div> + <div class="clearfix"></div> +</form> + +<script language="javascript"> +html = '<strong>...or select an example:</strong> '; +html = html + '<select onchange="load_example();" id="sel_example">'; +html = html + '<option value="">-- Choose Example --</option>'; +{% for ex in examples %} + html = html + '<option value="{{ex}}">{{ex}}</option>'; +{% endfor %} +html = html + '</select>'; +$('#examples').html(html); +</script> +{% endblock %} + diff --git a/extras/appengine/sqlformat/templates/master.html b/extras/appengine/sqlformat/templates/master.html new file mode 100644 index 0000000..88a9d36 --- /dev/null +++ b/extras/appengine/sqlformat/templates/master.html @@ -0,0 +1,103 @@ +<html> + <head> + <title>{% block title %}SQLFormat - Online SQL Formatter{% endblock %}</title> + <meta name="keywords" content="SQL, format, parse, python, beautify, pretty, online, formatting, formatter" /> + <meta name="description" content="Easy to use web service to format SQL statements." /> + <link rel="stylesheet" href="/static/pygments.css" /> + <link rel="stylesheet" href="/static/styles.css" /> + <script src="http://www.google.com/jsapi"></script> + <script> + google.load("jquery", "1.2.6"); + </script> + <script src="/static/hotkeys.js"></script> + <script src="/static/script.js"></script> + </head> + <body> + + <div id="help"> + <p>Keyboard Shortcuts</p> + <p> + <span class="shortcut">H</span> - Show / hide this help window<br/> + <span class="shortcut">Ctrl+F</span> - Format SQL and display result<br/> + <span class="shortcut">O</span> - Show / hide options<br/> + <span class="shortcut">T</span> - Set focus on SQL input<br/> + </p> + </div> + + <div id="header"> + <div id="header-inner"> + {% if user %}<img src="{{userimg}}" border="0" align="right" style="padding-top:.4em;"/>{% endif %} + <h1> + <a href="/"> + <span class="q">S<span class="q2">Q</span>L</span>Format + </a> + </h1> + <div id="slogan">Online SQL formatting service</div> + <div id="topmenu"> + <a href="/">Home</a> + | + <a href="/about/">About</a> + | + <a href="/source/">Source Code</a> + | + <a href="/api/">API</a> +<!-- + | + {% if user %} + <a href="{{logout_url}}">Sign out</a> + {% else %} + <a href="{{login_url}}">Sign in</a> + <span style="color: #babdb6;">with your Google account + to save preferred settings.</span> + {% endif %} +--> + </div> + </div> + </div> + + <div id="main"> + <div id="main-inner"> + {% block main %}MAIN CONTENT GOES HERE{% endblock %} + </div> + </div> + + <div id="footer"> + <div id="footer-inner"> + <div style="float: left; font-size: .85em;"> + <div>© 2011 Andi Albrecht + <code><albrecht dot andi gmail></code> + </div> + <div> + <a href="/">Home</a> + | + <a href="/about/">About</a> + | + <a href="/source/">Source Code</a> + | + <a href="/api/">API</a> + | + <a href="http://andialbrecht.wordpress.com/">Blog</a> + </div> + </div> + <div style="float: right;"> + <img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif" + alt="Powered by Google App Engine" /> + </div> + <div class="clearfix"></div> + </div> + </div> + + <script type="text/javascript"> + var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); + document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); + </script> + <script type="text/javascript"> + try { + var pageTracker = _gat._getTracker("UA-3535525-2"); + pageTracker._trackPageview(); + } catch(err) {}</script> + <script>init();</script> + <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script> + + </body> +</html> diff --git a/extras/appengine/sqlformat/templates/python-client-example.html b/extras/appengine/sqlformat/templates/python-client-example.html new file mode 100644 index 0000000..68bf820 --- /dev/null +++ b/extras/appengine/sqlformat/templates/python-client-example.html @@ -0,0 +1,17 @@ +<div class="highlight example"><pre><span class="c">#!/usr/bin/env python</span> + +<span class="k">import</span> <span class="nn">urllib</span> +<span class="k">import</span> <span class="nn">urllib2</span> + +<span class="n">payload</span> <span class="o">=</span> <span class="p">(</span> + <span class="p">(</span><span class="s">'data'</span><span class="p">,</span> <span class="s">'select * from foo join bar on val1 = val2 where id = 123;'</span><span class="p">),</span> + <span class="p">(</span><span class="s">'format'</span><span class="p">,</span> <span class="s">'text'</span><span class="p">),</span> + <span class="p">(</span><span class="s">'keyword_case'</span><span class="p">,</span> <span class="s">'upper'</span><span class="p">),</span> + <span class="p">(</span><span class="s">'reindent'</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span> + <span class="p">(</span><span class="s">'n_indents'</span><span class="p">,</span> <span class="mf">2</span><span class="p">),</span> + <span class="p">)</span> + +<span class="n">response</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">'http://sqlformat.appspot.com/format/'</span><span class="p">,</span> + <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">payload</span><span class="p">))</span> +<span class="k">print</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> +</pre></div> diff --git a/extras/appengine/sqlformat/templates/source.html b/extras/appengine/sqlformat/templates/source.html 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 %} +<div id="response"> + <h1>Source Code</h1> + + <h2>Python Module</h2> + <p> + The sources for the SQL parser and formatter module are + hosted on Google Code. + To clone the repository run: + <p> + <code class="pre"> hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse</code> + </p> + <p> + <a href="http://python-sqlparse.googlecode.com">Visit the project page</a> + | + <a href="http://code.google.com/p/python-sqlparse/source/browse/">Browse the sources online</a> + | + <a href="http://python-sqlparse.googlecode.com/svn/docs/api/index.html"> API Documentation</a> + </p> + <p> + Some relevant parts of the Python module contain code from the + <a href="http://pygments.org/">pygments</a> syntax highlighter. + The underlying Python module uses a non-validating SQL parser. + This approach makes it possible to parse even syntactically incorrect + SQL statements. + </p> + + <p> + Currently the parser module is used by + <a href="http://crunchyfrog.googlecode.com/">CrunchyFrog</a> - a + database front-end for Gnome. + </p> + + <p> + The <code>sqlparse</code> module is released under the terms of the + <a href="http://www.opensource.org/licenses/bsd-license.php">New BSD License</a>. + </p> + + <h2>App Engine Application</h2> + <p> + The source code for this App Engine application is available in the + <code>examples</code> directory of the Python module + (but it's really nothing special ;-). + </p> + + <h2>Contributing</h2> + <p> + Please file bug reports and feature requests on the project site at + <a href="http://code.google.com/p/python-sqlparse/issues/entry">http://code.google.com/p/python-sqlparse/issues/entry</a> + or if you have code to contribute upload it to + <a href="http://codereview.appspot.com">http://codereview.appspot.com</a> + and add albrecht.andi@googlemail.com as reviewer. + </p> + +</div> +{% endblock %} diff --git a/extras/appengine/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 = ('<textarea class="resizable" ' - 'style="height: 350px; margin-top: 1em;">%s</textarea>' - % 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') |
