From bf2d4e04c4b1470f32f871825f1a816e30dd3094 Mon Sep 17 00:00:00 2001 From: Sebastian Silva Date: Sun, 20 Nov 2011 08:29:24 +0000 Subject: Branched Hello World Web Activity --- diff --git a/activity.py b/activity.py index 879bccf..4d8a8ba 100644 --- a/activity.py +++ b/activity.py @@ -129,21 +129,17 @@ class HelloWorldActivity(activity.Activity): toolbar_box.toolbar.insert(separator, -1) separator.show() - #play_image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PLAY, - # gtk.ICON_SIZE_BUTTON) - #play_image.show() - + """ Disabled start_button = ToolButton('go-home') - #start_button.set_icon_widget(play_image) - start_button.show() - start_button.connect('clicked', self.__start_button_cb) - toolbar_box.toolbar.insert(start_button, -1) + start_button.connect('clicked', self.__start_button_cb) + start_button.show() debug_button = ToolButton("activity-debug") toolbar_box.toolbar.insert(debug_button, -1) debug_button.connect('clicked', self.__debug_button_cb) debug_button.show() + """ stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) @@ -208,7 +204,6 @@ class HelloWorldActivity(activity.Activity): if self._shared_activity: self.share_server() - def share_server(self): # Make a tube for it chan = self._shared_activity.telepathy_tubes_chan diff --git a/activity/activity-helloworld.svg b/activity/activity-helloworld.svg index 8da7c63..13dc787 100644 --- a/activity/activity-helloworld.svg +++ b/activity/activity-helloworld.svg @@ -1,26 +1,118 @@ - + ]> - - - - - image/svg+xml + - - - - - - - + r="19.903" + cy="27.5" + cx="27.375" + d="m 47.278,27.5 c 0,10.992123 -8.910877,19.903 -19.903,19.903 -10.992123,0 -19.9029999,-8.910877 -19.9029999,-19.903 0,-10.992123 8.9108769,-19.9029999 19.9029999,-19.9029999 10.992123,0 19.903,8.9108769 19.903,19.9029999 z" + sodipodi:cx="27.375" + sodipodi:cy="27.5" + sodipodi:rx="19.903" + sodipodi:ry="19.903" + style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:3.5;display:inline" /> + + + + + + + + + + diff --git a/activity/activity-websdk.svg b/activity/activity-websdk.svg deleted file mode 100644 index 15cd6cc..0000000 --- a/activity/activity-websdk.svg +++ /dev/null @@ -1,220 +0,0 @@ - - -]> -image/svg+xml - - - - - - - - - - - - - diff --git a/activity/activity.info b/activity/activity.info index d391415..4659d43 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -1,7 +1,7 @@ [Activity] -name = Construct -activity_version = 2 -bundle_id = org.sugarlabs.Construct +name = Hello Web World +activity_version = 1 +bundle_id = org.somosazucar.HelloWorldWeb exec = websdk-launcher -icon = activity-websdk +icon = activity-helloworld license = GPLv3+ diff --git a/app/app.py b/app/app.py index 40405cb..291b309 100644 --- a/app/app.py +++ b/app/app.py @@ -8,198 +8,26 @@ app.debug = True app.secret_key="ilovesugar" genshi = Genshi(app) +@app.route('/') +def hello_world(): + flash("Hello World") + return render_response('hello.html') + def shutdown_server(): func = request.environ.get('werkzeug.server.shutdown') if func is None: raise RuntimeError('Not running with the Werkzeug Server') func() -def list_files(directory): - files=os.listdir(directory) - print "showing %s" % directory - return sorted(files) - -def identify(filename): - if not os.path.exists(filename): - raise ValueError('File not found') - icon = 'document-generic.png' - mode = '' - directory=os.path.dirname(filename) - icon = 'document-generic.png' - href = '/edit/%s' % filename - if filename.endswith('.py'): - icon = 'text-x-python.png' - mode = 'python' - if filename.endswith('.html'): - icon = 'text-uri-list.png' - mode = 'html' - if filename.endswith('.css'): - icon = 'text-uri-list.png' - mode = 'css' - if filename.endswith('.js'): - icon = 'text-uri-list.png' - mode = 'javascript' - if os.path.isdir(filename): - icon = 'folder.png' - href = '/files/%s' % filename - mode = 'dir' - if filename.endswith('.xo'): - href = '#' - return icon,mode,href - -@app.route('/') -def index(): - try: - directory=session['pwd'] - except KeyError: - directory=u"" - return vsplit(frame2="/files/%s" % directory) - -@app.route('/edit/') -@app.route('/edit/') -def edit(filename): - try: - if len(session['edit_history'])==6: - session['edit_history'].pop(0) - if not filename in session['edit_history']: - session['edit_history'].append(filename) - except KeyError: - session['edit_history']=[filename,] - session.modified = True - icon, mode, href = identify(filename) - content = open(filename).read().decode('utf-8') - tmpl = 'editor.html' - directory=os.path.dirname(filename) - return render_response(tmpl, dict(content=content, icon=icon,basename=os.path.basename(filename), - filename=filename, absdir=os.path.normpath(directory), mode=mode, directory=directory)) - -@app.route('/save', methods=['POST']) -def save(): - filename = request.form['filename'] - f=open(filename,"wb") - content = request.form['content'] - # Ace seems to be confused about newlines - content = content.replace('\r\n', '\n').replace('\r', '\n') - f.write(content.encode('utf-8')) - print "saving content: %s" % filename - f.close() - directory = os.path.dirname(filename) - return "saved" - -@app.route('/chdir', methods=['POST']) -def chdir(): - if request.form['oldproject']!='': - session['project_dir']=os.getenv('HOME')+'/Activities/'+request.form['oldproject'] - with open(session['project_dir']+"/activity/activity.info", 'r') as f: - for line in f: - if line.startswith('name'): - session['project_name']=line[7:-1] - session['pwd']=session['project_home_dir']="." - os.chdir(session['project_dir']) - session['project_home']='/help' - #session['edit_history']=[] - if os.path.isdir('app'): - session['pwd']=session['project_home_dir']='app' - session['project_home']='/edit/app/app.py' - elif os.path.isfile('activity.py'): - session['project_home']='/edit/activity.py' - return vsplit(frame1=session['project_home'], - frame2='/files/%s' % session['pwd']) - -@app.route('/fileshome/') -def browse_home(): - try: - home_dir = session['project_home_dir'] - except KeyError: - home_dir = "." - return browse(home_dir) - -@app.route('/files/') -@app.route('/files/') -def browse(directory='.'): - session['pwd']=directory - - filelist = list_files(directory) - try: - session['project_dir'] - except KeyError: - filelist=[] - files = [] - if not os.path.abspath(directory)==os.path.abspath("."): - files.append( { 'name': '..', - 'icon': 'folder.png', - 'mode': 'dir', - 'href': '/files/%s' % os.path.join(directory,"..") }) - for filename in sorted(filelist): - icon, mode, href = identify(directory + "/" + filename) - if filename.startswith('.'): #hidden files - continue - if filename.endswith('.pyc'): #lets ignore these - continue - files.append( { 'name': filename, - 'icon': icon, - 'mode': mode, - 'href': href } ) - try: - project_name=session['project_name'] - except KeyError: - project_name='None'; - return render_response('filer.html', dict(files=files, - absdir=os.path.normpath(directory), - width=len(files)*94+10,# 94px is each file and 10px margin - project_name=project_name - )) - -@app.route('/delete/') -def delete(filename): - os.unlink(filename) - directory = os.path.dirname(filename) - return help() +@app.route('/debug') +def debug(): + raise Warning("This is a traceback of the Construct IDE environment. This is what you'll see when there's an error in your program or you manually raise an exception.") @app.route('/shutdown') def shutdown(): shutdown_server() return 'Goodbye' -@app.route('/help') -def help(): - port=request.environ.get('SERVER_PORT') - files=list_files(os.getenv('HOME')+'/Activities') - activities = [] - for file in files: - if file.endswith("activity"): - activities.append(file) - files = [] - try: - for filename in session['edit_history']: - icon, mode, href = identify(filename) - files.append( { 'name': os.path.basename(filename), - 'icon': icon, - 'mode': mode, - 'href': href } ) - except: - pass - try: - project_name=session['project_name'] - except KeyError: - project_name='None'; - - return render_response('help.html', dict(port=port, - activities=activities, - project_name=project_name, - edit_history=files)) - -def vsplit(frame1='/help', frame2='/files/'): - return render_response('split-view.html', dict(frame1=frame1, frame2=frame2)) - -@app.route('/split') -def split(): - return vsplit() - -@app.route('/debug') -def debug(): - raise Warning("This is a traceback of the Construct IDE environment. This is what you'll see when there's an error in your program or you manually raise an exception.") - if __name__=="__main__": try: port=int(sys.argv[1]) @@ -207,5 +35,5 @@ if __name__=="__main__": port=5000 import webbrowser webbrowser.open("http://localhost:%s/" % port) - #app.run(port=port) # for local only - app.run(host='0.0.0.0', port=port) # open for all + app.run(port=port) # for local only + #app.run(host='0.0.0.0', port=port) # open for all diff --git a/app/static/doc/flask-docs/.buildinfo b/app/static/doc/flask-docs/.buildinfo deleted file mode 100644 index ad0796f..0000000 --- a/app/static/doc/flask-docs/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 39b2407f81d28483972c20d3689be37c -tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/app/static/doc/flask-docs/_images/debugger.png b/app/static/doc/flask-docs/_images/debugger.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/debugger1.png b/app/static/doc/flask-docs/_images/debugger1.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger1.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/debugger2.png b/app/static/doc/flask-docs/_images/debugger2.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger2.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/debugger3.png b/app/static/doc/flask-docs/_images/debugger3.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger3.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/debugger4.png b/app/static/doc/flask-docs/_images/debugger4.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger4.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/debugger5.png b/app/static/doc/flask-docs/_images/debugger5.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_images/debugger5.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/flaskr.png b/app/static/doc/flask-docs/_images/flaskr.png deleted file mode 100644 index 07d027d..0000000 --- a/app/static/doc/flask-docs/_images/flaskr.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/logo-full.png b/app/static/doc/flask-docs/_images/logo-full.png deleted file mode 100644 index 5deaf1b..0000000 --- a/app/static/doc/flask-docs/_images/logo-full.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/logo-full1.png b/app/static/doc/flask-docs/_images/logo-full1.png deleted file mode 100644 index 5deaf1b..0000000 --- a/app/static/doc/flask-docs/_images/logo-full1.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/logo-full2.png b/app/static/doc/flask-docs/_images/logo-full2.png deleted file mode 100644 index 5deaf1b..0000000 --- a/app/static/doc/flask-docs/_images/logo-full2.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/no.png b/app/static/doc/flask-docs/_images/no.png deleted file mode 100644 index 4ac1083..0000000 --- a/app/static/doc/flask-docs/_images/no.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_images/yes.png b/app/static/doc/flask-docs/_images/yes.png deleted file mode 100644 index ac27c4e..0000000 --- a/app/static/doc/flask-docs/_images/yes.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_sources/api.txt b/app/static/doc/flask-docs/_sources/api.txt deleted file mode 100644 index 7695788..0000000 --- a/app/static/doc/flask-docs/_sources/api.txt +++ /dev/null @@ -1,624 +0,0 @@ -.. _api: - -API -=== - -.. module:: flask - -This part of the documentation covers all the interfaces of Flask. For -parts where Flask depends on external libraries, we document the most -important right here and provide links to the canonical documentation. - - -Application Object ------------------- - -.. autoclass:: Flask - :members: - :inherited-members: - - -Blueprint Objects ------------------ - -.. autoclass:: Blueprint - :members: - :inherited-members: - -Incoming Request Data ---------------------- - -.. autoclass:: Request - :members: - - .. attribute:: form - - A :class:`~werkzeug.datastructures.MultiDict` with the parsed form data from `POST` - or `PUT` requests. Please keep in mind that file uploads will not - end up here, but instead in the :attr:`files` attribute. - - .. attribute:: args - - A :class:`~werkzeug.datastructures.MultiDict` with the parsed contents of the query - string. (The part in the URL after the question mark). - - .. attribute:: values - - A :class:`~werkzeug.datastructures.CombinedMultiDict` with the contents of both - :attr:`form` and :attr:`args`. - - .. attribute:: cookies - - A :class:`dict` with the contents of all cookies transmitted with - the request. - - .. attribute:: stream - - If the incoming form data was not encoded with a known mimetype - the data is stored unmodified in this stream for consumption. Most - of the time it is a better idea to use :attr:`data` which will give - you that data as a string. The stream only returns the data once. - - .. attribute:: headers - - The incoming request headers as a dictionary like object. - - .. attribute:: data - - Contains the incoming request data as string in case it came with - a mimetype Flask does not handle. - - .. attribute:: files - - A :class:`~werkzeug.datastructures.MultiDict` with files uploaded as part of a - `POST` or `PUT` request. Each file is stored as - :class:`~werkzeug.datastructures.FileStorage` object. It basically behaves like a - standard file object you know from Python, with the difference that - it also has a :meth:`~werkzeug.datastructures.FileStorage.save` function that can - store the file on the filesystem. - - .. attribute:: environ - - The underlying WSGI environment. - - .. attribute:: method - - The current request method (``POST``, ``GET`` etc.) - - .. attribute:: path - .. attribute:: script_root - .. attribute:: url - .. attribute:: base_url - .. attribute:: url_root - - Provides different ways to look at the current URL. Imagine your - application is listening on the following URL:: - - http://www.example.com/myapplication - - And a user requests the following URL:: - - http://www.example.com/myapplication/page.html?x=y - - In this case the values of the above mentioned attributes would be - the following: - - ============= ====================================================== - `path` ``/page.html`` - `script_root` ``/myapplication`` - `base_url` ``http://www.example.com/myapplication/page.html`` - `url` ``http://www.example.com/myapplication/page.html?x=y`` - `url_root` ``http://www.example.com/myapplication/`` - ============= ====================================================== - - .. attribute:: is_xhr - - `True` if the request was triggered via a JavaScript - `XMLHttpRequest`. This only works with libraries that support the - ``X-Requested-With`` header and set it to `XMLHttpRequest`. - Libraries that do that are prototype, jQuery and Mochikit and - probably some more. - -.. class:: request - - To access incoming request data, you can use the global `request` - object. Flask parses incoming request data for you and gives you - access to it through that global object. Internally Flask makes - sure that you always get the correct data for the active thread if you - are in a multithreaded environment. - - This is a proxy. See :ref:`notes-on-proxies` for more information. - - The request object is an instance of a :class:`~werkzeug.wrappers.Request` - subclass and provides all of the attributes Werkzeug defines. This - just shows a quick overview of the most important ones. - - -Response Objects ----------------- - -.. autoclass:: flask.Response - :members: set_cookie, data, mimetype - - .. attribute:: headers - - A :class:`Headers` object representing the response headers. - - .. attribute:: status_code - - The response status as integer. - - -Sessions --------- - -If you have the :attr:`Flask.secret_key` set you can use sessions in Flask -applications. A session basically makes it possible to remember -information from one request to another. The way Flask does this is by -using a signed cookie. So the user can look at the session contents, but -not modify it unless they know the secret key, so make sure to set that -to something complex and unguessable. - -To access the current session you can use the :class:`session` object: - -.. class:: session - - The session object works pretty much like an ordinary dict, with the - difference that it keeps track on modifications. - - This is a proxy. See :ref:`notes-on-proxies` for more information. - - The following attributes are interesting: - - .. attribute:: new - - `True` if the session is new, `False` otherwise. - - .. attribute:: modified - - `True` if the session object detected a modification. Be advised - that modifications on mutable structures are not picked up - automatically, in that situation you have to explicitly set the - attribute to `True` yourself. Here an example:: - - # this change is not picked up because a mutable object (here - # a list) is changed. - session['objects'].append(42) - # so mark it as modified yourself - session.modified = True - - .. attribute:: permanent - - If set to `True` the session lives for - :attr:`~flask.Flask.permanent_session_lifetime` seconds. The - default is 31 days. If set to `False` (which is the default) the - session will be deleted when the user closes the browser. - - -Session Interface ------------------ - -.. versionadded:: 0.8 - -The session interface provides a simple way to replace the session -implementation that Flask is using. - -.. currentmodule:: flask.sessions - -.. autoclass:: SessionInterface - :members: - -.. autoclass:: SecureCookieSessionInterface - :members: - -.. autoclass:: NullSession - :members: - -.. autoclass:: SessionMixin - :members: - -.. admonition:: Notice - - The ``PERMANENT_SESSION_LIFETIME`` config key can also be an integer - starting with Flask 0.8. Either catch this down yourself or use - the :attr:`~flask.Flask.permanent_session_lifetime` attribute on the - app which converts the result to an integer automatically. - - -Test Client ------------ - -.. currentmodule:: flask.testing - -.. autoclass:: FlaskClient - :members: - - -Application Globals -------------------- - -.. currentmodule:: flask - -To share data that is valid for one request only from one function to -another, a global variable is not good enough because it would break in -threaded environments. Flask provides you with a special object that -ensures it is only valid for the active request and that will return -different values for each request. In a nutshell: it does the right -thing, like it does for :class:`request` and :class:`session`. - -.. data:: g - - Just store on this whatever you want. For example a database - connection or the user that is currently logged in. - - This is a proxy. See :ref:`notes-on-proxies` for more information. - - -Useful Functions and Classes ----------------------------- - -.. data:: current_app - - Points to the application handling the request. This is useful for - extensions that want to support multiple applications running side - by side. - - This is a proxy. See :ref:`notes-on-proxies` for more information. - -.. autofunction:: has_request_context - -.. autofunction:: url_for - -.. function:: abort(code) - - Raises an :exc:`~werkzeug.exceptions.HTTPException` for the given - status code. For example to abort request handling with a page not - found exception, you would call ``abort(404)``. - - :param code: the HTTP error code. - -.. autofunction:: redirect - -.. autofunction:: make_response - -.. autofunction:: send_file - -.. autofunction:: send_from_directory - -.. autofunction:: safe_join - -.. autofunction:: escape - -.. autoclass:: Markup - :members: escape, unescape, striptags - -Message Flashing ----------------- - -.. autofunction:: flash - -.. autofunction:: get_flashed_messages - -Returning JSON --------------- - -.. autofunction:: jsonify - -.. data:: json - - If JSON support is picked up, this will be the module that Flask is - using to parse and serialize JSON. So instead of doing this yourself:: - - try: - import simplejson as json - except ImportError: - import json - - You can instead just do this:: - - from flask import json - - For usage examples, read the :mod:`json` documentation. - - The :func:`~json.dumps` function of this json module is also available - as filter called ``|tojson`` in Jinja2. Note that inside `script` - tags no escaping must take place, so make sure to disable escaping - with ``|safe`` if you intend to use it inside `script` tags: - - .. sourcecode:: html+jinja - - - - Note that the ``|tojson`` filter escapes forward slashes properly. - -Template Rendering ------------------- - -.. autofunction:: render_template - -.. autofunction:: render_template_string - -.. autofunction:: get_template_attribute - -Configuration -------------- - -.. autoclass:: Config - :members: - -Extensions ----------- - -.. data:: flask.ext - - This module acts as redirect import module to Flask extensions. It was - added in 0.8 as the canonical way to import Flask extensions and makes - it possible for us to have more flexibility in how we distribute - extensions. - - If you want to use an extension named “Flask-Foo” you would import it - from :data:`~flask.ext` as follows:: - - from flask.ext import foo - - .. versionadded:: 0.8 - -Useful Internals ----------------- - -.. autoclass:: flask.ctx.RequestContext - :members: - -.. data:: _request_ctx_stack - - The internal :class:`~werkzeug.local.LocalStack` that is used to implement - all the context local objects used in Flask. This is a documented - instance and can be used by extensions and application code but the - use is discouraged in general. - - The following attributes are always present on each layer of the - stack: - - `app` - the active Flask application. - - `url_adapter` - the URL adapter that was used to match the request. - - `request` - the current request object. - - `session` - the active session object. - - `g` - an object with all the attributes of the :data:`flask.g` object. - - `flashes` - an internal cache for the flashed messages. - - Example usage:: - - from flask import _request_ctx_stack - - def get_session(): - ctx = _request_ctx_stack.top - if ctx is not None: - return ctx.session - -.. autoclass:: flask.blueprints.BlueprintSetupState - :members: - -Signals -------- - -.. when modifying this list, also update the one in signals.rst - -.. versionadded:: 0.6 - -.. data:: signals_available - - `True` if the signalling system is available. This is the case - when `blinker`_ is installed. - -.. data:: template_rendered - - This signal is sent when a template was successfully rendered. The - signal is invoked with the instance of the template as `template` - and the context as dictionary (named `context`). - -.. data:: request_started - - This signal is sent before any request processing started but when the - request context was set up. Because the request context is already - bound, the subscriber can access the request with the standard global - proxies such as :class:`~flask.request`. - -.. data:: request_finished - - This signal is sent right before the response is sent to the client. - It is passed the response to be sent named `response`. - -.. data:: got_request_exception - - This signal is sent when an exception happens during request processing. - It is sent *before* the standard exception handling kicks in and even - in debug mode, where no exception handling happens. The exception - itself is passed to the subscriber as `exception`. - -.. data:: request_tearing_down - - This signal is sent when the application is tearing down the request. - This is always called, even if an error happened. No arguments are - provided. - -.. currentmodule:: None - -.. class:: flask.signals.Namespace - - An alias for :class:`blinker.base.Namespace` if blinker is available, - otherwise a dummy class that creates fake signals. This class is - available for Flask extensions that want to provide the same fallback - system as Flask itself. - - .. method:: signal(name, doc=None) - - Creates a new signal for this namespace if blinker is available, - otherwise returns a fake signal that has a send method that will - do nothing but will fail with a :exc:`RuntimeError` for all other - operations, including connecting. - -.. _blinker: http://pypi.python.org/pypi/blinker - -Class Based Views ------------------ - -.. versionadded:: 0.7 - -.. currentmodule:: None - -.. autoclass:: flask.views.View - :members: - -.. autoclass:: flask.views.MethodView - :members: - -.. _url-route-registrations: - -URL Route Registrations ------------------------ - -Generally there are three ways to define rules for the routing system: - -1. You can use the :meth:`flask.Flask.route` decorator. -2. You can use the :meth:`flask.Flask.add_url_rule` function. -3. You can directly access the underlying Werkzeug routing system - which is exposed as :attr:`flask.Flask.url_map`. - -Variable parts in the route can be specified with angular brackets -(``/user/``). By default a variable part in the URL accepts any -string without a slash however a different converter can be specified as -well by using ````. - -Variable parts are passed to the view function as keyword arguments. - -The following converters are available: - -=========== =============================================== -`unicode` accepts any text without a slash (the default) -`int` accepts integers -`float` like `int` but for floating point values -`path` like the default but also accepts slashes -=========== =============================================== - -Here are some examples:: - - @app.route('/') - def index(): - pass - - @app.route('/') - def show_user(username): - pass - - @app.route('/post/') - def show_post(post_id): - pass - -An important detail to keep in mind is how Flask deals with trailing -slashes. The idea is to keep each URL unique so the following rules -apply: - -1. If a rule ends with a slash and is requested without a slash by the - user, the user is automatically redirected to the same page with a - trailing slash attached. -2. If a rule does not end with a trailing slash and the user requests the - page with a trailing slash, a 404 not found is raised. - -This is consistent with how web servers deal with static files. This -also makes it possible to use relative link targets safely. - -You can also define multiple rules for the same function. They have to be -unique however. Defaults can also be specified. Here for example is a -definition for a URL that accepts an optional page:: - - @app.route('/users/', defaults={'page': 1}) - @app.route('/users/page/') - def show_users(page): - pass - -This specifies that ``/users/`` will be the URL for page one and -``/users/page/N`` will be the URL for page `N`. - -Here are the parameters that :meth:`~flask.Flask.route` and -:meth:`~flask.Flask.add_url_rule` accept. The only difference is that -with the route parameter the view function is defined with the decorator -instead of the `view_func` parameter. - -=============== ========================================================== -`rule` the URL roule as string -`endpoint` the endpoint for the registered URL rule. Flask itself - assumes that the name of the view function is the name - of the endpoint if not explicitly stated. -`view_func` the function to call when serving a request to the - provided endpoint. If this is not provided one can - specify the function later by storing it in the - :attr:`~flask.Flask.view_functions` dictionary with the - endpoint as key. -`defaults` A dictionary with defaults for this rule. See the - example above for how defaults work. -`subdomain` specifies the rule for the subdomain in case subdomain - matching is in use. If not specified the default - subdomain is assumed. -`**options` the options to be forwarded to the underlying - :class:`~werkzeug.routing.Rule` object. A change to - Werkzeug is handling of method options. methods is a list - of methods this rule should be limited to (`GET`, `POST` - etc.). By default a rule just listens for `GET` (and - implicitly `HEAD`). Starting with Flask 0.6, `OPTIONS` is - implicitly added and handled by the standard request - handling. They have to be specified as keyword arguments. -=============== ========================================================== - -.. _view-func-options: - -View Function Options ---------------------- - -For internal usage the view functions can have some attributes attached to -customize behavior the view function would normally not have control over. -The following attributes can be provided optionally to either override -some defaults to :meth:`~flask.Flask.add_url_rule` or general behavior: - -- `__name__`: The name of a function is by default used as endpoint. If - endpoint is provided explicitly this value is used. Additionally this - will be prefixed with the name of the blueprint by default which - cannot be customized from the function itself. - -- `methods`: If methods are not provided when the URL rule is added, - Flask will look on the view function object itself is an `methods` - attribute exists. If it does, it will pull the information for the - methods from there. - -- `provide_automatic_options`: if this attribute is set Flask will - either force enable or disable the automatic implementation of the - HTTP `OPTIONS` response. This can be useful when working with - decorators that want to customize the `OPTIONS` response on a per-view - basis. - -Full example:: - - def index(): - if request.method == 'OPTIONS': - # custom options handling here - ... - return 'Hello World!' - index.provide_automatic_options = False - index.methods = ['GET', 'OPTIONS'] - - app.add_url_rule('/', index) - -.. versionadded:: 0.8 - The `provide_automatic_options` functionality was added. diff --git a/app/static/doc/flask-docs/_sources/becomingbig.txt b/app/static/doc/flask-docs/_sources/becomingbig.txt deleted file mode 100644 index 20a0186..0000000 --- a/app/static/doc/flask-docs/_sources/becomingbig.txt +++ /dev/null @@ -1,88 +0,0 @@ -.. _becomingbig: - -Becoming Big -============ - -Your application is becoming more and more complex? If you suddenly -realize that Flask does things in a way that does not work out for your -application there are ways to deal with that. - -Flask is powered by Werkzeug and Jinja2, two libraries that are in use at -a number of large websites out there and all Flask does is bring those -two together. Being a microframework Flask does not do much more than -combining existing libraries - there is not a lot of code involved. -What that means for large applications is that it's very easy to take the -code from Flask and put it into a new module within the applications and -expand on that. - -Flask is designed to be extended and modified in a couple of different -ways: - -- Flask extensions. For a lot of reusable functionality you can create - extensions. For extensions a number of hooks exist throughout Flask - with signals and callback functions. - -- Subclassing. The majority of functionality can be changed by creating - a new subclass of the :class:`~flask.Flask` class and overriding - methods provided for this exact purpose. - -- Forking. If nothing else works out you can just take the Flask - codebase at a given point and copy/paste it into your application - and change it. Flask is designed with that in mind and makes this - incredible easy. You just have to take the package and copy it - into your application's code and rename it (for example to - `framework`). Then you can start modifying the code in there. - -Why consider Forking? ---------------------- - -The majority of code of Flask is within Werkzeug and Jinja2. These -libraries do the majority of the work. Flask is just the paste that glues -those together. For every project there is the point where the underlying -framework gets in the way (due to assumptions the original developers -had). This is natural because if this would not be the case, the -framework would be a very complex system to begin with which causes a -steep learning curve and a lot of user frustration. - -This is not unique to Flask. Many people use patched and modified -versions of their framework to counter shortcomings. This idea is also -reflected in the license of Flask. You don't have to contribute any -changes back if you decide to modify the framework. - -The downside of forking is of course that Flask extensions will most -likely break because the new framework has a different import name. -Furthermore integrating upstream changes can be a complex process, -depending on the number of changes. Because of that, forking should be -the very last resort. - -Scaling like a Pro ------------------- - -For many web applications the complexity of the code is less an issue than -the scaling for the number of users or data entries expected. Flask by -itself is only limited in terms of scaling by your application code, the -data store you want to use and the Python implementation and webserver you -are running on. - -Scaling well means for example that if you double the amount of servers -you get about twice the performance. Scaling bad means that if you add a -new server the application won't perform any better or would not even -support a second server. - -There is only one limiting factor regarding scaling in Flask which are -the context local proxies. They depend on context which in Flask is -defined as being either a thread, process or greenlet. If your server -uses some kind of concurrency that is not based on threads or greenlets, -Flask will no longer be able to support these global proxies. However the -majority of servers are using either threads, greenlets or separate -processes to achieve concurrency which are all methods well supported by -the underlying Werkzeug library. - -Dialogue with the Community ---------------------------- - -The Flask developers are very interested to keep everybody happy, so as -soon as you find an obstacle in your way, caused by Flask, don't hesitate -to contact the developers on the mailinglist or IRC channel. The best way -for the Flask and Flask-extension developers to improve it for larger -applications is getting feedback from users. diff --git a/app/static/doc/flask-docs/_sources/blueprints.txt b/app/static/doc/flask-docs/_sources/blueprints.txt deleted file mode 100644 index 9422fd0..0000000 --- a/app/static/doc/flask-docs/_sources/blueprints.txt +++ /dev/null @@ -1,203 +0,0 @@ -.. _blueprints: - -Modular Applications with Blueprints -==================================== - -.. versionadded:: 0.7 - -Flask uses a concept of *blueprints* for making application components and -supporting common patterns within an application or across applications. -Blueprints can greatly simplify how large applications work and provide a -central means for Flask extensions to register operations on applications. -A :class:`Blueprint` object works similarly to a :class:`Flask` -application object, but it is not actually an application. Rather it is a -*blueprint* of how to construct or extend an application. - -Why Blueprints? ---------------- - -Blueprints in Flask are intended for these cases: - -* Factor an application into a set of blueprints. This is ideal for - larger applications; a project could instantiate an application object, - initialize several extensions, and register a collection of blueprints. -* Register a blueprint on an application at a URL prefix and/or subdomain. - Parameters in the URL prefix/subdomain become common view arguments - (with defaults) across all view functions in the blueprint. -* Register a blueprint multiple times on an application with different URL - rules. -* Provide template filters, static files, templates, and other utilities - through blueprints. A blueprint does not have to implement applications - or view functions. -* Register a blueprint on an application for any of these cases when - initializing a Flask extension. - -A blueprint in Flask is not a pluggable app because it is not actually an -application -- it's a set of operations which can be registered on an -application, even multiple times. Why not have multiple application -objects? You can do that (see :ref:`app-dispatch`), but your applications -will have separate configs and will be managed at the WSGI layer. - -Blueprints instead provide separation at the Flask level, share -application config, and can change an application object as necessary with -being registered. The downside is that you cannot unregister a blueprint -once an application was created without having to destroy the whole -application object. - -The Concept of Blueprints -------------------------- - -The basic concept of blueprints is that they record operations to execute -when registered on an application. Flask associates view functions with -blueprints when dispatching requests and generating URLs from one endpoint -to another. - -My First Blueprint ------------------- - -This is what a very basic blueprint looks like. In this case we want to -implement a blueprint that does simple rendering of static templates:: - - from flask import Blueprint, render_template, abort - from jinja2 import TemplateNotFound - - simple_page = Blueprint('simple_page', __name__) - - @simple_page.route('/', defaults={'page': 'index'}) - @simple_page.route('/') - def show(page): - try: - return render_template('pages/%s.html' % page) - except TemplateNotFound: - abort(404) - -When you bind a function with the help of the ``@simple_page.route`` -decorator the blueprint will record the intention of registering the -function `show` on the application when it's later registered. -Additionally it will prefix the endpoint of the function with the -name of the blueprint which was given to the :class:`Blueprint` -constructor (in this case also ``simple_page``). - -Registering Blueprints ----------------------- - -So how do you register that blueprint? Like this:: - - from flask import Flask - from yourapplication.simple_page import simple_page - - app = Flask(__name__) - app.register_blueprint(simple_page) - -If you check the rules registered on the application, you will find -these:: - - [' (HEAD, OPTIONS, GET) -> static>, - ' (HEAD, OPTIONS, GET) -> simple_page.show>, - simple_page.show>] - -The first one is obviously from the application ifself for the static -files. The other two are for the `show` function of the ``simple_page`` -blueprint. As you can see, they are also prefixed with the name of the -blueprint and separated by a dot (``.``). - -Blueprints however can also be mounted at different locations:: - - app.register_blueprint(simple_page, url_prefix='/pages') - -And sure enough, these are the generated rules:: - - [' (HEAD, OPTIONS, GET) -> static>, - ' (HEAD, OPTIONS, GET) -> simple_page.show>, - simple_page.show>] - -On top of that you can register blueprints multiple times though not every -blueprint might respond properly to that. In fact it depends on how the -blueprint is implemented if it can be mounted more than once. - -Blueprint Resources -------------------- - -Blueprints can provide resources as well. Sometimes you might want to -introduce a blueprint only for the resources it provides. - -Blueprint Resource Folder -````````````````````````` - -Like for regular applications, blueprints are considered to be contained -in a folder. While multiple blueprints can originate from the same folder, -it does not have to be the case and it's usually not recommended. - -The folder is inferred from the second argument to :class:`Blueprint` which -is usually `__name__`. This argument specifies what logical Python -module or package corresponds to the blueprint. If it points to an actual -Python package that package (which is a folder on the filesystem) is the -resource folder. If it's a module, the package the module is contained in -will be the resource folder. You can access the -:attr:`Blueprint.root_path` property to see what the resource folder is:: - - >>> simple_page.root_path - '/Users/username/TestProject/yourapplication' - -To quickly open sources from this folder you can use the -:meth:`~Blueprint.open_resource` function:: - - with simple_page.open_resource('static/style.css') as f: - code = f.read() - -Static Files -```````````` - -A blueprint can expose a folder with static files by providing a path to a -folder on the filesystem via the `static_folder` keyword argument. It can -either be an absolute path or one relative to the folder of the -blueprint:: - - admin = Blueprint('admin', __name__, static_folder='static') - -By default the rightmost part of the path is where it is exposed on the -web. Because the folder is called ``static`` here it will be available at -the location of the blueprint + ``/static``. Say the blueprint is -registered for ``/admin`` the static folder will be at ``/admin/static``. - -The endpoint is named `blueprint_name.static` so you can generate URLs to -it like you would do to the static folder of the application:: - - url_for('admin.static', filename='style.css') - -Templates -````````` - -If you want the blueprint to expose templates you can do that by providing -the `template_folder` parameter to the :class:`Blueprint` constructor:: - - admin = Blueprint('admin', __name__, template_folder='templates') - -As for static files, the path can be absolute or relative to the blueprint -resource folder. The template folder is added to the searchpath of -templates but with a lower priority than the actual application's template -folder. That way you can easily override templates that a blueprint -provides in the actual application. - -So if you have a blueprint in the folder ``yourapplication/admin`` and you -want to render the template ``'admin/index.html'`` and you have provided -``templates`` as a `template_folder` you will have to create a file like -this: ``yourapplication/admin/templates/admin/index.html``. - -Building URLs -------------- - -If you want to link from one page to another you can use the -:func:`url_for` function just like you normally would do just that you -prefix the URL endpoint with the name of the blueprint and a dot (``.``):: - - url_for('admin.index') - -Additionally if you are in a view function of a blueprint or a rendered -template and you want to link to another endpoint of the same blueprint, -you can use relative redirects by prefixing the endpoint with a dot only:: - - url_for('.index') - -This will link to ``admin.index`` for instance in case the current request -was dispatched to any other admin blueprint endpoint. diff --git a/app/static/doc/flask-docs/_sources/changelog.txt b/app/static/doc/flask-docs/_sources/changelog.txt deleted file mode 100644 index d6c5f48..0000000 --- a/app/static/doc/flask-docs/_sources/changelog.txt +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../CHANGES diff --git a/app/static/doc/flask-docs/_sources/config.txt b/app/static/doc/flask-docs/_sources/config.txt deleted file mode 100644 index ca724dc..0000000 --- a/app/static/doc/flask-docs/_sources/config.txt +++ /dev/null @@ -1,384 +0,0 @@ -.. _config: - -Configuration Handling -====================== - -.. versionadded:: 0.3 - -Applications need some kind of configuration. There are different settings -you might want to change depending on the application environment like -toggling the debug mode, setting the secret key, and other such -environment-specific things. - -The way Flask is designed usually requires the configuration to be -available when the application starts up. You can hardcode the -configuration in the code, which for many small applications is not -actually that bad, but there are better ways. - -Independent of how you load your config, there is a config object -available which holds the loaded configuration values: -The :attr:`~flask.Flask.config` attribute of the :class:`~flask.Flask` -object. This is the place where Flask itself puts certain configuration -values and also where extensions can put their configuration values. But -this is also where you can have your own configuration. - -Configuration Basics --------------------- - -The :attr:`~flask.Flask.config` is actually a subclass of a dictionary and -can be modified just like any dictionary:: - - app = Flask(__name__) - app.config['DEBUG'] = True - -Certain configuration values are also forwarded to the -:attr:`~flask.Flask` object so you can read and write them from there:: - - app.debug = True - -To update multiple keys at once you can use the :meth:`dict.update` -method:: - - app.config.update( - DEBUG=True, - SECRET_KEY='...' - ) - -Builtin Configuration Values ----------------------------- - -The following configuration values are used internally by Flask: - -.. tabularcolumns:: |p{6.5cm}|p{8.5cm}| - -================================= ========================================= -``DEBUG`` enable/disable debug mode -``TESTING`` enable/disable testing mode -``PROPAGATE_EXCEPTIONS`` explicitly enable or disable the - propagation of exceptions. If not set or - explicitly set to `None` this is - implicitly true if either `TESTING` or - `DEBUG` is true. -``PRESERVE_CONTEXT_ON_EXCEPTION`` By default if the application is in - debug mode the request context is not - popped on exceptions to enable debuggers - to introspect the data. This can be - disabled by this key. You can also use - this setting to force-enable it for non - debug execution which might be useful to - debug production applications (but also - very risky). -``SECRET_KEY`` the secret key -``SESSION_COOKIE_NAME`` the name of the session cookie -``SESSION_COOKIE_DOMAIN`` the domain for the session cookie. If - this is not set, the cookie will be - valid for all subdomains of - ``SERVER_NAME``. -``SESSION_COOKIE_PATH`` the path for the session cookie. If - this is not set the cookie will be valid - for all of ``APPLICATION_ROOT`` or if - that is not set for ``'/'``. -``SESSION_COOKIE_HTTPONLY`` controls if the cookie should be set - with the httponly flag. Defaults to - `True`. -``SESSION_COOKIE_SECURE`` controls if the cookie should be set - with the secure flag. Defaults to - `False`. -``PERMANENT_SESSION_LIFETIME`` the lifetime of a permanent session as - :class:`datetime.timedelta` object. - Starting with Flask 0.8 this can also be - an integer representing seconds. -``USE_X_SENDFILE`` enable/disable x-sendfile -``LOGGER_NAME`` the name of the logger -``SERVER_NAME`` the name and port number of the server. - Required for subdomain support (e.g.: - ``'myapp.dev:5000'``) Note that - localhost does not support subdomains so - setting this to “localhost” does not - help. -``APPLICATION_ROOT`` If the application does not occupy - a whole domain or subdomain this can - be set to the path where the application - is configured to live. This is for - session cookie as path value. If - domains are used, this should be - ``None``. -``MAX_CONTENT_LENGTH`` If set to a value in bytes, Flask will - reject incoming requests with a - content length greater than this by - returning a 413 status code. -``TRAP_HTTP_EXCEPTIONS`` If this is set to ``True`` Flask will - not execute the error handlers of HTTP - exceptions but instead treat the - exception like any other and bubble it - through the exception stack. This is - helpful for hairy debugging situations - where you have to find out where an HTTP - exception is coming from. -``TRAP_BAD_REQUEST_ERRORS`` Werkzeug's internal data structures that - deal with request specific data will - raise special key errors that are also - bad request exceptions. Likewise many - operations can implicitly fail with a - BadRequest exception for consistency. - Since it's nice for debugging to know - why exactly it failed this flag can be - used to debug those situations. If this - config is set to ``True`` you will get - a regular traceback instead. -================================= ========================================= - -.. admonition:: More on ``SERVER_NAME`` - - The ``SERVER_NAME`` key is used for the subdomain support. Because - Flask cannot guess the subdomain part without the knowledge of the - actual server name, this is required if you want to work with - subdomains. This is also used for the session cookie. - - Please keep in mind that not only Flask has the problem of not knowing - what subdomains are, your web browser does as well. Most modern web - browsers will not allow cross-subdomain cookies to be set on a - server name without dots in it. So if your server name is - ``'localhost'`` you will not be able to set a cookie for - ``'localhost'`` and every subdomain of it. Please chose a different - server name in that case, like ``'myapplication.local'`` and add - this name + the subdomains you want to use into your host config - or setup a local `bind`_. - -.. _bind: https://www.isc.org/software/bind - -.. versionadded:: 0.4 - ``LOGGER_NAME`` - -.. versionadded:: 0.5 - ``SERVER_NAME`` - -.. versionadded:: 0.6 - ``MAX_CONTENT_LENGTH`` - -.. versionadded:: 0.7 - ``PROPAGATE_EXCEPTIONS``, ``PRESERVE_CONTEXT_ON_EXCEPTION`` - -.. versionadded:: 0.8 - ``TRAP_BAD_REQUEST_ERRORS``, ``TRAP_HTTP_EXCEPTIONS``, - ``APPLICATION_ROOT``, ``SESSION_COOKIE_DOMAIN``, - ``SESSION_COOKIE_PATH``, ``SESSION_COOKIE_HTTPONLY``, - ``SESSION_COOKIE_SECURE`` - -Configuring from Files ----------------------- - -Configuration becomes more useful if you can store it in a separate file, -ideally located outside the actual application package. This makes -packaging and distributing your application possible via various package -handling tools (:ref:`distribute-deployment`) and finally modifying the -configuration file afterwards. - -So a common pattern is this:: - - app = Flask(__name__) - app.config.from_object('yourapplication.default_settings') - app.config.from_envvar('YOURAPPLICATION_SETTINGS') - -This first loads the configuration from the -`yourapplication.default_settings` module and then overrides the values -with the contents of the file the :envvar:`YOURAPPLICATION_SETTINGS` -environment variable points to. This environment variable can be set on -Linux or OS X with the export command in the shell before starting the -server:: - - $ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg - $ python run-app.py - * Running on http://127.0.0.1:5000/ - * Restarting with reloader... - -On Windows systems use the `set` builtin instead:: - - >set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg - -The configuration files themselves are actual Python files. Only values -in uppercase are actually stored in the config object later on. So make -sure to use uppercase letters for your config keys. - -Here is an example of a configuration file:: - - # Example configuration - DEBUG = False - SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' - -Make sure to load the configuration very early on, so that extensions have -the ability to access the configuration when starting up. There are other -methods on the config object as well to load from individual files. For a -complete reference, read the :class:`~flask.Config` object's -documentation. - - -Configuration Best Practices ----------------------------- - -The downside with the approach mentioned earlier is that it makes testing -a little harder. There is no single 100% solution for this problem in -general, but there are a couple of things you can keep in mind to improve -that experience: - -1. create your application in a function and register blueprints on it. - That way you can create multiple instances of your application with - different configurations attached which makes unittesting a lot - easier. You can use this to pass in configuration as needed. - -2. Do not write code that needs the configuration at import time. If you - limit yourself to request-only accesses to the configuration you can - reconfigure the object later on as needed. - - -Development / Production ------------------------- - -Most applications need more than one configuration. There should be at -least separate configurations for the production server and the one used -during development. The easiest way to handle this is to use a default -configuration that is always loaded and part of the version control, and a -separate configuration that overrides the values as necessary as mentioned -in the example above:: - - app = Flask(__name__) - app.config.from_object('yourapplication.default_settings') - app.config.from_envvar('YOURAPPLICATION_SETTINGS') - -Then you just have to add a separate `config.py` file and export -``YOURAPPLICATION_SETTINGS=/path/to/config.py`` and you are done. However -there are alternative ways as well. For example you could use imports or -subclassing. - -What is very popular in the Django world is to make the import explicit in -the config file by adding an ``from yourapplication.default_settings -import *`` to the top of the file and then overriding the changes by hand. -You could also inspect an environment variable like -``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc -and import different hardcoded files based on that. - -An interesting pattern is also to use classes and inheritance for -configuration:: - - class Config(object): - DEBUG = False - TESTING = False - DATABASE_URI = 'sqlite://:memory:' - - class ProductionConfig(Config): - DATABASE_URI = 'mysql://user@localhost/foo' - - class DevelopmentConfig(Config): - DEBUG = True - - class TestingConfig(Config): - TESTING = True - -To enable such a config you just have to call into -:meth:`~flask.Config.from_object`:: - - app.config.from_object('configmodule.ProductionConfig') - -There are many different ways and it's up to you how you want to manage -your configuration files. However here a list of good recommendations: - -- keep a default configuration in version control. Either populate the - config with this default configuration or import it in your own - configuration files before overriding values. -- use an environment variable to switch between the configurations. - This can be done from outside the Python interpreter and makes - development and deployment much easier because you can quickly and - easily switch between different configs without having to touch the - code at all. If you are working often on different projects you can - even create your own script for sourcing that activates a virtualenv - and exports the development configuration for you. -- Use a tool like `fabric`_ in production to push code and - configurations separately to the production server(s). For some - details about how to do that, head over to the - :ref:`fabric-deployment` pattern. - -.. _fabric: http://fabfile.org/ - - -.. _instance-folders: - -Instance Folders ----------------- - -.. versionadded:: 0.8 - -Flask 0.8 introduces instance folders. Flask for a long time made it -possible to refer to paths relative to the application's folder directly -(via :attr:`Flask.root_path`). This was also how many developers loaded -configurations stored next to the application. Unfortunately however this -only works well if applications are not packages in which case the root -path refers to the contents of the package. - -With Flask 0.8 a new attribute was introduced: -:attr:`Flask.instance_path`. It refers to a new concept called the -“instance folder”. The instance folder is designed to not be under -version control and be deployment specific. It's the perfect place to -drop things that either change at runtime or configuration files. - -You can either explicitly provide the path of the instance folder when -creating the Flask application or you can let Flask autodetect the -instance folder. For explicit configuration use the `instance_path` -parameter:: - - app = Flask(__name__, instance_path='/path/to/instance/folder') - -Please keep in mind that this path *must* be absolute when provided. - -If the `instance_path` parameter is not provided the following default -locations are used: - -- Uninstalled module:: - - /myapp.py - /instance - -- Uninstalled package:: - - /myapp - /__init__.py - /instance - -- Installed module or package:: - - $PREFIX/lib/python2.X/site-packages/myapp - $PREFIX/var/myapp-instance - - ``$PREFIX`` is the prefix of your Python installation. This can be - ``/usr`` or the path to your virtualenv. You can print the value of - ``sys.prefix`` to see what the prefix is set to. - -Since the config object provided loading of configuration files from -relative filenames we made it possible to change the loading via filenames -to be relative to the instance path if wanted. The behavior of relative -paths in config files can be flipped between “relative to the application -root” (the default) to “relative to instance folder” via the -`instance_relative_config` switch to the application constructor:: - - app = Flask(__name__, instance_relative_config=True) - -Here is a full example of how to configure Flask to preload the config -from a module and then override the config from a file in the config -folder if it exists:: - - app = Flask(__name__, instance_relative_config=True) - app.config.from_object('yourapplication.default_settings') - app.config.from_pyfile('application.cfg', silent=True) - -The path to the instance folder can be found via the -:attr:`Flask.instance_path`. Flask also provides a shortcut to open a -file from the instance folder with :meth:`Flask.open_instance_resource`. - -Example usage for both:: - - filename = os.path.join(app.instance_root, 'application.cfg') - with open(filename) as f: - config = f.read() - - # or via open_instance_resource: - with app.open_instance_resource('application.cfg') as f: - config = f.read() diff --git a/app/static/doc/flask-docs/_sources/deploying/cgi.txt b/app/static/doc/flask-docs/_sources/deploying/cgi.txt deleted file mode 100644 index a2fba90..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/cgi.txt +++ /dev/null @@ -1,46 +0,0 @@ -CGI -=== - -If all other deployment methods do not work, CGI will work for sure. -CGI is supported by all major servers but usually has a sub-optimal -performance. - -This is also the way you can use a Flask application on Google's `App -Engine`_, where execution happens in a CGI-like environment. - -.. admonition:: Watch Out - - Please make sure in advance that any ``app.run()`` calls you might - have in your application file are inside an ``if __name__ == - '__main__':`` block or moved to a separate file. Just make sure it's - not called because this will always start a local WSGI server which - we do not want if we deploy that application to CGI / app engine. - -Creating a `.cgi` file ----------------------- - -First you need to create the CGI application file. Let's call it -`yourapplication.cgi`:: - - #!/usr/bin/python - from wsgiref.handlers import CGIHandler - from yourapplication import app - - CGIHandler().run(app) - -Server Setup ------------- - -Usually there are two ways to configure the server. Either just copy the -`.cgi` into a `cgi-bin` (and use `mod_rewrite` or something similar to -rewrite the URL) or let the server point to the file directly. - -In Apache for example you can put a like like this into the config: - -.. sourcecode:: apache - - ScriptAlias /app /path/to/the/application.cgi - -For more information consult the documentation of your webserver. - -.. _App Engine: http://code.google.com/appengine/ diff --git a/app/static/doc/flask-docs/_sources/deploying/fastcgi.txt b/app/static/doc/flask-docs/_sources/deploying/fastcgi.txt deleted file mode 100644 index 6dace1a..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/fastcgi.txt +++ /dev/null @@ -1,164 +0,0 @@ -.. _deploying-fastcgi: - -FastCGI -======= - -FastCGI is a deployment option on servers like `nginx`_, `lighttpd`_, -and `cherokee`_; see :ref:`deploying-uwsgi` and -:ref:`deploying-other-servers` for other options. To use your WSGI -application with any of them you will need a FastCGI server first. The -most popular one is `flup`_ which we will use for this guide. Make sure -to have it installed to follow along. - -.. admonition:: Watch Out - - Please make sure in advance that any ``app.run()`` calls you might - have in your application file are inside an ``if __name__ == - '__main__':`` block or moved to a separate file. Just make sure it's - not called because this will always start a local WSGI server which - we do not want if we deploy that application to FastCGI. - -Creating a `.fcgi` file ------------------------ - -First you need to create the FastCGI server file. Let's call it -`yourapplication.fcgi`:: - - #!/usr/bin/python - from flup.server.fcgi import WSGIServer - from yourapplication import app - - if __name__ == '__main__': - WSGIServer(app).run() - -This is enough for Apache to work, however nginx and older versions of -lighttpd need a socket to be explicitly passed to communicate with the -FastCGI server. For that to work you need to pass the path to the -socket to the :class:`~flup.server.fcgi.WSGIServer`:: - - WSGIServer(application, bindAddress='/path/to/fcgi.sock').run() - -The path has to be the exact same path you define in the server -config. - -Save the `yourapplication.fcgi` file somewhere you will find it again. -It makes sense to have that in `/var/www/yourapplication` or something -similar. - -Make sure to set the executable bit on that file so that the servers -can execute it: - -.. sourcecode:: text - - # chmod +x /var/www/yourapplication/yourapplication.fcgi - -Configuring lighttpd --------------------- - -A basic FastCGI configuration for lighttpd looks like that:: - - fastcgi.server = ("/yourapplication.fcgi" => - (( - "socket" => "/tmp/yourapplication-fcgi.sock", - "bin-path" => "/var/www/yourapplication/yourapplication.fcgi", - "check-local" => "disable", - "max-procs" => 1 - )) - ) - - alias.url = ( - "/static/" => "/path/to/your/static" - ) - - url.rewrite-once = ( - "^(/static.*)$" => "$1", - "^(/.*)$" => "/yourapplication.fcgi$1" - -Remember to enable the FastCGI, alias and rewrite modules. This -configuration binds the application to `/yourapplication`. If you want -the application to work in the URL root you have to work around a -lighttpd bug with the -:class:`~werkzeug.contrib.fixers.LighttpdCGIRootFix` middleware. - -Make sure to apply it only if you are mounting the application the URL -root. Also, see the Lighty docs for more information on `FastCGI and -Python `_ -(note that explicitly passing a socket to run() is no longer necessary). - - -Configuring nginx ------------------ - -Installing FastCGI applications on nginx is a bit different because by -default no FastCGI parameters are forwarded. - -A basic flask FastCGI configuration for nginx looks like this:: - - location = /yourapplication { rewrite ^ /yourapplication/ last; } - location /yourapplication { try_files $uri @yourapplication; } - location @yourapplication { - include fastcgi_params; - fastcgi_split_path_info ^(/yourapplication)(.*)$; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_pass unix:/tmp/yourapplication-fcgi.sock; - } - -This configuration binds the application to `/yourapplication`. If you -want to have it in the URL root it's a bit simpler because you don't -have to figure out how to calculate `PATH_INFO` and `SCRIPT_NAME`:: - - location / { try_files $uri @yourapplication; } - location @yourapplication { - include fastcgi_params; - fastcgi_param PATH_INFO $fastcgi_script_name; - fastcgi_param SCRIPT_NAME ""; - fastcgi_pass unix:/tmp/yourapplication-fcgi.sock; - } - -Running FastCGI Processes -------------------------- - -Since Nginx and others do not load FastCGI apps, you have to do it by -yourself. `Supervisor can manage FastCGI processes. -`_ -You can look around for other FastCGI process managers or write a script -to run your `.fcgi` file at boot, e.g. using a SysV ``init.d`` script. -For a temporary solution, you can always run the ``.fcgi`` script inside -GNU screen. See ``man screen`` for details, and note that this is a -manual solution which does not persist across system restart:: - - $ screen - $ /var/www/yourapplication/yourapplication.fcgi - -Debugging ---------- - -FastCGI deployments tend to be hard to debug on most webservers. Very -often the only thing the server log tells you is something along the -lines of "premature end of headers". In order to debug the application -the only thing that can really give you ideas why it breaks is switching -to the correct user and executing the application by hand. - -This example assumes your application is called `application.fcgi` and -that your webserver user is `www-data`:: - - $ su www-data - $ cd /var/www/yourapplication - $ python application.fcgi - Traceback (most recent call last): - File "yourapplication.fcgi", line 4, in - ImportError: No module named yourapplication - -In this case the error seems to be "yourapplication" not being on the -python path. Common problems are: - -- Relative paths being used. Don't rely on the current working directory -- The code depending on environment variables that are not set by the - web server. -- Different python interpreters being used. - -.. _nginx: http://nginx.org/ -.. _lighttpd: http://www.lighttpd.net/ -.. _cherokee: http://www.cherokee-project.com/ -.. _flup: http://trac.saddi.com/flup diff --git a/app/static/doc/flask-docs/_sources/deploying/index.txt b/app/static/doc/flask-docs/_sources/deploying/index.txt deleted file mode 100644 index d258df8..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/index.txt +++ /dev/null @@ -1,23 +0,0 @@ -.. _deployment: - -Deployment Options -================== - -Depending on what you have available there are multiple ways to run -Flask applications. You can use the builtin server during development, -but you should use a full deployment option for production applications. -(Do not use the builtin development server in production.) Several -options are available and documented here. - -If you have a different WSGI server look up the server documentation -about how to use a WSGI app with it. Just remember that your -:class:`Flask` application object is the actual WSGI application. - -.. toctree:: - :maxdepth: 2 - - mod_wsgi - cgi - fastcgi - uwsgi - others diff --git a/app/static/doc/flask-docs/_sources/deploying/mod_wsgi.txt b/app/static/doc/flask-docs/_sources/deploying/mod_wsgi.txt deleted file mode 100644 index c85ed64..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/mod_wsgi.txt +++ /dev/null @@ -1,167 +0,0 @@ -.. _mod_wsgi-deployment: - -mod_wsgi (Apache) -================= - -If you are using the `Apache`_ webserver, consider using `mod_wsgi`_. - -.. admonition:: Watch Out - - Please make sure in advance that any ``app.run()`` calls you might - have in your application file are inside an ``if __name__ == - '__main__':`` block or moved to a separate file. Just make sure it's - not called because this will always start a local WSGI server which - we do not want if we deploy that application to mod_wsgi. - -.. _Apache: http://httpd.apache.org/ - -Installing `mod_wsgi` ---------------------- - -If you don't have `mod_wsgi` installed yet you have to either install it -using a package manager or compile it yourself. The mod_wsgi -`installation instructions`_ cover source installations on UNIX systems. - -If you are using Ubuntu/Debian you can apt-get it and activate it as -follows: - -.. sourcecode:: text - - # apt-get install libapache2-mod-wsgi - -On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by -using pkg_add: - -.. sourcecode:: text - - # pkg_add -r mod_wsgi - -If you are using pkgsrc you can install `mod_wsgi` by compiling the -`www/ap2-wsgi` package. - -If you encounter segfaulting child processes after the first apache -reload you can safely ignore them. Just restart the server. - -Creating a `.wsgi` file ------------------------ - -To run your application you need a `yourapplication.wsgi` file. This file -contains the code `mod_wsgi` is executing on startup to get the application -object. The object called `application` in that file is then used as -application. - -For most applications the following file should be sufficient:: - - from yourapplication import app as application - -If you don't have a factory function for application creation but a singleton -instance you can directly import that one as `application`. - -Store that file somewhere that you will find it again (e.g.: -`/var/www/yourapplication`) and make sure that `yourapplication` and all -the libraries that are in use are on the python load path. If you don't -want to install it system wide consider using a `virtual python`_ -instance. - -Configuring Apache ------------------- - -The last thing you have to do is to create an Apache configuration file -for your application. In this example we are telling `mod_wsgi` to -execute the application under a different user for security reasons: - -.. sourcecode:: apache - - - ServerName example.com - - WSGIDaemonProcess yourapplication user=user1 group=group1 threads=5 - WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi - - - WSGIProcessGroup yourapplication - WSGIApplicationGroup %{GLOBAL} - Order deny,allow - Allow from all - - - -For more information consult the `mod_wsgi wiki`_. - -.. _mod_wsgi: http://code.google.com/p/modwsgi/ -.. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide -.. _virtual python: http://pypi.python.org/pypi/virtualenv -.. _mod_wsgi wiki: http://code.google.com/p/modwsgi/wiki/ - -Troubleshooting ---------------- - -If your application does not run, follow this guide to troubleshoot: - -**Problem:** application does not run, errorlog shows SystemExit ignored - You have a ``app.run()`` call in your application file that is not - guarded by an ``if __name__ == '__main__':`` condition. Either - remove that :meth:`~flask.Flask.run` call from the file and move it - into a separate `run.py` file or put it into such an if block. - -**Problem:** application gives permission errors - Probably caused by your application running as the wrong user. Make - sure the folders the application needs access to have the proper - privileges set and the application runs as the correct user - (``user`` and ``group`` parameter to the `WSGIDaemonProcess` - directive) - -**Problem:** application dies with an error on print - Keep in mind that mod_wsgi disallows doing anything with - :data:`sys.stdout` and :data:`sys.stderr`. You can disable this - protection from the config by setting the `WSGIRestrictStdout` to - ``off``: - - .. sourcecode:: apache - - WSGIRestrictStdout Off - - Alternatively you can also replace the standard out in the .wsgi file - with a different stream:: - - import sys - sys.stdout = sys.stderr - -**Problem:** accessing resources gives IO errors - Your application probably is a single .py file you symlinked into - the site-packages folder. Please be aware that this does not work, - instead you either have to put the folder into the pythonpath the - file is stored in, or convert your application into a package. - - The reason for this is that for non-installed packages, the module - filename is used to locate the resources and for symlinks the wrong - filename is picked up. - -Support for Automatic Reloading -------------------------------- - -To help deployment tools you can activate support for automatic -reloading. Whenever something changes the `.wsgi` file, `mod_wsgi` will -reload all the daemon processes for us. - -For that, just add the following directive to your `Directory` section: - -.. sourcecode:: apache - - WSGIScriptReloading On - -Working with Virtual Environments ---------------------------------- - -Virtual environments have the advantage that they never install the -required dependencies system wide so you have a better control over what -is used where. If you want to use a virtual environment with mod_wsgi -you have to modify your `.wsgi` file slightly. - -Add the following lines to the top of your `.wsgi` file:: - - activate_this = '/path/to/env/bin/activate_this.py' - execfile(activate_this, dict(__file__=activate_this)) - -This sets up the load paths according to the settings of the virtual -environment. Keep in mind that the path has to be absolute. diff --git a/app/static/doc/flask-docs/_sources/deploying/others.txt b/app/static/doc/flask-docs/_sources/deploying/others.txt deleted file mode 100644 index 6f3e5cc..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/others.txt +++ /dev/null @@ -1,102 +0,0 @@ -.. _deploying-other-servers: - -Other Servers -============= - -There are popular servers written in Python that allow the execution of WSGI -applications as well. These servers stand alone when they run; you can proxy -to them from your web server. - -Tornado --------- - -`Tornado`_ is an open source version of the scalable, non-blocking web -server and tools that power `FriendFeed`_. Because it is non-blocking and -uses epoll, it can handle thousands of simultaneous standing connections, -which means it is ideal for real-time web services. Integrating this -service with Flask is a trivial task:: - - from tornado.wsgi import WSGIContainer - from tornado.httpserver import HTTPServer - from tornado.ioloop import IOLoop - from yourapplication import app - - http_server = HTTPServer(WSGIContainer(app)) - http_server.listen(5000) - IOLoop.instance().start() - - -.. _Tornado: http://www.tornadoweb.org/ -.. _FriendFeed: http://friendfeed.com/ - -Gevent -------- - -`Gevent`_ is a coroutine-based Python networking library that uses -`greenlet`_ to provide a high-level synchronous API on top of `libevent`_ -event loop:: - - from gevent.wsgi import WSGIServer - from yourapplication import app - - http_server = WSGIServer(('', 5000), app) - http_server.serve_forever() - -.. _Gevent: http://www.gevent.org/ -.. _greenlet: http://codespeak.net/py/0.9.2/greenlet.html -.. _libevent: http://monkey.org/~provos/libevent/ - -Gunicorn --------- - -`Gunicorn`_ 'Green Unicorn' is a WSGI HTTP Server for UNIX. It's a pre-fork -worker model ported from Ruby's Unicorn project. It supports both `eventlet`_ -and `greenlet`_. Running a Flask application on this server is quite simple:: - - gunicorn myproject:app - -`Gunicorn`_ provides many command-line options -- see ``gunicorn -h``. -For example, to run a Flask application with 4 worker processes (``-w -4``) binding to localhost port 4000 (``-b 127.0.0.1:4000``):: - - gunicorn -w 4 -b 127.0.0.1:4000 myproject:app - -.. _Gunicorn: http://gunicorn.org/ -.. _eventlet: http://eventlet.net/ -.. _greenlet: http://codespeak.net/py/0.9.2/greenlet.html - -Proxy Setups ------------- - -If you deploy your application using one of these servers behind an HTTP -proxy you will need to rewrite a few headers in order for the -application to work. The two problematic values in the WSGI environment -usually are `REMOTE_ADDR` and `HTTP_HOST`. Werkzeug ships a fixer that -will solve some common setups, but you might want to write your own WSGI -middleware for specific setups. - -The most common setup invokes the host being set from `X-Forwarded-Host` -and the remote address from `X-Forwarded-For`:: - - from werkzeug.contrib.fixers import ProxyFix - app.wsgi_app = ProxyFix(app.wsgi_app) - -Please keep in mind that it is a security issue to use such a middleware -in a non-proxy setup because it will blindly trust the incoming -headers which might be forged by malicious clients. - -If you want to rewrite the headers from another header, you might want to -use a fixer like this:: - - class CustomProxyFix(object): - - def __init__(self, app): - self.app = app - - def __call__(self, environ, start_response): - host = environ.get('HTTP_X_FHOST', '') - if host: - environ['HTTP_HOST'] = host - return self.app(environ, start_response) - - app.wsgi_app = CustomProxyFix(app.wsgi_app) diff --git a/app/static/doc/flask-docs/_sources/deploying/uwsgi.txt b/app/static/doc/flask-docs/_sources/deploying/uwsgi.txt deleted file mode 100644 index bdee15b..0000000 --- a/app/static/doc/flask-docs/_sources/deploying/uwsgi.txt +++ /dev/null @@ -1,68 +0,0 @@ -.. _deploying-uwsgi: - -uWSGI -===== - -uWSGI is a deployment option on servers like `nginx`_, `lighttpd`_, and -`cherokee`_; see :ref:`deploying-fastcgi` and -:ref:`deploying-other-servers` for other options. To use your WSGI -application with uWSGI protocol you will need a uWSGI server -first. uWSGI is both a protocol and an application server; the -application server can serve uWSGI, FastCGI, and HTTP protocols. - -The most popular uWSGI server is `uwsgi`_, which we will use for this -guide. Make sure to have it installed to follow along. - -.. admonition:: Watch Out - - Please make sure in advance that any ``app.run()`` calls you might - have in your application file are inside an ``if __name__ == - '__main__':`` block or moved to a separate file. Just make sure it's - not called because this will always start a local WSGI server which - we do not want if we deploy that application to uWSGI. - -Starting your app with uwsgi ----------------------------- - -`uwsgi` is designed to operate on WSGI callables found in python modules. - -Given a flask application in myapp.py, use the following command: - -.. sourcecode:: text - - $ uwsgi -s /tmp/uwsgi.sock --module myapp --callable app - -Or, if you prefer: - -.. sourcecode:: text - - $ uwsgi -s /tmp/uwsgi.sock -w myapp:app - -Configuring nginx ------------------ - -A basic flask uWSGI configuration for nginx looks like this:: - - location = /yourapplication { rewrite ^ /yourapplication/; } - location /yourapplication { try_files $uri @yourapplication; } - location @yourapplication { - include uwsgi_params; - uwsgi_param SCRIPT_NAME /yourapplication; - uwsgi_modifier1 30; - uwsgi_pass unix:/tmp/uwsgi.sock; - } - -This configuration binds the application to `/yourapplication`. If you want -to have it in the URL root it's a bit simpler because you don't have to tell -it the WSGI `SCRIPT_NAME` or set the uwsgi modifier to make use of it:: - - location / { try_files $uri @yourapplication; } - location @yourapplication { - include uwsgi_params; - uwsgi_pass unix:/tmp/uwsgi.sock; - } - -.. _nginx: http://nginx.org/ -.. _lighttpd: http://www.lighttpd.net/ -.. _cherokee: http://www.cherokee-project.com/ -.. _uwsgi: http://projects.unbit.it/uwsgi/ diff --git a/app/static/doc/flask-docs/_sources/design.txt b/app/static/doc/flask-docs/_sources/design.txt deleted file mode 100644 index 6ca363a..0000000 --- a/app/static/doc/flask-docs/_sources/design.txt +++ /dev/null @@ -1,191 +0,0 @@ -.. _design: - -Design Decisions in Flask -========================= - -If you are curious why Flask does certain things the way it does and not -differently, this section is for you. This should give you an idea about -some of the design decisions that may appear arbitrary and surprising at -first, especially in direct comparison with other frameworks. - - -The Explicit Application Object -------------------------------- - -A Python web application based on WSGI has to have one central callable -object that implements the actual application. In Flask this is an -instance of the :class:`~flask.Flask` class. Each Flask application has -to create an instance of this class itself and pass it the name of the -module, but why can't Flask do that itself? - -Without such an explicit application object the following code:: - - from flask import Flask - app = Flask(__name__) - - @app.route('/') - def index(): - return 'Hello World!' - -Would look like this instead:: - - from hypothetical_flask import route - - @route('/') - def index(): - return 'Hello World!' - -There are three major reasons for this. The most important one is that -implicit application objects require that there may only be one instance at -the time. There are ways to fake multiple applications with a single -application object, like maintaining a stack of applications, but this -causes some problems I won't outline here in detail. Now the question is: -when does a microframework need more than one application at the same -time? A good example for this is unittesting. When you want to test -something it can be very helpful to create a minimal application to test -specific behavior. When the application object is deleted everything it -allocated will be freed again. - -Another thing that becomes possible when you have an explicit object lying -around in your code is that you can subclass the base class -(:class:`~flask.Flask`) to alter specific behaviour. This would not be -possible without hacks if the object were created ahead of time for you -based on a class that is not exposed to you. - -But there is another very important reason why Flask depends on an -explicit instantiation of that class: the package name. Whenever you -create a Flask instance you usually pass it `__name__` as package name. -Flask depends on that information to properly load resources relative -to your module. With Python's outstanding support for reflection it can -then access the package to figure out where the templates and static files -are stored (see :meth:`~flask.Flask.open_resource`). Now obviously there -are frameworks around that do not need any configuration and will still be -able to load templates relative to your application module. But they have -to use the current working directory for that, which is a very unreliable -way to determine where the application is. The current working directory -is process-wide and if you are running multiple applications in one -process (which could happen in a webserver without you knowing) the paths -will be off. Worse: many webservers do not set the working directory to -the directory of your application but to the document root which does not -have to be the same folder. - -The third reason is "explicit is better than implicit". That object is -your WSGI application, you don't have to remember anything else. If you -want to apply a WSGI middleware, just wrap it and you're done (though -there are better ways to do that so that you do not lose the reference -to the application object :meth:`~flask.Flask.wsgi_app`). - -Furthermore this design makes it possible to use a factory function to -create the application which is very helpful for unittesting and similar -things (:ref:`app-factories`). - -The Routing System ------------------- - -Flask uses the Werkzeug routing system which has was designed to -automatically order routes by complexity. This means that you can declare -routes in arbitrary order and they will still work as expected. This is a -requirement if you want to properly implement decorator based routing -since decorators could be fired in undefined order when the application is -split into multiple modules. - -Another design decision with the Werkzeug routing system is that routes -in Werkzeug try to ensure that there is that URLs are unique. Werkzeug -will go quite far with that in that it will automatically redirect to a -canonical URL if a route is ambiguous. - - -One Template Engine -------------------- - -Flask decides on one template engine: Jinja2. Why doesn't Flask have a -pluggable template engine interface? You can obviously use a different -template engine, but Flask will still configure Jinja2 for you. While -that limitation that Jinja2 is *always* configured will probably go away, -the decision to bundle one template engine and use that will not. - -Template engines are like programming languages and each of those engines -has a certain understanding about how things work. On the surface they -all work the same: you tell the engine to evaluate a template with a set -of variables and take the return value as string. - -But that's about where similarities end. Jinja2 for example has an -extensive filter system, a certain way to do template inheritance, support -for reusable blocks (macros) that can be used from inside templates and -also from Python code, uses Unicode for all operations, supports -iterative template rendering, configurable syntax and more. On the other -hand an engine like Genshi is based on XML stream evaluation, template -inheritance by taking the availability of XPath into account and more. -Mako on the other hand treats templates similar to Python modules. - -When it comes to connecting a template engine with an application or -framework there is more than just rendering templates. For instance, -Flask uses Jinja2's extensive autoescaping support. Also it provides -ways to access macros from Jinja2 templates. - -A template abstraction layer that would not take the unique features of -the template engines away is a science on its own and a too large -undertaking for a microframework like Flask. - -Furthermore extensions can then easily depend on one template language -being present. You can easily use your own templating language, but an -extension could still depend on Jinja itself. - - -Micro with Dependencies ------------------------ - -Why does Flask call itself a microframework and yet it depends on two -libraries (namely Werkzeug and Jinja2). Why shouldn't it? If we look -over to the Ruby side of web development there we have a protocol very -similar to WSGI. Just that it's called Rack there, but besides that it -looks very much like a WSGI rendition for Ruby. But nearly all -applications in Ruby land do not work with Rack directly, but on top of a -library with the same name. This Rack library has two equivalents in -Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but -from my understanding it's sort of deprecated in favour of WebOb. The -development of WebOb and Werkzeug started side by side with similar ideas -in mind: be a good implementation of WSGI for other applications to take -advantage. - -Flask is a framework that takes advantage of the work already done by -Werkzeug to properly interface WSGI (which can be a complex task at -times). Thanks to recent developments in the Python package -infrastructure, packages with dependencies are no longer an issue and -there are very few reasons against having libraries that depend on others. - - -Thread Locals -------------- - -Flask uses thread local objects (context local objects in fact, they -support greenlet contexts as well) for request, session and an extra -object you can put your own things on (:data:`~flask.g`). Why is that and -isn't that a bad idea? - -Yes it is usually not such a bright idea to use thread locals. They cause -troubles for servers that are not based on the concept of threads and make -large applications harder to maintain. However Flask is just not designed -for large applications or asynchronous servers. Flask wants to make it -quick and easy to write a traditional web application. - -Also see the :ref:`becomingbig` section of the documentation for some -inspiration for larger applications based on Flask. - - -What Flask is, What Flask is Not --------------------------------- - -Flask will never have a database layer. It will not have a form library -or anything else in that direction. Flask itself just bridges to Werkzeug -to implement a proper WSGI application and to Jinja2 to handle templating. -It also binds to a few common standard library packages such as logging. -Everything else is up for extensions. - -Why is this the case? Because people have different preferences and -requirements and Flask could not meet those if it would force any of this -into the core. The majority of web applications will need a template -engine in some sort. However not every application needs a SQL database. - -The idea of Flask is to build a good foundation for all applications. -Everything else is up to you or extensions. diff --git a/app/static/doc/flask-docs/_sources/errorhandling.txt b/app/static/doc/flask-docs/_sources/errorhandling.txt deleted file mode 100644 index debb9d7..0000000 --- a/app/static/doc/flask-docs/_sources/errorhandling.txt +++ /dev/null @@ -1,237 +0,0 @@ -.. _application-errors: - -Handling Application Errors -=========================== - -.. versionadded:: 0.3 - -Applications fail, servers fail. Sooner or later you will see an exception -in production. Even if your code is 100% correct, you will still see -exceptions from time to time. Why? Because everything else involved will -fail. Here some situations where perfectly fine code can lead to server -errors: - -- the client terminated the request early and the application was still - reading from the incoming data. -- the database server was overloaded and could not handle the query. -- a filesystem is full -- a harddrive crashed -- a backend server overloaded -- a programming error in a library you are using -- network connection of the server to another system failed. - -And that's just a small sample of issues you could be facing. So how do we -deal with that sort of problem? By default if your application runs in -production mode, Flask will display a very simple page for you and log the -exception to the :attr:`~flask.Flask.logger`. - -But there is more you can do, and we will cover some better setups to deal -with errors. - -Error Mails ------------ - -If the application runs in production mode (which it will do on your -server) you won't see any log messages by default. Why is that? Flask -tries to be a zero-configuration framework. Where should it drop the logs -for you if there is no configuration? Guessing is not a good idea because -chances are, the place it guessed is not the place where the user has -permission to create a logfile. Also, for most small applications nobody -will look at the logs anyways. - -In fact, I promise you right now that if you configure a logfile for the -application errors you will never look at it except for debugging an issue -when a user reported it for you. What you want instead is a mail the -second the exception happened. Then you get an alert and you can do -something about it. - -Flask uses the Python builtin logging system, and it can actually send -you mails for errors which is probably what you want. Here is how you can -configure the Flask logger to send you mails for exceptions:: - - ADMINS = ['yourname@example.com'] - if not app.debug: - import logging - from logging.handlers import SMTPHandler - mail_handler = SMTPHandler('127.0.0.1', - 'server-error@example.com', - ADMINS, 'YourApplication Failed') - mail_handler.setLevel(logging.ERROR) - app.logger.addHandler(mail_handler) - -So what just happened? We created a new -:class:`~logging.handlers.SMTPHandler` that will send mails with the mail -server listening on ``127.0.0.1`` to all the `ADMINS` from the address -*server-error@example.com* with the subject "YourApplication Failed". If -your mail server requires credentials, these can also be provided. For -that check out the documentation for the -:class:`~logging.handlers.SMTPHandler`. - -We also tell the handler to only send errors and more critical messages. -Because we certainly don't want to get a mail for warnings or other -useless logs that might happen during request handling. - -Before you run that in production, please also look at :ref:`logformat` to -put more information into that error mail. That will save you from a lot -of frustration. - - -Logging to a File ------------------ - -Even if you get mails, you probably also want to log warnings. It's a -good idea to keep as much information around that might be required to -debug a problem. Please note that Flask itself will not issue any -warnings in the core system, so it's your responsibility to warn in the -code if something seems odd. - -There are a couple of handlers provided by the logging system out of the -box but not all of them are useful for basic error logging. The most -interesting are probably the following: - -- :class:`~logging.FileHandler` - logs messages to a file on the - filesystem. -- :class:`~logging.handlers.RotatingFileHandler` - logs messages to a file - on the filesystem and will rotate after a certain number of messages. -- :class:`~logging.handlers.NTEventLogHandler` - will log to the system - event log of a Windows system. If you are deploying on a Windows box, - this is what you want to use. -- :class:`~logging.handlers.SysLogHandler` - sends logs to a UNIX - syslog. - -Once you picked your log handler, do like you did with the SMTP handler -above, just make sure to use a lower setting (I would recommend -`WARNING`):: - - if not app.debug: - import logging - from themodule import TheHandlerYouWant - file_handler = TheHandlerYouWant(...) - file_handler.setLevel(logging.WARNING) - app.logger.addHandler(file_handler) - -.. _logformat: - -Controlling the Log Format --------------------------- - -By default a handler will only write the message string into a file or -send you that message as mail. A log record stores more information, -and it makes a lot of sense to configure your logger to also contain that -information so that you have a better idea of why that error happened, and -more importantly, where it did. - -A formatter can be instantiated with a format string. Note that -tracebacks are appended to the log entry automatically. You don't have to -do that in the log formatter format string. - -Here some example setups: - -Email -````` - -:: - - from logging import Formatter - mail_handler.setFormatter(Formatter(''' - Message type: %(levelname)s - Location: %(pathname)s:%(lineno)d - Module: %(module)s - Function: %(funcName)s - Time: %(asctime)s - - Message: - - %(message)s - ''')) - -File logging -```````````` - -:: - - from logging import Formatter - file_handler.setFormatter(Formatter( - '%(asctime)s %(levelname)s: %(message)s ' - '[in %(pathname)s:%(lineno)d]' - )) - - -Complex Log Formatting -`````````````````````` - -Here is a list of useful formatting variables for the format string. Note -that this list is not complete, consult the official documentation of the -:mod:`logging` package for a full list. - -.. tabularcolumns:: |p{3cm}|p{12cm}| - -+------------------+----------------------------------------------------+ -| Format | Description | -+==================+====================================================+ -| ``%(levelname)s``| Text logging level for the message | -| | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``, | -| | ``'ERROR'``, ``'CRITICAL'``). | -+------------------+----------------------------------------------------+ -| ``%(pathname)s`` | Full pathname of the source file where the | -| | logging call was issued (if available). | -+------------------+----------------------------------------------------+ -| ``%(filename)s`` | Filename portion of pathname. | -+------------------+----------------------------------------------------+ -| ``%(module)s`` | Module (name portion of filename). | -+------------------+----------------------------------------------------+ -| ``%(funcName)s`` | Name of function containing the logging call. | -+------------------+----------------------------------------------------+ -| ``%(lineno)d`` | Source line number where the logging call was | -| | issued (if available). | -+------------------+----------------------------------------------------+ -| ``%(asctime)s`` | Human-readable time when the LogRecord` was | -| | created. By default this is of the form | -| | ``"2003-07-08 16:49:45,896"`` (the numbers after | -| | the comma are millisecond portion of the time). | -| | This can be changed by subclassing the formatter | -| | and overriding the | -| | :meth:`~logging.Formatter.formatTime` method. | -+------------------+----------------------------------------------------+ -| ``%(message)s`` | The logged message, computed as ``msg % args`` | -+------------------+----------------------------------------------------+ - -If you want to further customize the formatting, you can subclass the -formatter. The formatter has three interesting methods: - -:meth:`~logging.Formatter.format`: - handles the actual formatting. It is passed a - :class:`~logging.LogRecord` object and has to return the formatted - string. -:meth:`~logging.Formatter.formatTime`: - called for `asctime` formatting. If you want a different time format - you can override this method. -:meth:`~logging.Formatter.formatException` - called for exception formatting. It is passed an :attr:`~sys.exc_info` - tuple and has to return a string. The default is usually fine, you - don't have to override it. - -For more information, head over to the official documentation. - - -Other Libraries ---------------- - -So far we only configured the logger your application created itself. -Other libraries might log themselves as well. For example, SQLAlchemy uses -logging heavily in its core. While there is a method to configure all -loggers at once in the :mod:`logging` package, I would not recommend using -it. There might be a situation in which you want to have multiple -separate applications running side by side in the same Python interpreter -and then it becomes impossible to have different logging setups for those. - -Instead, I would recommend figuring out which loggers you are interested -in, getting the loggers with the :func:`~logging.getLogger` function and -iterating over them to attach handlers:: - - from logging import getLogger - loggers = [app.logger, getLogger('sqlalchemy'), - getLogger('otherlibrary')] - for logger in loggers: - logger.addHandler(mail_handler) - logger.addHandler(file_handler) diff --git a/app/static/doc/flask-docs/_sources/extensiondev.txt b/app/static/doc/flask-docs/_sources/extensiondev.txt deleted file mode 100644 index ee0d5e6..0000000 --- a/app/static/doc/flask-docs/_sources/extensiondev.txt +++ /dev/null @@ -1,387 +0,0 @@ -Flask Extension Development -=========================== - -Flask, being a microframework, often requires some repetitive steps to get -a third party library working. Because very often these steps could be -abstracted to support multiple projects the `Flask Extension Registry`_ -was created. - -If you want to create your own Flask extension for something that does not -exist yet, this guide to extension development will help you get your -extension running in no time and to feel like users would expect your -extension to behave. - -.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ - -Anatomy of an Extension ------------------------ - -Extensions are all located in a package called ``flask_something`` -where "something" is the name of the library you want to bridge. So for -example if you plan to add support for a library named `simplexml` to -Flask, you would name your extension's package ``flask_simplexml``. - -The name of the actual extension (the human readable name) however would -be something like "Flask-SimpleXML". Make sure to include the name -"Flask" somewhere in that name and that you check the capitalization. -This is how users can then register dependencies to your extension in -their `setup.py` files. - -Flask sets up a redirect package called :data:`flask.ext` where users -should import the extensions from. If you for instance have a package -called ``flask_something`` users would import it as -``flask.ext.something``. This is done to transition from the old -namespace packages. See :ref:`ext-import-transition` for more details. - -But how do extensions look like themselves? An extension has to ensure -that it works with multiple Flask application instances at once. This is -a requirement because many people will use patterns like the -:ref:`app-factories` pattern to create their application as needed to aid -unittests and to support multiple configurations. Because of that it is -crucial that your application supports that kind of behaviour. - -Most importantly the extension must be shipped with a `setup.py` file and -registered on PyPI. Also the development checkout link should work so -that people can easily install the development version into their -virtualenv without having to download the library by hand. - -Flask extensions must be licensed as BSD or MIT or a more liberal license -to be enlisted on the Flask Extension Registry. Keep in mind that the -Flask Extension Registry is a moderated place and libraries will be -reviewed upfront if they behave as required. - -"Hello Flaskext!" ------------------ - -So let's get started with creating such a Flask extension. The extension -we want to create here will provide very basic support for SQLite3. - -First we create the following folder structure:: - - flask-sqlite3/ - flask_sqlite3.py - LICENSE - README - -Here's the contents of the most important files: - -setup.py -```````` - -The next file that is absolutely required is the `setup.py` file which is -used to install your Flask extension. The following contents are -something you can work with:: - - """ - Flask-SQLite3 - ------------- - - This is the description for that library - """ - from setuptools import setup - - - setup( - name='Flask-SQLite3', - version='1.0', - url='http://example.com/flask-sqlite3/', - license='BSD', - author='Your Name', - author_email='your-email@example.com', - description='Very short description', - long_description=__doc__, - py_modules=['flask_sqlite3'], - # if you would be using a package instead use packages instead - # of py_modules: - # packages=['flask_sqlite3'], - zip_safe=False, - include_package_data=True, - platforms='any', - install_requires=[ - 'Flask' - ], - classifiers=[ - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Software Development :: Libraries :: Python Modules' - ] - ) - -That's a lot of code but you can really just copy/paste that from existing -extensions and adapt. - -flask_sqlite3.py -```````````````` - -Now this is where your extension code goes. But how exactly should such -an extension look like? What are the best practices? Continue reading -for some insight. - -Initializing Extensions ------------------------ - -Many extensions will need some kind of initialization step. For example, -consider your application is currently connecting to SQLite like the -documentation suggests (:ref:`sqlite3`) you will need to provide a few -functions and before / after request handlers. So how does the extension -know the name of the application object? - -Quite simple: you pass it to it. - -There are two recommended ways for an extension to initialize: - -initialization functions: - If your extension is called `helloworld` you might have a function - called ``init_helloworld(app[, extra_args])`` that initializes the - extension for that application. It could attach before / after - handlers etc. - -classes: - Classes work mostly like initialization functions but can later be - used to further change the behaviour. For an example look at how the - `OAuth extension`_ works: there is an `OAuth` object that provides - some helper functions like `OAuth.remote_app` to create a reference to - a remote application that uses OAuth. - -What to use depends on what you have in mind. For the SQLite 3 extension -we will use the class based approach because it will provide users with a -manager object that handles opening and closing database connections. - -The Extension Code ------------------- - -Here's the contents of the `flask_sqlite3.py` for copy/paste:: - - from __future__ import absolute_import - import sqlite3 - - from flask import _request_ctx_stack - - class SQLite3(object): - - def __init__(self, app): - self.app = app - self.app.config.setdefault('SQLITE3_DATABASE', ':memory:') - self.app.teardown_request(self.teardown_request) - self.app.before_request(self.before_request) - - def connect(self): - return sqlite3.connect(self.app.config['SQLITE3_DATABASE']) - - def before_request(self): - ctx = _request_ctx_stack.top - ctx.sqlite3_db = self.connect() - - def teardown_request(self, exception): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - - def get_db(self): - ctx = _request_ctx_stack.top - if ctx is not None: - return ctx.sqlite3_db - -So here's what these lines of code do: - -1. The ``__future__`` import is necessary to activate absolute imports. - Otherwise we could not call our module `sqlite3.py` and import the - top-level `sqlite3` module which actually implements the connection to - SQLite. -2. We create a class for our extension that requires a supplied `app` object, - sets a configuration for the database if it's not there - (:meth:`dict.setdefault`), and attaches `before_request` and - `teardown_request` handlers. -3. Next, we define a `connect` function that opens a database connection. -4. Then we set up the request handlers we bound to the app above. Note here - that we're attaching our database connection to the top request context via - `_request_ctx_stack.top`. Extensions should use the top context and not the - `g` object to store things like database connections. -5. Finally, we add a `get_db` function that simplifies access to the context's - database. - -So why did we decide on a class based approach here? Because using our -extension looks something like this:: - - from flask import Flask - from flask_sqlite3 import SQLite3 - - app = Flask(__name__) - app.config.from_pyfile('the-config.cfg') - manager = SQLite3(app) - db = manager.get_db() - -You can then use the database from views like this:: - - @app.route('/') - def show_all(): - cur = db.cursor() - cur.execute(...) - -Opening a database connection from outside a view function is simple. - ->>> from yourapplication import db ->>> cur = db.cursor() ->>> cur.execute(...) - -Adding an `init_app` Function ------------------------------ - -In practice, you'll almost always want to permit users to initialize your -extension and provide an app object after the fact. This can help avoid -circular import problems when a user is breaking their app into multiple files. -Our extension could add an `init_app` function as follows:: - - class SQLite3(object): - - def __init__(self, app=None): - if app is not None: - self.app = app - self.init_app(self.app) - else: - self.app = None - - def init_app(self, app): - self.app = app - self.app.config.setdefault('SQLITE3_DATABASE', ':memory:') - self.app.teardown_request(self.teardown_request) - self.app.before_request(self.before_request) - - def connect(self): - return sqlite3.connect(app.config['SQLITE3_DATABASE']) - - def before_request(self): - ctx = _request_ctx_stack.top - ctx.sqlite3_db = self.connect() - - def teardown_request(self, exception): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - - def get_db(self): - ctx = _request_ctx_stack.top - if ctx is not None: - return ctx.sqlite3_db - -The user could then initialize the extension in one file:: - - manager = SQLite3() - -and bind their app to the extension in another file:: - - manager.init_app(app) - -End-Of-Request Behavior ------------------------ - -Due to the change in Flask 0.7 regarding functions that are run at the end -of the request your extension will have to be extra careful there if it -wants to continue to support older versions of Flask. The following -pattern is a good way to support both:: - - def close_connection(response): - ctx = _request_ctx_stack.top - ctx.sqlite3_db.close() - return response - - if hasattr(app, 'teardown_request'): - app.teardown_request(close_connection) - else: - app.after_request(close_connection) - -Strictly speaking the above code is wrong, because teardown functions are -passed the exception and typically don't return anything. However because -the return value is discarded this will just work assuming that the code -in between does not touch the passed parameter. - -Learn from Others ------------------ - -This documentation only touches the bare minimum for extension -development. If you want to learn more, it's a very good idea to check -out existing extensions on the `Flask Extension Registry`_. If you feel -lost there is still the `mailinglist`_ and the `IRC channel`_ to get some -ideas for nice looking APIs. Especially if you do something nobody before -you did, it might be a very good idea to get some more input. This not -only to get an idea about what people might want to have from an -extension, but also to avoid having multiple developers working on pretty -much the same side by side. - -Remember: good API design is hard, so introduce your project on the -mailinglist, and let other developers give you a helping hand with -designing the API. - -The best Flask extensions are extensions that share common idioms for the -API. And this can only work if collaboration happens early. - -Approved Extensions -------------------- - -Flask also has the concept of approved extensions. Approved extensions -are tested as part of Flask itself to ensure extensions do not break on -new releases. These approved extensions are listed on the `Flask -Extension Registry`_ and marked appropriately. If you want your own -extension to be approved you have to follow these guidelines: - -1. An approved Flask extension must provide exactly one package or module - named ``flask_extensionname``. They might also reside inside a - ``flaskext`` namespace packages though this is discouraged now. -2. It must ship a testing suite that can either be invoked with ``make test`` - or ``python setup.py test``. For test suites invoked with ``make - test`` the extension has to ensure that all dependencies for the test - are installed automatically, in case of ``python setup.py test`` - dependencies for tests alone can be specified in the `setup.py` - file. The test suite also has to be part of the distribution. -3. APIs of approved extensions will be checked for the following - characteristics: - - - an approved extension has to support multiple applications - running in the same Python process. - - it must be possible to use the factory pattern for creating - applications. - -4. The license must be BSD/MIT/WTFPL licensed. -5. The naming scheme for official extensions is *Flask-ExtensionName* or - *ExtensionName-Flask*. -6. Approved extensions must define all their dependencies in the - `setup.py` file unless a dependency cannot be met because it is not - available on PyPI. -7. The extension must have documentation that uses one of the two Flask - themes for Sphinx documentation. -8. The setup.py description (and thus the PyPI description) has to - link to the documentation, website (if there is one) and there - must be a link to automatically install the development version - (``PackageName==dev``). -9. The ``zip_safe`` flag in the setup script must be set to ``False``, - even if the extension would be safe for zipping. -10. An extension currently has to support Python 2.5, 2.6 as well as - Python 2.7 - - -.. _ext-import-transition: - -Extension Import Transition ---------------------------- - -For a while we recommended using namespace packages for Flask extensions. -This turned out to be problematic in practice because many different -competing namespace package systems exist and pip would automatically -switch between different systems and this caused a lot of problems for -users. - -Instead we now recommend naming packages ``flask_foo`` instead of the now -deprecated ``flaskext.foo``. Flask 0.8 introduces a redirect import -system that lets uses import from ``flask.ext.foo`` and it will try -``flask_foo`` first and if that fails ``flaskext.foo``. - -Flask extensions should urge users to import from ``flask.ext.foo`` -instead of ``flask_foo`` or ``flaskext_foo`` so that extensions can -transition to the new package name without affecting users. - - -.. _OAuth extension: http://packages.python.org/Flask-OAuth/ -.. _mailinglist: http://flask.pocoo.org/mailinglist/ -.. _IRC channel: http://flask.pocoo.org/community/irc/ diff --git a/app/static/doc/flask-docs/_sources/extensions.txt b/app/static/doc/flask-docs/_sources/extensions.txt deleted file mode 100644 index 53dca56..0000000 --- a/app/static/doc/flask-docs/_sources/extensions.txt +++ /dev/null @@ -1,48 +0,0 @@ -Flask Extensions -================ - -Flask extensions extend the functionality of Flask in various different -ways. For instance they add support for databases and other common tasks. - -Finding Extensions ------------------- - -Flask extensions are listed on the `Flask Extension Registry`_ and can be -downloaded with ``easy_install`` or ``pip``. If you add a Flask extension -as dependency to your ``requirements.rst`` or ``setup.py`` file they are -usually installed with a simple command or when your application installs. - -Using Extensions ----------------- - -Extensions typically have documentation that goes along that shows how to -use it. There are no general rules in how extensions are supposed to -behave but they are imported from common locations. If you have an -extension called ``Flask-Foo`` or ``Foo-Flask`` it will be always -importable from ``flask.ext.foo``:: - - from flask.ext import foo - -Flask Before 0.8 ----------------- - -If you are using Flask 0.7 or earlier the :data:`flask.ext` package will not -exist, instead you have to import from ``flaskext.foo`` or ``flask_foo`` -depending on how the extension is distributed. If you want to develop an -application that supports Flask 0.7 or earlier you should still import -from the :data:`flask.ext` package. We provide you with a compatibility -module that provides this package for older versions of Flask. You can -download it from github: `flaskext_compat.py`_ - -And here is how you can use it:: - - import flaskext_compat - flaskext_compat.activate() - - from flask.ext import foo - -Once the ``flaskext_compat`` module is activated the :data:`flask.ext` will -exist and you can start importing from there. - -.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ -.. _flaskext_compat.py: https://github.com/mitsuhiko/flask/raw/master/scripts/flaskext_compat.py diff --git a/app/static/doc/flask-docs/_sources/foreword.txt b/app/static/doc/flask-docs/_sources/foreword.txt deleted file mode 100644 index 10b886b..0000000 --- a/app/static/doc/flask-docs/_sources/foreword.txt +++ /dev/null @@ -1,100 +0,0 @@ -Foreword -======== - -Read this before you get started with Flask. This hopefully answers some -questions about the purpose and goals of the project, and when you -should or should not be using it. - -What does "micro" mean? ------------------------ - -To me, the "micro" in microframework refers not only to the simplicity and -small size of the framework, but also the fact that it does not make much -decisions for you. While Flask does pick a templating engine for you, we -won't make such decisions for your datastore or other parts. - -For us however the term “micro” does not mean that the whole implementation -has to fit into a single Python file. - -One of the design decisions with Flask was that simple tasks should be -simple and not take up a lot of code and yet not limit yourself. Because -of that we took a few design choices that some people might find -surprising or unorthodox. For example, Flask uses thread-local objects -internally so that you don't have to pass objects around from function to -function within a request in order to stay threadsafe. While this is a -really easy approach and saves you a lot of time, it might also cause some -troubles for very large applications because changes on these thread-local -objects can happen anywhere in the same thread. In order to solve these -problems we don't hide the thread locals for you but instead embrace them -and provide you with a lot of tools to make it as pleasant as possible to -work with them. - -Flask is also based on convention over configuration, which means that -many things are preconfigured. For example, by convention, templates and -static files are in subdirectories within the Python source tree of the -application. While this can be changed you usually don't have to. - -The main reason however why Flask is called a "microframework" is the idea -to keep the core simple but extensible. There is no database abstraction -layer, no form validation or anything else where different libraries -already exist that can handle that. However Flask knows the concept of -extensions that can add this functionality into your application as if it -was implemented in Flask itself. There are currently extensions for -object relational mappers, form validation, upload handling, various open -authentication technologies and more. - -Since Flask is based on a very solid foundation there is not a lot of code -in Flask itself. As such it's easy to adapt even for lage applications -and we are making sure that you can either configure it as much as -possible by subclassing things or by forking the entire codebase. If you -are interested in that, check out the :ref:`becomingbig` chapter. - -If you are curious about the Flask design principles, head over to the -section about :ref:`design`. - -Web Development is Dangerous ----------------------------- - -I'm not joking. Well, maybe a little. If you write a web -application, you are probably allowing users to register and leave their -data on your server. The users are entrusting you with data. And even if -you are the only user that might leave data in your application, you still -want that data to be stored securely. - -Unfortunately, there are many ways the security of a web application can be -compromised. Flask protects you against one of the most common security -problems of modern web applications: cross-site scripting (XSS). Unless -you deliberately mark insecure HTML as secure, Flask and the underlying -Jinja2 template engine have you covered. But there are many more ways to -cause security problems. - -The documentation will warn you about aspects of web development that -require attention to security. Some of these security concerns -are far more complex than one might think, and we all sometimes underestimate -the likelihood that a vulnerability will be exploited, until a clever -attacker figures out a way to exploit our applications. And don't think -that your application is not important enough to attract an attacker. -Depending on the kind of attack, chances are that automated bots are -probing for ways to fill your database with spam, links to malicious -software, and the like. - -So always keep security in mind when doing web development. - -The Status of Python 3 ----------------------- - -Currently the Python community is in the process of improving libraries to -support the new iteration of the Python programming language. While the -situation is greatly improving there are still some issues that make it -hard for us to switch over to Python 3 just now. These problems are -partially caused by changes in the language that went unreviewed for too -long, partially also because we have not quite worked out how the lower -level API should change for the unicode differences in Python3. - -Werkzeug and Flask will be ported to Python 3 as soon as a solution for -the changes is found, and we will provide helpful tips how to upgrade -existing applications to Python 3. Until then, we strongly recommend -using Python 2.6 and 2.7 with activated Python 3 warnings during -development. If you plan on upgrading to Python 3 in the near future we -strongly recommend that you read `How to write forwards compatible -Python code `_. diff --git a/app/static/doc/flask-docs/_sources/htmlfaq.txt b/app/static/doc/flask-docs/_sources/htmlfaq.txt deleted file mode 100644 index 1da25f3..0000000 --- a/app/static/doc/flask-docs/_sources/htmlfaq.txt +++ /dev/null @@ -1,207 +0,0 @@ -HTML/XHTML FAQ -============== - -The Flask documentation and example applications are using HTML5. You -may notice that in many situations, when end tags are optional they are -not used, so that the HTML is cleaner and faster to load. Because there -is much confusion about HTML and XHTML among developers, this document tries -to answer some of the major questions. - - -History of XHTML ----------------- - -For a while, it appeared that HTML was about to be replaced by XHTML. -However, barely any websites on the Internet are actual XHTML (which is -HTML processed using XML rules). There are a couple of major reasons -why this is the case. One of them is Internet Explorer's lack of proper -XHTML support. The XHTML spec states that XHTML must be served with the MIME -type `application/xhtml+xml`, but Internet Explorer refuses to read files -with that MIME type. -While it is relatively easy to configure Web servers to serve XHTML properly, -few people do. This is likely because properly using XHTML can be quite -painful. - -One of the most important causes of pain is XML's draconian (strict and -ruthless) error handling. When an XML parsing error is encountered, -the browser is supposed to show the user an ugly error message, instead -of attempting to recover from the error and display what it can. Most of -the (X)HTML generation on the web is based on non-XML template engines -(such as Jinja, the one used in Flask) which do not protect you from -accidentally creating invalid XHTML. There are XML based template engines, -such as Kid and the popular Genshi, but they often come with a larger -runtime overhead and, are not as straightforward to use because they have -to obey XML rules. - -The majority of users, however, assumed they were properly using XHTML. -They wrote an XHTML doctype at the top of the document and self-closed all -the necessary tags (``
`` becomes ``
`` or ``

`` in XHTML). -However, even if the document properly validates as XHTML, what really -determines XHTML/HTML processing in browsers is the MIME type, which as -said before is often not set properly. So the valid XHTML was being treated -as invalid HTML. - -XHTML also changed the way JavaScript is used. To properly work with XHTML, -programmers have to use the namespaced DOM interface with the XHTML -namespace to query for HTML elements. - -History of HTML5 ----------------- - -Development of the HTML5 specification was started in 2004 under the name -"Web Applications 1.0" by the Web Hypertext Application Technology Working -Group, or WHATWG (which was formed by the major browser vendors Apple, -Mozilla, and Opera) with the goal of writing a new and improved HTML -specification, based on existing browser behaviour instead of unrealistic -and backwards-incompatible specifications. - -For example, in HTML4 ``Hello``. However, since people were using -XHTML-like tags along the lines of ````, browser vendors implemented -the XHTML syntax over the syntax defined by the specification. - -In 2007, the specification was adopted as the basis of a new HTML -specification under the umbrella of the W3C, known as HTML5. Currently, -it appears that XHTML is losing traction, as the XHTML 2 working group has -been disbanded and HTML5 is being implemented by all major browser vendors. - -HTML versus XHTML ------------------ - -The following table gives you a quick overview of features available in -HTML 4.01, XHTML 1.1 and HTML5. (XHTML 1.0 is not included, as it was -superseded by XHTML 1.1 and the barely-used XHTML5.) - -.. tabularcolumns:: |p{9cm}|p{2cm}|p{2cm}|p{2cm}| - -+-----------------------------------------+----------+----------+----------+ -| | HTML4.01 | XHTML1.1 | HTML5 | -+=========================================+==========+==========+==========+ -| ``value`` | |Y| [1]_ | |N| | |N| | -+-----------------------------------------+----------+----------+----------+ -| ``
`` supported | |N| | |Y| | |Y| [2]_ | -+-----------------------------------------+----------+----------+----------+ -| `` - -Another method is using Google's `AJAX Libraries API -`_ to load jQuery: - -.. sourcecode:: html - - - - -In this case you have to put jQuery into your static folder as a fallback, but it will -first try to load it directly from Google. This has the advantage that your -website will probably load faster for users if they went to at least one -other website before using the same jQuery version from Google because it -will already be in the browser cache. - -Where is My Site? ------------------ - -Do you know where your application is? If you are developing the answer -is quite simple: it's on localhost port something and directly on the root -of that server. But what if you later decide to move your application to -a different location? For example to ``http://example.com/myapp``? On -the server side this never was a problem because we were using the handy -:func:`~flask.url_for` function that could answer that question for -us, but if we are using jQuery we should not hardcode the path to -the application but make that dynamic, so how can we do that? - -A simple method would be to add a script tag to our page that sets a -global variable to the prefix to the root of the application. Something -like this: - -.. sourcecode:: html+jinja - - - -The ``|safe`` is necessary so that Jinja does not escape the JSON encoded -string with HTML rules. Usually this would be necessary, but we are -inside a `script` block here where different rules apply. - -.. admonition:: Information for Pros - - In HTML the `script` tag is declared `CDATA` which means that entities - will not be parsed. Everything until ```` is handled as script. - This also means that there must never be any ``"|tojson|safe }}`` is rendered as - ``"<\/script>"``). - - -JSON View Functions -------------------- - -Now let's create a server side function that accepts two URL arguments of -numbers which should be added together and then sent back to the -application in a JSON object. This is a really ridiculous example and is -something you usually would do on the client side alone, but a simple -example that shows how you would use jQuery and Flask nonetheless:: - - from flask import Flask, jsonify, render_template, request - app = Flask(__name__) - - @app.route('/_add_numbers') - def add_numbers(): - a = request.args.get('a', 0, type=int) - b = request.args.get('b', 0, type=int) - return jsonify(result=a + b) - - @app.route('/') - def index(): - return render_template('index.html') - -As you can see I also added an `index` method here that renders a -template. This template will load jQuery as above and have a little form -we can add two numbers and a link to trigger the function on the server -side. - -Note that we are using the :meth:`~werkzeug.datastructures.MultiDict.get` method here -which will never fail. If the key is missing a default value (here ``0``) -is returned. Furthermore it can convert values to a specific type (like -in our case `int`). This is especially handy for code that is -triggered by a script (APIs, JavaScript etc.) because you don't need -special error reporting in that case. - -The HTML --------- - -Your index.html template either has to extend a `layout.html` template with -jQuery loaded and the `$SCRIPT_ROOT` variable set, or do that on the top. -Here's the HTML code needed for our little application (`index.html`). -Notice that we also drop the script directly into the HTML here. It is -usually a better idea to have that in a separate script file: - -.. sourcecode:: html - - -

jQuery Example

-

+ - = - ? -

calculate server side - -I won't got into detail here about how jQuery works, just a very quick -explanation of the little bit of code above: - -1. ``$(function() { ... })`` specifies code that should run once the - browser is done loading the basic parts of the page. -2. ``$('selector')`` selects an element and lets you operate on it. -3. ``element.bind('event', func)`` specifies a function that should run - when the user clicked on the element. If that function returns - `false`, the default behaviour will not kick in (in this case, navigate - to the `#` URL). -4. ``$.getJSON(url, data, func)`` sends a `GET` request to `url` and will - send the contents of the `data` object as query parameters. Once the - data arrived, it will call the given function with the return value as - argument. Note that we can use the `$SCRIPT_ROOT` variable here that - we set earlier. - -If you don't get the whole picture, download the `sourcecode -for this example -`_ -from github. diff --git a/app/static/doc/flask-docs/_sources/patterns/lazyloading.txt b/app/static/doc/flask-docs/_sources/patterns/lazyloading.txt deleted file mode 100644 index 50ad6fa..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/lazyloading.txt +++ /dev/null @@ -1,104 +0,0 @@ -Lazily Loading Views -==================== - -Flask is usually used with the decorators. Decorators are simple and you -have the URL right next to the function that is called for that specific -URL. However there is a downside to this approach: it means all your code -that uses decorators has to be imported upfront or Flask will never -actually find your function. - -This can be a problem if your application has to import quick. It might -have to do that on systems like Google's App Engine or other systems. So -if you suddenly notice that your application outgrows this approach you -can fall back to a centralized URL mapping. - -The system that enables having a central URL map is the -:meth:`~flask.Flask.add_url_rule` function. Instead of using decorators, -you have a file that sets up the application with all URLs. - -Converting to Centralized URL Map ---------------------------------- - -Imagine the current application looks somewhat like this:: - - from flask import Flask - app = Flask(__name__) - - @app.route('/') - def index(): - pass - - @app.route('/user/') - def user(username): - pass - -Then the centralized approach you would have one file with the views -(`views.py`) but without any decorator:: - - def index(): - pass - - def user(username): - pass - -And then a file that sets up an application which maps the functions to -URLs:: - - from flask import Flask - from yourapplication import views - app = Flask(__name__) - app.add_url_rule('/', view_func=views.index) - app.add_url_rule('/user/', view_func=views.user) - -Loading Late ------------- - -So far we only split up the views and the routing, but the module is still -loaded upfront. The trick to actually load the view function as needed. -This can be accomplished with a helper class that behaves just like a -function but internally imports the real function on first use:: - - from werkzeug import import_string, cached_property - - class LazyView(object): - - def __init__(self, import_name): - self.__module__, self.__name__ = import_name.rsplit('.', 1) - self.import_name = import_name - - @cached_property - def view(self): - return import_string(self.import_name) - - def __call__(self, *args, **kwargs): - return self.view(*args, **kwargs) - -What's important here is is that `__module__` and `__name__` are properly -set. This is used by Flask internally to figure out how to name the -URL rules in case you don't provide a name for the rule yourself. - -Then you can define your central place to combine the views like this:: - - from flask import Flask - from yourapplication.helpers import LazyView - app = Flask(__name__) - app.add_url_rule('/', - view_func=LazyView('yourapplication.views.index')) - app.add_url_rule('/user/', - view_func=LazyView('yourapplication.views.user')) - -You can further optimize this in terms of amount of keystrokes needed to -write this by having a function that calls into -:meth:`~flask.Flask.add_url_rule` by prefixing a string with the project -name and a dot, and by wrapping `view_func` in a `LazyView` as needed:: - - def url(url_rule, import_name, **options): - view = LazyView('yourapplication.' + import_name) - app.add_url_rule(url_rule, view_func=view, **options) - - url('/', 'views.index') - url('/user/', 'views.user') - -One thing to keep in mind is that before and after request handlers have -to be in a file that is imported upfront to work properly on the first -request. The same goes for any kind of remaining decorator. diff --git a/app/static/doc/flask-docs/_sources/patterns/mongokit.txt b/app/static/doc/flask-docs/_sources/patterns/mongokit.txt deleted file mode 100644 index a9c4eef..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/mongokit.txt +++ /dev/null @@ -1,144 +0,0 @@ -.. mongokit-pattern: - -MongoKit in Flask -================= - -Using a document database rather than a full DBMS gets more common these days. -This pattern shows how to use MongoKit, a document mapper library, to -integrate with MongoDB. - -This pattern requires a running MongoDB server and the MongoKit library -installed. - -There are two very common ways to use MongoKit. I will outline each of them -here: - - -Declarative ------------ - -The default behaviour of MongoKit is the declarative one that is based on -common ideas from Django or the SQLAlchemy declarative extension. - -Here an example `app.py` module for your application:: - - from flask import Flask - from mongokit import Connection, Document - - # configuration - MONGODB_HOST = 'localhost' - MONGODB_PORT = 27017 - - # create the little application object - app = Flask(__name__) - app.config.from_object(__name__) - - # connect to the database - connection = Connection(app.config['MONGODB_HOST'], - app.config['MONGODB_PORT']) - - -To define your models, just subclass the `Document` class that is imported -from MongoKit. If you've seen the SQLAlchemy pattern you may wonder why we do -not have a session and even do not define a `init_db` function here. On the -one hand, MongoKit does not have something like a session. This sometimes -makes it more to type but also makes it blazingly fast. On the other hand, -MongoDB is schemaless. This means you can modify the data structure from one -insert query to the next without any problem. MongoKit is just schemaless -too, but implements some validation to ensure data integrity. - -Here is an example document (put this also into `app.py`, e.g.):: - - def max_length(length): - def validate(value): - if len(value) <= length: - return True - raise Exception('%s must be at most %s characters long' % length) - return validate - - class User(Document): - structure = { - 'name': unicode, - 'email': unicode, - } - validators = { - 'name': max_length(50), - 'email': max_length(120) - } - use_dot_notation = True - def __repr__(self): - return '' % (self.name) - - # register the User document with our current connection - connection.register([User]) - - -This example shows you how to define your schema (named structure), a -validator for the maximum character length and uses a special MongoKit feature -called `use_dot_notation`. Per default MongoKit behaves like a python -dictionary but with `use_dot_notation` set to `True` you can use your -documents like you use models in nearly any other ORM by using dots to -separate between attributes. - -You can insert entries into the database like this: - ->>> from yourapplication.database import connection ->>> from yourapplication.models import User ->>> collection = connection['test'].users ->>> user = collection.User() ->>> user['name'] = u'admin' ->>> user['email'] = u'admin@localhost' ->>> user.save() - -Note that MongoKit is kinda strict with used column types, you must not use a -common `str` type for either `name` or `email` but unicode. - -Querying is simple as well: - ->>> list(collection.User.find()) -[] ->>> collection.User.find_one({'name': u'admin'}) - - -.. _MongoKit: http://bytebucket.org/namlook/mongokit/ - - -PyMongo Compatibility Layer ---------------------------- - -If you just want to use PyMongo, you can do that with MongoKit as well. You -may use this process if you need the best performance to get. Note that this -example does not show how to couple it with Flask, see the above MongoKit code -for examples:: - - from MongoKit import Connection - - connection = Connection() - -To insert data you can use the `insert` method. We have to get a -collection first, this is somewhat the same as a table in the SQL world. - ->>> collection = connection['test'].users ->>> user = {'name': u'admin', 'email': u'admin@localhost'} ->>> collection.insert(user) - -print list(collection.find()) -print collection.find_one({'name': u'admin'}) - -MongoKit will automatically commit for us. - -To query your database, you use the collection directly: - ->>> list(collection.find()) -[{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'}] ->>> collection.find_one({'name': u'admin'}) -{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'} - -These results are also dict-like objects: - ->>> r = collection.find_one({'name': u'admin'}) ->>> r['email'] -u'admin@localhost' - -For more information about MongoKit, head over to the -`website `_. diff --git a/app/static/doc/flask-docs/_sources/patterns/packages.txt b/app/static/doc/flask-docs/_sources/patterns/packages.txt deleted file mode 100644 index 79fd2c5..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/packages.txt +++ /dev/null @@ -1,115 +0,0 @@ -.. _larger-applications: - -Larger Applications -=================== - -For larger applications it's a good idea to use a package instead of a -module. That is quite simple. Imagine a small application looks like -this:: - - /yourapplication - /yourapplication.py - /static - /style.css - /templates - layout.html - index.html - login.html - ... - -Simple Packages ---------------- - -To convert that into a larger one, just create a new folder -`yourapplication` inside the existing one and move everything below it. -Then rename `yourapplication.py` to `__init__.py`. (Make sure to delete -all `.pyc` files first, otherwise things would most likely break) - -You should then end up with something like that:: - - /yourapplication - /yourapplication - /__init__.py - /static - /style.css - /templates - layout.html - index.html - login.html - ... - -But how do you run your application now? The naive ``python -yourapplication/__init__.py`` will not work. Let's just say that Python -does not want modules in packages to be the startup file. But that is not -a big problem, just add a new file called `runserver.py` next to the inner -`yourapplication` folder with the following contents:: - - from yourapplication import app - app.run(debug=True) - -What did we gain from this? Now we can restructure the application a bit -into multiple modules. The only thing you have to remember is the -following quick checklist: - -1. the `Flask` application object creation has to be in the - `__init__.py` file. That way each module can import it safely and the - `__name__` variable will resolve to the correct package. -2. all the view functions (the ones with a :meth:`~flask.Flask.route` - decorator on top) have to be imported when in the `__init__.py` file. - Not the object itself, but the module it is in. Import the view module - **after the application object is created**. - -Here's an example `__init__.py`:: - - from flask import Flask - app = Flask(__name__) - - import yourapplication.views - -And this is what `views.py` would look like:: - - from yourapplication import app - - @app.route('/') - def index(): - return 'Hello World!' - -You should then end up with something like that:: - - /yourapplication - /runserver.py - /yourapplication - /__init__.py - /views.py - /static - /style.css - /templates - layout.html - index.html - login.html - ... - -.. admonition:: Circular Imports - - Every Python programmer hates them, and yet we just added some: - circular imports (That's when two modules depend on each other. In this - case `views.py` depends on `__init__.py`). Be advised that this is a - bad idea in general but here it is actually fine. The reason for this is - that we are not actually using the views in `__init__.py` and just - ensuring the module is imported and we are doing that at the bottom of - the file. - - There are still some problems with that approach but if you want to use - decorators there is no way around that. Check out the - :ref:`becomingbig` section for some inspiration how to deal with that. - - -.. _working-with-modules: - -Working with Blueprints ------------------------ - -If you have larger applications it's recommended to divide them into -smaller groups where each group is implemented with the help of a -blueprint. For a gentle introduction into this topic refer to the -:ref:`blueprints` chapter of the documentation. diff --git a/app/static/doc/flask-docs/_sources/patterns/sqlalchemy.txt b/app/static/doc/flask-docs/_sources/patterns/sqlalchemy.txt deleted file mode 100644 index 5a33d1f..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/sqlalchemy.txt +++ /dev/null @@ -1,214 +0,0 @@ -.. _sqlalchemy-pattern: - -SQLAlchemy in Flask -=================== - -Many people prefer `SQLAlchemy`_ for database access. In this case it's -encouraged to use a package instead of a module for your flask application -and drop the models into a separate module (:ref:`larger-applications`). -While that is not necessary, it makes a lot of sense. - -There are four very common ways to use SQLAlchemy. I will outline each -of them here: - -Flask-SQLAlchemy Extension --------------------------- - -Because SQLAlchemy is a common database abstraction layer and object -relational mapper that requires a little bit of configuration effort, -there is a Flask extension that handles that for you. This is recommended -if you want to get started quickly. - -You can download `Flask-SQLAlchemy`_ from `PyPI -`_. - -.. _Flask-SQLAlchemy: http://packages.python.org/Flask-SQLAlchemy/ - - -Declarative ------------ - -The declarative extension in SQLAlchemy is the most recent method of using -SQLAlchemy. It allows you to define tables and models in one go, similar -to how Django works. In addition to the following text I recommend the -official documentation on the `declarative`_ extension. - -Here the example `database.py` module for your application:: - - from sqlalchemy import create_engine - from sqlalchemy.orm import scoped_session, sessionmaker - from sqlalchemy.ext.declarative import declarative_base - - engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) - db_session = scoped_session(sessionmaker(autocommit=False, - autoflush=False, - bind=engine)) - Base = declarative_base() - Base.query = db_session.query_property() - - def init_db(): - # import all modules here that might define models so that - # they will be registered properly on the metadata. Otherwise - # you will have to import them first before calling init_db() - import yourapplication.models - Base.metadata.create_all(bind=engine) - -To define your models, just subclass the `Base` class that was created by -the code above. If you are wondering why we don't have to care about -threads here (like we did in the SQLite3 example above with the -:data:`~flask.g` object): that's because SQLAlchemy does that for us -already with the :class:`~sqlalchemy.orm.scoped_session`. - -To use SQLAlchemy in a declarative way with your application, you just -have to put the following code into your application module. Flask will -automatically remove database sessions at the end of the request for you:: - - from yourapplication.database import db_session - - @app.teardown_request - def shutdown_session(exception=None): - db_session.remove() - -Here is an example model (put this into `models.py`, e.g.):: - - from sqlalchemy import Column, Integer, String - from yourapplication.database import Base - - class User(Base): - __tablename__ = 'users' - id = Column(Integer, primary_key=True) - name = Column(String(50), unique=True) - email = Column(String(120), unique=True) - - def __init__(self, name=None, email=None): - self.name = name - self.email = email - - def __repr__(self): - return '' % (self.name) - -To create the database you can use the `init_db` function: - ->>> from yourapplication.database import init_db ->>> init_db() - -You can insert entries into the database like this: - ->>> from yourapplication.database import db_session ->>> from yourapplication.models import User ->>> u = User('admin', 'admin@localhost') ->>> db_session.add(u) ->>> db_session.commit() - -Querying is simple as well: - ->>> User.query.all() -[] ->>> User.query.filter(User.name == 'admin').first() - - -.. _SQLAlchemy: http://www.sqlalchemy.org/ -.. _declarative: - http://www.sqlalchemy.org/docs/orm/extensions/declarative.html - -Manual Object Relational Mapping --------------------------------- - -Manual object relational mapping has a few upsides and a few downsides -versus the declarative approach from above. The main difference is that -you define tables and classes separately and map them together. It's more -flexible but a little more to type. In general it works like the -declarative approach, so make sure to also split up your application into -multiple modules in a package. - -Here is an example `database.py` module for your application:: - - from sqlalchemy import create_engine, MetaData - from sqlalchemy.orm import scoped_session, sessionmaker - - engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) - metadata = MetaData() - db_session = scoped_session(sessionmaker(autocommit=False, - autoflush=False, - bind=engine)) - def init_db(): - metadata.create_all(bind=engine) - -As for the declarative approach you need to close the session after -each request. Put this into your application module:: - - from yourapplication.database import db_session - - @app.teardown_request - def shutdown_session(exception=None): - db_session.remove() - -Here is an example table and model (put this into `models.py`):: - - from sqlalchemy import Table, Column, Integer, String - from sqlalchemy.orm import mapper - from yourapplication.database import metadata, db_session - - class User(object): - query = db_session.query_property() - - def __init__(self, name=None, email=None): - self.name = name - self.email = email - - def __repr__(self): - return '' % (self.name, self.email) - - users = Table('users', metadata, - Column('id', Integer, primary_key=True), - Column('name', String(50), unique=True), - Column('email', String(120), unique=True) - ) - mapper(User, users) - -Querying and inserting works exactly the same as in the example above. - - -SQL Abstraction Layer ---------------------- - -If you just want to use the database system (and SQL) abstraction layer -you basically only need the engine:: - - from sqlalchemy import create_engine, MetaData - - engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) - metadata = MetaData(bind=engine) - -Then you can either declare the tables in your code like in the examples -above, or automatically load them:: - - users = Table('users', metadata, autoload=True) - -To insert data you can use the `insert` method. We have to get a -connection first so that we can use a transaction: - ->>> con = engine.connect() ->>> con.execute(users.insert(name='admin', email='admin@localhost')) - -SQLAlchemy will automatically commit for us. - -To query your database, you use the engine directly or use a connection: - ->>> users.select(users.c.id == 1).execute().first() -(1, u'admin', u'admin@localhost') - -These results are also dict-like tuples: - ->>> r = users.select(users.c.id == 1).execute().first() ->>> r['name'] -u'admin' - -You can also pass strings of SQL statements to the -:meth:`~sqlalchemy.engine.base.Connection.execute` method: - ->>> engine.execute('select * from users where id = :1', [1]).first() -(1, u'admin', u'admin@localhost') - -For more information about SQLAlchemy, head over to the -`website `_. diff --git a/app/static/doc/flask-docs/_sources/patterns/sqlite3.txt b/app/static/doc/flask-docs/_sources/patterns/sqlite3.txt deleted file mode 100644 index 0d02e46..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/sqlite3.txt +++ /dev/null @@ -1,119 +0,0 @@ -.. _sqlite3: - -Using SQLite 3 with Flask -========================= - -In Flask you can implement the opening of database connections at the -beginning of the request and closing at the end with the -:meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.teardown_request` -decorators in combination with the special :class:`~flask.g` object. - -So here is a simple example of how you can use SQLite 3 with Flask:: - - import sqlite3 - from flask import g - - DATABASE = '/path/to/database.db' - - def connect_db(): - return sqlite3.connect(DATABASE) - - @app.before_request - def before_request(): - g.db = connect_db() - - @app.teardown_request - def teardown_request(exception): - if hasattr(g, 'db'): - g.db.close() - -.. note:: - - Please keep in mind that the teardown request functions are always - executed, even if a before-request handler failed or was never - executed. Because of this we have to make sure here that the database - is there before we close it. - -Connect on Demand ------------------ - -The downside of this approach is that this will only work if Flask -executed the before-request handlers for you. If you are attempting to -use the database from a script or the interactive Python shell you would -have to do something like this:: - - with app.test_request_context(): - app.preprocess_request() - # now you can use the g.db object - -In order to trigger the execution of the connection code. You won't be -able to drop the dependency on the request context this way, but you could -make it so that the application connects when necessary:: - - def get_connection(): - db = getattr(g, '_db', None) - if db is None: - db = g._db = connect_db() - return db - -Downside here is that you have to use ``db = get_connection()`` instead of -just being able to use ``g.db`` directly. - -.. _easy-querying: - -Easy Querying -------------- - -Now in each request handling function you can access `g.db` to get the -current open database connection. To simplify working with SQLite, a -helper function can be useful:: - - def query_db(query, args=(), one=False): - cur = g.db.execute(query, args) - rv = [dict((cur.description[idx][0], value) - for idx, value in enumerate(row)) for row in cur.fetchall()] - return (rv[0] if rv else None) if one else rv - -This handy little function makes working with the database much more -pleasant than it is by just using the raw cursor and connection objects. - -Here is how you can use it:: - - for user in query_db('select * from users'): - print user['username'], 'has the id', user['user_id'] - -Or if you just want a single result:: - - user = query_db('select * from users where username = ?', - [the_username], one=True) - if user is None: - print 'No such user' - else: - print the_username, 'has the id', user['user_id'] - -To pass variable parts to the SQL statement, use a question mark in the -statement and pass in the arguments as a list. Never directly add them to -the SQL statement with string formatting because this makes it possible -to attack the application using `SQL Injections -`_. - -Initial Schemas ---------------- - -Relational databases need schemas, so applications often ship a -`schema.sql` file that creates the database. It's a good idea to provide -a function that creates the database based on that schema. This function -can do that for you:: - - from contextlib import closing - - def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - -You can then create such a database from the python shell: - ->>> from yourapplication import init_db ->>> init_db() diff --git a/app/static/doc/flask-docs/_sources/patterns/streaming.txt b/app/static/doc/flask-docs/_sources/patterns/streaming.txt deleted file mode 100644 index 8393b00..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/streaming.txt +++ /dev/null @@ -1,61 +0,0 @@ -Streaming Contents -================== - -Sometimes you want to send an enormous amount of data to the client, much -more than you want to keep in memory. When you are generating the data on -the fly though, how do you send that back to the client without the -roundtrip to the filesystem? - -The answer is by using generators and direct responses. - -Basic Usage ------------ - -This is a basic view function that generates a lot of CSV data on the fly. -The trick is to have an inner function that uses a generator to generate -data and to then invoke that function and pass it to a response object:: - - from flask import Response - - @app.route('/large.csv') - def generate_large_csv(): - def generate(): - for row in iter_all_rows(): - yield ','.join(row) + '\n' - return Response(generate(), mimetype='text/csv') - -Each ``yield`` expression is directly sent to the browser. Now though -that some WSGI middlewares might break streaming, so be careful there in -debug environments with profilers and other things you might have enabled. - -Streaming from Templates ------------------------- - -The Jinja2 template engine also supports rendering templates piece by -piece. This functionality is not directly exposed by Flask because it is -quite uncommon, but you can easily do it yourself:: - - from flask import Response - - def stream_template(template_name, **context): - app.update_template_context(context) - t = app.jinja_env.get_template(template_name) - rv = t.stream(context) - rv.enable_buffering(5) - return rv - - @app.route('/my-large-page.html') - def render_large_template(): - rows = iter_all_rows() - return Response(stream_template('the_template.html', rows=rows)) - -The trick here is to get the template object from the Jinja2 environment -on the application and to call :meth:`~jinja2.Template.stream` instead of -:meth:`~jinja2.Template.render` which returns a stream object instead of a -string. Since we're bypassing the Flask template render functions and -using the template object itself we have to make sure to update the render -context ourselves by calling :meth:`~flask.Flask.update_template_context`. -The template is then evaluated as the stream is iterated over. Since each -time you do a yield the server will flush the content to the client you -might want to buffer up a few items in the template which you can do with -``rv.enable_buffering(size)``. ``5`` is a sane default. diff --git a/app/static/doc/flask-docs/_sources/patterns/templateinheritance.txt b/app/static/doc/flask-docs/_sources/patterns/templateinheritance.txt deleted file mode 100644 index 70015ec..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/templateinheritance.txt +++ /dev/null @@ -1,69 +0,0 @@ -.. _template-inheritance: - -Template Inheritance -==================== - -The most powerful part of Jinja is template inheritance. Template inheritance -allows you to build a base "skeleton" template that contains all the common -elements of your site and defines **blocks** that child templates can override. - -Sounds complicated but is very basic. It's easiest to understand it by starting -with an example. - - -Base Template -------------- - -This template, which we'll call ``layout.html``, defines a simple HTML skeleton -document that you might use for a simple two-column page. It's the job of -"child" templates to fill the empty blocks with content: - -.. sourcecode:: html+jinja - - - - - {% block head %} - - {% block title %}{% endblock %} - My Webpage - {% endblock %} - - -

{% block content %}{% endblock %}
- - - -In this example, the ``{% block %}`` tags define four blocks that child templates -can fill in. All the `block` tag does is tell the template engine that a -child template may override those portions of the template. - -Child Template --------------- - -A child template might look like this: - -.. sourcecode:: html+jinja - - {% extends "layout.html" %} - {% block title %}Index{% endblock %} - {% block head %} - {{ super() }} - - {% endblock %} - {% block content %} -

Index

-

- Welcome on my awesome homepage. - {% endblock %} - -The ``{% extends %}`` tag is the key here. It tells the template engine that -this template "extends" another template. When the template system evaluates -this template, first it locates the parent. The extends tag must be the -first tag in the template. To render the contents of a block defined in -the parent template, use ``{{ super() }}``. diff --git a/app/static/doc/flask-docs/_sources/patterns/urlprocessors.txt b/app/static/doc/flask-docs/_sources/patterns/urlprocessors.txt deleted file mode 100644 index 778a5a6..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/urlprocessors.txt +++ /dev/null @@ -1,126 +0,0 @@ -Using URL Processors -==================== - -.. versionadded:: 0.7 - -Flask 0.7 introduces the concept of URL processors. The idea is that you -might have a bunch of resources with common parts in the URL that you -don't always explicitly want to provide. For instance you might have a -bunch of URLs that have the language code in it but you don't want to have -to handle it in every single function yourself. - -URL processors are especially helpful when combined with blueprints. We -will handle both application specific URL processors here as well as -blueprint specifics. - -Internationalized Application URLs ----------------------------------- - -Consider an application like this:: - - from flask import Flask, g - - app = Flask(__name__) - - @app.route('//') - def index(lang_code): - g.lang_code = lang_code - ... - - @app.route('//about') - def about(lang_code): - g.lang_code = lang_code - ... - -This is an awful lot of repetition as you have to handle the language code -setting on the :data:`~flask.g` object yourself in every single function. -Sure, a decorator could be used to simplify this, but if you want to -generate URLs from one function to another you would have to still provide -the language code explicitly which can be annoying. - -For the latter, this is where :func:`~flask.Flask.url_defaults` functions -come in. They can automatically inject values into a call for -:func:`~flask.url_for` automatically. The code below checks if the -language code is not yet in the dictionary of URL values and if the -endpoint wants a value named ``'lang_code'``:: - - @app.url_defaults - def add_language_code(endpoint, values): - if 'lang_code' in values or not g.lang_code: - return - if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'): - values['lang_code'] = g.lang_code - -The method :meth:`~werkzeug.routing.Map.is_endpoint_expecting` of the URL -map can be used to figure out if it would make sense to provide a language -code for the given endpoint. - -The reverse of that function are -:meth:`~flask.Flask.url_value_preprocessor`\s. They are executed right -after the request was matched and can execute code based on the URL -values. The idea is that they pull information out of the values -dictionary and put it somewhere else:: - - @app.url_value_preprocessor - def pull_lang_code(endpoint, values): - g.lang_code = values.pop('lang_code', None) - -That way you no longer have to do the `lang_code` assigment to -:data:`~flask.g` in every function. You can further improve that by -writing your own decorator that prefixes URLs with the language code, but -the more beautiful solution is using a blueprint. Once the -``'lang_code'`` is popped from the values dictionary and it will no longer -be forwarded to the view function reducing the code to this:: - - from flask import Flask, g - - app = Flask(__name__) - - @app.url_defaults - def add_language_code(endpoint, values): - if 'lang_code' in values or not g.lang_code: - return - if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'): - values['lang_code'] = g.lang_code - - @app.url_value_preprocessor - def pull_lang_code(endpoint, values): - g.lang_code = values.pop('lang_code', None) - - @app.route('//') - def index(): - ... - - @app.route('//about') - def about(): - ... - -Internationalized Blueprint URLs --------------------------------- - -Because blueprints can automatically prefix all URLs with a common string -it's easy to automatically do that for every function. Furthermore -blueprints can have per-blueprint URL processors which removes a whole lot -of logic from the :meth:`~flask.Flask.url_defaults` function because it no -longer has to check if the URL is really interested in a ``'lang_code'`` -parameter:: - - from flask import Blueprint, g - - bp = Blueprint('frontend', __name__, url_prefix='/') - - @bp.url_defaults - def add_language_code(endpoint, values): - values.setdefault('lang_code', g.lang_code) - - @bp.url_value_preprocessor - def pull_lang_code(endpoint, values): - g.lang_code = values.pop('lang_code') - - @bp.route('/') - def index(): - ... - - @bp.route('/about') - def about(): - ... diff --git a/app/static/doc/flask-docs/_sources/patterns/viewdecorators.txt b/app/static/doc/flask-docs/_sources/patterns/viewdecorators.txt deleted file mode 100644 index a094857..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/viewdecorators.txt +++ /dev/null @@ -1,168 +0,0 @@ -View Decorators -=============== - -Python has a really interesting feature called function decorators. This -allow some really neat things for web applications. Because each view in -Flask is a function decorators can be used to inject additional -functionality to one or more functions. The :meth:`~flask.Flask.route` -decorator is the one you probably used already. But there are use cases -for implementing your own decorator. For instance, imagine you have a -view that should only be used by people that are logged in to. If a user -goes to the site and is not logged in, they should be redirected to the -login page. This is a good example of a use case where a decorator is an -excellent solution. - -Login Required Decorator ------------------------- - -So let's implement such a decorator. A decorator is a function that -returns a function. Pretty simple actually. The only thing you have to -keep in mind when implementing something like this is to update the -`__name__`, `__module__` and some other attributes of a function. This is -often forgotten, but you don't have to do that by hand, there is a -function for that that is used like a decorator (:func:`functools.wraps`). - -This example assumes that the login page is called ``'login'`` and that -the current user is stored as `g.user` and `None` if there is no-one -logged in:: - - from functools import wraps - from flask import g, request, redirect, url_for - - def login_required(f): - @wraps(f) - def decorated_function(*args, **kwargs): - if g.user is None: - return redirect(url_for('login', next=request.url)) - return f(*args, **kwargs) - return decorated_function - -So how would you use that decorator now? Apply it as innermost decorator -to a view function. When applying further decorators, always remember -that the :meth:`~flask.Flask.route` decorator is the outermost:: - - @app.route('/secret_page') - @login_required - def secret_page(): - pass - -Caching Decorator ------------------ - -Imagine you have a view function that does an expensive calculation and -because of that you would like to cache the generated results for a -certain amount of time. A decorator would be nice for that. We're -assuming you have set up a cache like mentioned in :ref:`caching-pattern`. - -Here an example cache function. It generates the cache key from a -specific prefix (actually a format string) and the current path of the -request. Notice that we are using a function that first creates the -decorator that then decorates the function. Sounds awful? Unfortunately -it is a little bit more complex, but the code should still be -straightforward to read. - -The decorated function will then work as follows - -1. get the unique cache key for the current request base on the current - path. -2. get the value for that key from the cache. If the cache returned - something we will return that value. -3. otherwise the original function is called and the return value is - stored in the cache for the timeout provided (by default 5 minutes). - -Here the code:: - - from functools import wraps - from flask import request - - def cached(timeout=5 * 60, key='view/%s'): - def decorator(f): - @wraps(f) - def decorated_function(*args, **kwargs): - cache_key = key % request.path - rv = cache.get(cache_key) - if rv is not None: - return rv - rv = f(*args, **kwargs) - cache.set(cache_key, rv, timeout=timeout) - return rv - return decorated_function - return decorator - -Notice that this assumes an instantiated `cache` object is available, see -:ref:`caching-pattern` for more information. - - -Templating Decorator --------------------- - -A common pattern invented by the TurboGears guys a while back is a -templating decorator. The idea of that decorator is that you return a -dictionary with the values passed to the template from the view function -and the template is automatically rendered. With that, the following -three examples do exactly the same:: - - @app.route('/') - def index(): - return render_template('index.html', value=42) - - @app.route('/') - @templated('index.html') - def index(): - return dict(value=42) - - @app.route('/') - @templated() - def index(): - return dict(value=42) - -As you can see, if no template name is provided it will use the endpoint -of the URL map with dots converted to slashes + ``'.html'``. Otherwise -the provided template name is used. When the decorated function returns, -the dictionary returned is passed to the template rendering function. If -`None` is returned, an empty dictionary is assumed, if something else than -a dictionary is returned we return it from the function unchanged. That -way you can still use the redirect function or return simple strings. - -Here the code for that decorator:: - - from functools import wraps - from flask import request - - def templated(template=None): - def decorator(f): - @wraps(f) - def decorated_function(*args, **kwargs): - template_name = template - if template_name is None: - template_name = request.endpoint \ - .replace('.', '/') + '.html' - ctx = f(*args, **kwargs) - if ctx is None: - ctx = {} - elif not isinstance(ctx, dict): - return ctx - return render_template(template_name, **ctx) - return decorated_function - return decorator - - -Endpoint Decorator ------------------- - -When you want to use the werkzeug routing system for more flexibility you -need to map the endpoint as defined in the :class:`~werkzeug.routing.Rule` -to a view function. This is possible with this decorator. For example:: - - from flask import Flask - from werkzeug.routing import Rule - - app = Flask(__name__) - app.url_map.add(Rule('/', endpoint='index')) - - @app.endpoint('index') - def my_index(): - return "Hello world" - - - diff --git a/app/static/doc/flask-docs/_sources/patterns/wtforms.txt b/app/static/doc/flask-docs/_sources/patterns/wtforms.txt deleted file mode 100644 index 93824df..0000000 --- a/app/static/doc/flask-docs/_sources/patterns/wtforms.txt +++ /dev/null @@ -1,124 +0,0 @@ -Form Validation with WTForms -============================ - -When you have to work with form data submitted by a browser view code -quickly becomes very hard to read. There are libraries out there designed -to make this process easier to manage. One of them is `WTForms`_ which we -will handle here. If you find yourself in the situation of having many -forms, you might want to give it a try. - -When you are working with WTForms you have to define your forms as classes -first. I recommend breaking up the application into multiple modules -(:ref:`larger-applications`) for that and adding a separate module for the -forms. - -.. admonition:: Getting most of WTForms with an Extension - - The `Flask-WTF`_ extension expands on this pattern and adds a few - handful little helpers that make working with forms and Flask more - fun. You can get it from `PyPI - `_. - -.. _Flask-WTF: http://packages.python.org/Flask-WTF/ - -The Forms ---------- - -This is an example form for a typical registration page:: - - from wtforms import Form, BooleanField, TextField, validators - - class RegistrationForm(Form): - username = TextField('Username', [validators.Length(min=4, max=25)]) - email = TextField('Email Address', [validators.Length(min=6, max=35)]) - password = PasswordField('New Password', [ - validators.Required(), - validators.EqualTo('confirm', message='Passwords must match') - ]) - confirm = PasswordField('Repeat Password') - accept_tos = BooleanField('I accept the TOS', [validators.Required()]) - -In the View ------------ - -In the view function, the usage of this form looks like this:: - - @app.route('/register', methods=['GET', 'POST']) - def register(): - form = RegistrationForm(request.form) - if request.method == 'POST' and form.validate(): - user = User(form.username.data, form.email.data, - form.password.data) - db_session.add(user) - flash('Thanks for registering') - return redirect(url_for('login')) - return render_template('register.html', form=form) - -Notice that we are implying that the view is using SQLAlchemy here -(:ref:`sqlalchemy-pattern`) but this is no requirement of course. Adapt -the code as necessary. - -Things to remember: - -1. create the form from the request :attr:`~flask.request.form` value if - the data is submitted via the HTTP `POST` method and - :attr:`~flask.request.args` if the data is submitted as `GET`. -2. to validate the data, call the :func:`~wtforms.form.Form.validate` - method which will return `True` if the data validates, `False` - otherwise. -3. to access individual values from the form, access `form..data`. - -Forms in Templates ------------------- - -Now to the template side. When you pass the form to the templates you can -easily render them there. Look at the following example template to see -how easy this is. WTForms does half the form generation for us already. -To make it even nicer, we can write a macro that renders a field with -label and a list of errors if there are any. - -Here's an example `_formhelpers.html` template with such a macro: - -.. sourcecode:: html+jinja - - {% macro render_field(field) %} -

{{ field.label }} -
{{ field(**kwargs)|safe }} - {% if field.errors %} -
    - {% for error in field.errors %}
  • {{ error }}{% endfor %} -
- {% endif %} -
- {% endmacro %} - -This macro accepts a couple of keyword arguments that are forwarded to -WTForm's field function that renders the field for us. The keyword -arguments will be inserted as HTML attributes. So for example you can -call ``render_field(form.username, class='username')`` to add a class to -the input element. Note that WTForms returns standard Python unicode -strings, so we have to tell Jinja2 that this data is already HTML escaped -with the `|safe` filter. - -Here the `register.html` template for the function we used above which -takes advantage of the `_formhelpers.html` template: - -.. sourcecode:: html+jinja - - {% from "_formhelpers.html" import render_field %} -
-
- {{ render_field(form.username) }} - {{ render_field(form.email) }} - {{ render_field(form.password) }} - {{ render_field(form.confirm) }} - {{ render_field(form.accept_tos) }} -
-

-

- -For more information about WTForms, head over to the `WTForms -website`_. - -.. _WTForms: http://wtforms.simplecodes.com/ -.. _WTForms website: http://wtforms.simplecodes.com/ diff --git a/app/static/doc/flask-docs/_sources/quickstart.txt b/app/static/doc/flask-docs/_sources/quickstart.txt deleted file mode 100644 index 34aa3be..0000000 --- a/app/static/doc/flask-docs/_sources/quickstart.txt +++ /dev/null @@ -1,824 +0,0 @@ -.. _quickstart: - -Quickstart -========== - -Eager to get started? This page gives a good introduction in how to get -started with Flask. This assumes you already have Flask installed. If -you do not, head over to the :ref:`installation` section. - - -A Minimal Application ---------------------- - -A minimal Flask application looks something like this:: - - from flask import Flask - app = Flask(__name__) - - @app.route('/') - def hello_world(): - return 'Hello World!' - - if __name__ == '__main__': - app.run() - -Just save it as `hello.py` or something similar and run it with your -Python interpreter. Make sure to not call your application `flask.py` -because this would conflict with Flask itself. - -:: - - $ python hello.py - * Running on http://127.0.0.1:5000/ - -Head over to `http://127.0.0.1:5000/ `_, you should -see your hello world greeting. - -So what did that code do? - -1. First we imported the :class:`~flask.Flask` class. An instance of this - class will be our WSGI application. The first argument is the name of - the application's module. If you are using a single module (like here) - you should use `__name__` because depending on if it's started as - application or imported as module the name will be different - (``'__main__'`` versus the actual import name). For more information - on that, have a look at the :class:`~flask.Flask` documentation. -2. Next we create an instance of it. We pass it the name of the module / - package. This is needed so that Flask knows where it should look for - templates, static files and so on. -3. Then we use the :meth:`~flask.Flask.route` decorator to tell Flask - what URL should trigger our function. -4. The function then has a name which is also used to generate URLs to - that particular function, and returns the message we want to display in - the user's browser. -5. Finally we use the :meth:`~flask.Flask.run` function to run the - local server with our application. The ``if __name__ == '__main__':`` - makes sure the server only runs if the script is executed directly from - the Python interpreter and not used as imported module. - -To stop the server, hit control-C. - -.. _public-server: - -.. admonition:: Externally Visible Server - - If you run the server you will notice that the server is only available - from your own computer, not from any other in the network. This is the - default because in debugging mode a user of the application can execute - arbitrary Python code on your computer. If you have `debug` disabled - or trust the users on your network, you can make the server publicly - available. - - Just change the call of the :meth:`~flask.Flask.run` method to look - like this:: - - app.run(host='0.0.0.0') - - This tells your operating system to listen on a public IP. - - -Debug Mode ----------- - -The :meth:`~flask.Flask.run` method is nice to start a local -development server, but you would have to restart it manually after each -change you do to code. That is not very nice and Flask can do better. If -you enable the debug support the server will reload itself on code changes -and also provide you with a helpful debugger if things go wrong. - -There are two ways to enable debugging. Either set that flag on the -application object:: - - app.debug = True - app.run() - -Or pass it to run:: - - app.run(debug=True) - -Both will have exactly the same effect. - -.. admonition:: Attention - - Even though the interactive debugger does not work in forking environments - (which makes it nearly impossible to use on production servers), it still - allows the execution of arbitrary code. That makes it a major security - risk and therefore it **must never be used on production machines**. - -Screenshot of the debugger in action: - -.. image:: _static/debugger.png - :align: center - :class: screenshot - :alt: screenshot of debugger in action - -.. admonition:: Working With Other Debuggers - - Debuggers interfere with each other. If you are using another debugger - (e.g. PyDev or IntelliJ), you may need to set ``app.debug = False``. - - -Routing -------- - -Modern web applications have beautiful URLs. This helps people remember -the URLs which is especially handy for applications that are used from -mobile devices with slower network connections. If the user can directly -go to the desired page without having to hit the index page it is more -likely they will like the page and come back next time. - -As you have seen above, the :meth:`~flask.Flask.route` decorator is used -to bind a function to a URL. Here are some basic examples:: - - @app.route('/') - def index(): - return 'Index Page' - - @app.route('/hello') - def hello(): - return 'Hello World' - -But there is more to it! You can make certain parts of the URL dynamic -and attach multiple rules to a function. - -Variable Rules -`````````````` - -To add variable parts to a URL you can mark these special sections as -````. Such a part is then passed as keyword argument to -your function. Optionally a converter can be specified by specifying a -rule with ````. Here are some nice examples:: - - @app.route('/user/') - def show_user_profile(username): - # show the user profile for that user - pass - - @app.route('/post/') - def show_post(post_id): - # show the post with the given id, the id is an integer - pass - -The following converters exist: - -=========== =========================================== -`int` accepts integers -`float` like `int` but for floating point values -`path` like the default but also accepts slashes -=========== =========================================== - -.. admonition:: Unique URLs / Redirection Behaviour - - Flask's URL rules are based on Werkzeug's routing module. The idea - behind that module is to ensure nice looking and also unique URLs based - on behaviour Apache and earlier servers coined. - - Take these two rules:: - - @app.route('/projects/') - def projects(): - pass - - @app.route('/about') - def about(): - pass - - They look rather similar, the difference is the trailing slash in the - URL *definition*. In the first case, the canonical URL for the - `projects` endpoint has a trailing slash. It's similar to a folder in - that sense. Accessing it without a trailing slash will cause Flask to - redirect to the canonical URL with the trailing slash. - - However in the second case the URL is defined without a slash so it - behaves similar to a file and accessing the URL with a trailing slash - will be a 404 error. - - Why is this? This allows relative URLs to continue working if users - access the page when they forget a trailing slash. This behaviour is - also consistent with how Apache and other servers work. Also, the URLs - will stay unique which helps search engines not indexing the same page - twice. - - -.. _url-building: - -URL Building -```````````` - -If it can match URLs, can it also generate them? Of course it can. To -build a URL to a specific function you can use the :func:`~flask.url_for` -function. It accepts the name of the function as first argument and a -number of keyword arguments, each corresponding to the variable part of -the URL rule. Unknown variable parts are appended to the URL as query -parameter. Here are some examples: - ->>> from flask import Flask, url_for ->>> app = Flask(__name__) ->>> @app.route('/') -... def index(): pass -... ->>> @app.route('/login') -... def login(): pass -... ->>> @app.route('/user/') -... def profile(username): pass -... ->>> with app.test_request_context(): -... print url_for('index') -... print url_for('login') -... print url_for('login', next='/') -... print url_for('profile', username='John Doe') -... -/ -/login -/login?next=/ -/user/John%20Doe - -(This also uses the :meth:`~flask.Flask.test_request_context` method -explained below. It basically tells Flask to think we are handling a -request even though we are not, we are in an interactive Python shell. -Have a look at the explanation below. :ref:`context-locals`). - -Why would you want to build URLs instead of hardcoding them in your -templates? There are three good reasons for this: - -1. reversing is often more descriptive than hardcoding the URLs. Also and - more importantly you can change URLs in one go without having to change - the URLs all over the place. -2. URL building will handle escaping of special characters and Unicode - data transparently for you, you don't have to deal with that. -3. If your application is placed outside the URL root (so say in - ``/myapplication`` instead of ``/``), :func:`~flask.url_for` will - handle that properly for you. - - -HTTP Methods -```````````` - -HTTP (the protocol web applications are speaking) knows different methods -to access URLs. By default a route only answers to `GET` requests, but -that can be changed by providing the `methods` argument to the -:meth:`~flask.Flask.route` decorator. Here are some examples:: - - @app.route('/login', methods=['GET', 'POST']) - def login(): - if request.method == 'POST': - do_the_login() - else: - show_the_login_form() - -If `GET` is present, `HEAD` will be added automatically for you. You -don't have to deal with that. It will also make sure that `HEAD` requests -are handled like the `HTTP RFC`_ (the document describing the HTTP -protocol) demands, so you can completely ignore that part of the HTTP -specification. Likewise as of Flask 0.6, `OPTIONS` is implemented for you -as well automatically. - -You have no idea what an HTTP method is? Worry not, here is a quick -introduction to HTTP methods and why they matter: - -The HTTP method (also often called "the verb") tells the server what the -clients wants to *do* with the requested page. The following methods are -very common: - -`GET` - The browser tells the server to just *get* the information stored on - that page and send it. This is probably the most common method. - -`HEAD` - The browser tells the server to get the information, but it is only - interested in the *headers*, not the content of the page. An - application is supposed to handle that as if a `GET` request was - received but to not deliver the actual content. In Flask you don't - have to deal with that at all, the underlying Werkzeug library handles - that for you. - -`POST` - The browser tells the server that it wants to *post* some new - information to that URL and that the server must ensure the data is - stored and only stored once. This is how HTML forms are usually - transmitting data to the server. - -`PUT` - Similar to `POST` but the server might trigger the store procedure - multiple times by overwriting the old values more than once. Now you - might be asking why is this useful, but there are some good reasons - to do it this way. Consider that the connection gets lost during - transmission: in this situation a system between the browser and the - server might receive the request safely a second time without breaking - things. With `POST` that would not be possible because it must only - be triggered once. - -`DELETE` - Remove the information at the given location. - -`OPTIONS` - Provides a quick way for a client to figure out which methods are - supported by this URL. Starting with Flask 0.6, this is implemented - for you automatically. - -Now the interesting part is that in HTML4 and XHTML1, the only methods a -form can submit to the server are `GET` and `POST`. But with JavaScript -and future HTML standards you can use the other methods as well. Furthermore -HTTP has become quite popular lately and browsers are no longer the only -clients that are using HTTP. For instance, many revision control system -use it. - -.. _HTTP RFC: http://www.ietf.org/rfc/rfc2068.txt - -Static Files ------------- - -Dynamic web applications need static files as well. That's usually where -the CSS and JavaScript files are coming from. Ideally your web server is -configured to serve them for you, but during development Flask can do that -as well. Just create a folder called `static` in your package or next to -your module and it will be available at `/static` on the application. - -To generate URLs to that part of the URL, use the special ``'static'`` URL -name:: - - url_for('static', filename='style.css') - -The file has to be stored on the filesystem as ``static/style.css``. - -Rendering Templates -------------------- - -Generating HTML from within Python is not fun, and actually pretty -cumbersome because you have to do the HTML escaping on your own to keep -the application secure. Because of that Flask configures the `Jinja2 -`_ template engine for you automatically. - -To render a template you can use the :func:`~flask.render_template` -method. All you have to do is to provide the name of the template and the -variables you want to pass to the template engine as keyword arguments. -Here's a simple example of how to render a template:: - - from flask import render_template - - @app.route('/hello/') - @app.route('/hello/') - def hello(name=None): - return render_template('hello.html', name=name) - -Flask will look for templates in the `templates` folder. So if your -application is a module, that folder is next to that module, if it's a -package it's actually inside your package: - -**Case 1**: a module:: - - /application.py - /templates - /hello.html - -**Case 2**: a package:: - - /application - /__init__.py - /templates - /hello.html - -For templates you can use the full power of Jinja2 templates. Head over -to the the official `Jinja2 Template Documentation -`_ for more information. - -Here is an example template: - -.. sourcecode:: html+jinja - - - Hello from Flask - {% if name %} -

Hello {{ name }}!

- {% else %} -

Hello World!

- {% endif %} - -Inside templates you also have access to the :class:`~flask.request`, -:class:`~flask.session` and :class:`~flask.g` [#]_ objects -as well as the :func:`~flask.get_flashed_messages` function. - -Templates are especially useful if inheritance is used. If you want to -know how that works, head over to the :ref:`template-inheritance` pattern -documentation. Basically template inheritance makes it possible to keep -certain elements on each page (like header, navigation and footer). - -Automatic escaping is enabled, so if name contains HTML it will be escaped -automatically. If you can trust a variable and you know that it will be -safe HTML (because for example it came from a module that converts wiki -markup to HTML) you can mark it as safe by using the -:class:`~jinja2.Markup` class or by using the ``|safe`` filter in the -template. Head over to the Jinja 2 documentation for more examples. - -Here is a basic introduction to how the :class:`~jinja2.Markup` class works: - ->>> from flask import Markup ->>> Markup('Hello %s!') % 'hacker' -Markup(u'Hello <blink>hacker</blink>!') ->>> Markup.escape('hacker') -Markup(u'<blink>hacker</blink>') ->>> Markup('Marked up » HTML').striptags() -u'Marked up \xbb HTML' - -.. versionchanged:: 0.5 - - Autoescaping is no longer enabled for all templates. The following - extensions for templates trigger autoescaping: ``.html``, ``.htm``, - ``.xml``, ``.xhtml``. Templates loaded from a string will have - autoescaping disabled. - -.. [#] Unsure what that :class:`~flask.g` object is? It's something in which - you can store information for your own needs, check the documentation of - that object (:class:`~flask.g`) and the :ref:`sqlite3` for more - information. - - -Accessing Request Data ----------------------- - -For web applications it's crucial to react to the data a client sent to -the server. In Flask this information is provided by the global -:class:`~flask.request` object. If you have some experience with Python -you might be wondering how that object can be global and how Flask -manages to still be threadsafe. The answer are context locals: - - -.. _context-locals: - -Context Locals -`````````````` - -.. admonition:: Insider Information - - If you want to understand how that works and how you can implement - tests with context locals, read this section, otherwise just skip it. - -Certain objects in Flask are global objects, but not of the usual kind. -These objects are actually proxies to objects that are local to a specific -context. What a mouthful. But that is actually quite easy to understand. - -Imagine the context being the handling thread. A request comes in and the -webserver decides to spawn a new thread (or something else, the -underlying object is capable of dealing with other concurrency systems -than threads as well). When Flask starts its internal request handling it -figures out that the current thread is the active context and binds the -current application and the WSGI environments to that context (thread). -It does that in an intelligent way that one application can invoke another -application without breaking. - -So what does this mean to you? Basically you can completely ignore that -this is the case unless you are doing something like unittesting. You -will notice that code that depends on a request object will suddenly break -because there is no request object. The solution is creating a request -object yourself and binding it to the context. The easiest solution for -unittesting is by using the :meth:`~flask.Flask.test_request_context` -context manager. In combination with the `with` statement it will bind a -test request so that you can interact with it. Here is an example:: - - from flask import request - - with app.test_request_context('/hello', method='POST'): - # now you can do something with the request until the - # end of the with block, such as basic assertions: - assert request.path == '/hello' - assert request.method == 'POST' - -The other possibility is passing a whole WSGI environment to the -:meth:`~flask.Flask.request_context` method:: - - from flask import request - - with app.request_context(environ): - assert request.method == 'POST' - -The Request Object -`````````````````` - -The request object is documented in the API section and we will not cover -it here in detail (see :class:`~flask.request`). Here is a broad overview of -some of the most common operations. First of all you have to import it from -the `flask` module:: - - from flask import request - -The current request method is available by using the -:attr:`~flask.request.method` attribute. To access form data (data -transmitted in a `POST` or `PUT` request) you can use the -:attr:`~flask.request.form` attribute. Here is a full example of the two -attributes mentioned above:: - - @app.route('/login', methods=['POST', 'GET']) - def login(): - error = None - if request.method == 'POST': - if valid_login(request.form['username'], - request.form['password']): - return log_the_user_in(request.form['username']) - else: - error = 'Invalid username/password' - # this is executed if the request method was GET or the - # credentials were invalid - -What happens if the key does not exist in the `form` attribute? In that -case a special :exc:`KeyError` is raised. You can catch it like a -standard :exc:`KeyError` but if you don't do that, a HTTP 400 Bad Request -error page is shown instead. So for many situations you don't have to -deal with that problem. - -To access parameters submitted in the URL (``?key=value``) you can use the -:attr:`~flask.request.args` attribute:: - - searchword = request.args.get('q', '') - -We recommend accessing URL parameters with `get` or by catching the -`KeyError` because users might change the URL and presenting them a 400 -bad request page in that case is not user friendly. - -For a full list of methods and attributes of the request object, head over -to the :class:`~flask.request` documentation. - - -File Uploads -```````````` - -You can handle uploaded files with Flask easily. Just make sure not to -forget to set the ``enctype="multipart/form-data"`` attribute on your HTML -form, otherwise the browser will not transmit your files at all. - -Uploaded files are stored in memory or at a temporary location on the -filesystem. You can access those files by looking at the -:attr:`~flask.request.files` attribute on the request object. Each -uploaded file is stored in that dictionary. It behaves just like a -standard Python :class:`file` object, but it also has a -:meth:`~werkzeug.datastructures.FileStorage.save` method that allows you to store that -file on the filesystem of the server. Here is a simple example showing how -that works:: - - from flask import request - - @app.route('/upload', methods=['GET', 'POST']) - def upload_file(): - if request.method == 'POST': - f = request.files['the_file'] - f.save('/var/www/uploads/uploaded_file.txt') - ... - -If you want to know how the file was named on the client before it was -uploaded to your application, you can access the -:attr:`~werkzeug.datastructures.FileStorage.filename` attribute. However please keep in -mind that this value can be forged so never ever trust that value. If you -want to use the filename of the client to store the file on the server, -pass it through the :func:`~werkzeug.utils.secure_filename` function that -Werkzeug provides for you:: - - from flask import request - from werkzeug import secure_filename - - @app.route('/upload', methods=['GET', 'POST']) - def upload_file(): - if request.method == 'POST': - f = request.files['the_file'] - f.save('/var/www/uploads/' + secure_filename(f.filename)) - ... - -For some better examples, checkout the :ref:`uploading-files` pattern. - -Cookies -``````` - -To access cookies you can use the :attr:`~flask.Request.cookies` -attribute. To set cookies you can use the -:attr:`~flask.Response.set_cookie` method of response objects. The -:attr:`~flask.Request.cookies` attribute of request objects is a -dictionary with all the cookies the client transmits. If you want to use -sessions, do not use the cookies directly but instead use the -:ref:`sessions` in Flask that add some security on top of cookies for you. - -Reading cookies:: - - from flask import request - - @app.route('/') - def index(): - username = request.cookies.get('username') - # use cookies.get(key) instead of cookies[key] to not get a - # KeyError if the cookie is missing. - -Storing cookies:: - - from flask import make_response - - @app.route('/') - def index(): - resp = make_response(render_template(...)) - resp.set_cookie('username', 'the username') - return resp - -Note that cookies are set on response objects. Since you normally you -just return strings from the view functions Flask will convert them into -response objects for you. If you explicitly want to do that you can use -the :meth:`~flask.make_response` function and then modify it. - -Sometimes you might want to set a cookie at a point where the response -object does not exist yet. This is possible by utilizing the -:ref:`deferred-callbacks` pattern. - -For this also see :ref:`about-responses`. - -Redirects and Errors --------------------- - -To redirect a user to somewhere else you can use the -:func:`~flask.redirect` function. To abort a request early with an error -code use the :func:`~flask.abort` function. Here an example how this works:: - - from flask import abort, redirect, url_for - - @app.route('/') - def index(): - return redirect(url_for('login')) - - @app.route('/login') - def login(): - abort(401) - this_is_never_executed() - -This is a rather pointless example because a user will be redirected from -the index to a page they cannot access (401 means access denied) but it -shows how that works. - -By default a black and white error page is shown for each error code. If -you want to customize the error page, you can use the -:meth:`~flask.Flask.errorhandler` decorator:: - - from flask import render_template - - @app.errorhandler(404) - def page_not_found(error): - return render_template('page_not_found.html'), 404 - -Note the ``404`` after the :func:`~flask.render_template` call. This -tells Flask that the status code of that page should be 404 which means -not found. By default 200 is assumed which translates to: all went well. - -.. _about-responses: - -About Responses ---------------- - -The return value from a view function is automatically converted into a -response object for you. If the return value is a string it's converted -into a response object with the string as response body, an ``200 OK`` -error code and a ``text/html`` mimetype. The logic that Flask applies to -converting return values into response objects is as follows: - -1. If a response object of the correct type is returned it's directly - returned from the view. -2. If it's a string, a response object is created with that data and the - default parameters. -3. If a tuple is returned the response object is created by passing the - tuple as arguments to the response object's constructor. -4. If neither of that works, Flask will assume the return value is a - valid WSGI application and converts that into a response object. - -If you want to get hold of the resulting response object inside the view -you can use the :func:`~flask.make_response` function. - -Imagine you have a view like this: - -.. sourcecode:: python - - @app.errorhandler(404) - def not_found(error): - return render_template('error.html'), 404 - -You just need to wrap the return expression with -:func:`~flask.make_response` and get the result object to modify it, then -return it: - -.. sourcecode:: python - - @app.errorhandler(404) - def not_found(error): - resp = make_response(render_template('error.html'), 404) - resp.headers['X-Something'] = 'A value' - return resp - -.. _sessions: - -Sessions --------- - -Besides the request object there is also a second object called -:class:`~flask.session` that allows you to store information specific to a -user from one request to the next. This is implemented on top of cookies -for you and signs the cookies cryptographically. What this means is that -the user could look at the contents of your cookie but not modify it, -unless they know the secret key used for signing. - -In order to use sessions you have to set a secret key. Here is how -sessions work:: - - from flask import Flask, session, redirect, url_for, escape, request - - app = Flask(__name__) - - @app.route('/') - def index(): - if 'username' in session: - return 'Logged in as %s' % escape(session['username']) - return 'You are not logged in' - - @app.route('/login', methods=['GET', 'POST']) - def login(): - if request.method == 'POST': - session['username'] = request.form['username'] - return redirect(url_for('index')) - return ''' -
-

-

-

- ''' - - @app.route('/logout') - def logout(): - # remove the username from the session if its there - session.pop('username', None) - return redirect(url_for('index')) - - # set the secret key. keep this really secret: - app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' - -The here mentioned :func:`~flask.escape` does escaping for you if you are -not using the template engine (like in this example). - -.. admonition:: How to generate good secret keys - - The problem with random is that it's hard to judge what random is. And - a secret key should be as random as possible. Your operating system - has ways to generate pretty random stuff based on a cryptographic - random generator which can be used to get such a key: - - >>> import os - >>> os.urandom(24) - '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O`_ for more -information. - -Hooking in WSGI Middlewares ---------------------------- - -If you want to add a WSGI middleware to your application you can wrap the -internal WSGI application. For example if you want to use one of the -middlewares from the Werkzeug package to work around bugs in lighttpd, you -can do it like this:: - - from werkzeug.contrib.fixers import LighttpdCGIRootFix - app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app) diff --git a/app/static/doc/flask-docs/_sources/reqcontext.txt b/app/static/doc/flask-docs/_sources/reqcontext.txt deleted file mode 100644 index 0249b88..0000000 --- a/app/static/doc/flask-docs/_sources/reqcontext.txt +++ /dev/null @@ -1,239 +0,0 @@ -.. _request-context: - -The Request Context -=================== - -This document describes the behavior in Flask 0.7 which is mostly in line -with the old behavior but has some small, subtle differences. - -One of the design ideas behind Flask is that there are two different -“states” in which code is executed. The application setup state in which -the application implicitly is on the module level. It starts when the -:class:`Flask` object is instantiated, and it implicitly ends when the -first request comes in. While the application is in this state a few -assumptions are true: - -- the programmer can modify the application object safely. -- no request handling happened so far -- you have to have a reference to the application object in order to - modify it, there is no magic proxy that can give you a reference to - the application object you're currently creating or modifying. - -On the contrast, during request handling, a couple of other rules exist: - -- while a request is active, the context local objects - (:data:`flask.request` and others) point to the current request. -- any code can get hold of these objects at any time. - -The magic that makes this works is internally referred in Flask as the -“request context”. - -Diving into Context Locals --------------------------- - -Say you have a utility function that returns the URL the user should be -redirected to. Imagine it would always redirect to the URL's ``next`` -parameter or the HTTP referrer or the index page:: - - from flask import request, url_for - - def redirect_url(): - return request.args.get('next') or \ - request.referrer or \ - url_for('index') - -As you can see, it accesses the request object. If you try to run this -from a plain Python shell, this is the exception you will see: - ->>> redirect_url() -Traceback (most recent call last): - File "", line 1, in -AttributeError: 'NoneType' object has no attribute 'request' - -That makes a lot of sense because we currently do not have a request we -could access. So we have to make a request and bind it to the current -context. The :attr:`~flask.Flask.test_request_context` method can create -us a :class:`~flask.ctx.RequestContext`: - ->>> ctx = app.test_request_context('/?next=http://example.com/') - -This context can be used in two ways. Either with the `with` statement -or by calling the :meth:`~flask.ctx.RequestContext.push` and -:meth:`~flask.ctx.RequestContext.pop` methods: - ->>> ctx.push() - -From that point onwards you can work with the request object: - ->>> redirect_url() -u'http://example.com/' - -Until you call `pop`: - ->>> ctx.pop() - -Because the request context is internally maintained as a stack you can -push and pop multiple times. This is very handy to implement things like -internal redirects. - -For more information of how to utilize the request context from the -interactive Python shell, head over to the :ref:`shell` chapter. - -How the Context Works ---------------------- - -If you look into how the Flask WSGI application internally works, you will -find a piece of code that looks very much like this:: - - def wsgi_app(self, environ): - with self.request_context(environ): - try: - response = self.full_dispatch_request() - except Exception, e: - response = self.make_response(self.handle_exception(e)) - return response(environ, start_response) - -The method :meth:`~Flask.request_context` returns a new -:class:`~flask.ctx.RequestContext` object and uses it in combination with -the `with` statement to bind the context. Everything that is called from -the same thread from this point onwards until the end of the `with` -statement will have access to the request globals (:data:`flask.request` -and others). - -The request context internally works like a stack: The topmost level on -the stack is the current active request. -:meth:`~flask.ctx.RequestContext.push` adds the context to the stack on -the very top, :meth:`~flask.ctx.RequestContext.pop` removes it from the -stack again. On popping the application's -:func:`~flask.Flask.teardown_request` functions are also executed. - -.. _callbacks-and-errors: - -Callbacks and Errors --------------------- - -What happens if an error occurs in Flask during request processing? This -particular behavior changed in 0.7 because we wanted to make it easier to -understand what is actually happening. The new behavior is quite simple: - -1. Before each request, :meth:`~flask.Flask.before_request` functions are - executed. If one of these functions return a response, the other - functions are no longer called. In any case however the return value - is treated as a replacement for the view's return value. - -2. If the :meth:`~flask.Flask.before_request` functions did not return a - response, the regular request handling kicks in and the view function - that was matched has the chance to return a response. - -3. The return value of the view is then converted into an actual response - object and handed over to the :meth:`~flask.Flask.after_request` - functions which have the chance to replace it or modify it in place. - -4. At the end of the request the :meth:`~flask.Flask.teardown_request` - functions are executed. This always happens, even in case of an - unhandled exception down the road or if a before-request handler was - not executed yet or at all (for example in test environments sometimes - you might want to not execute before-request callbacks). - -Now what happens on errors? In production mode if an exception is not -caught, the 500 internal server handler is called. In development mode -however the exception is not further processed and bubbles up to the WSGI -server. That way things like the interactive debugger can provide helpful -debug information. - -An important change in 0.7 is that the internal server error is now no -longer post processed by the after request callbacks and after request -callbacks are no longer guaranteed to be executed. This way the internal -dispatching code looks cleaner and is easier to customize and understand. - -The new teardown functions are supposed to be used as a replacement for -things that absolutely need to happen at the end of request. - -Teardown Callbacks ------------------- - -The teardown callbacks are special callbacks in that they are executed at -at different point. Strictly speaking they are independent of the actual -request handling as they are bound to the lifecycle of the -:class:`~flask.ctx.RequestContext` object. When the request context is -popped, the :meth:`~flask.Flask.teardown_request` functions are called. - -This is important to know if the life of the request context is prolonged -by using the test client in a with statement or when using the request -context from the command line:: - - with app.test_client() as client: - resp = client.get('/foo') - # the teardown functions are still not called at that point - # even though the response ended and you have the response - # object in your hand - - # only when the code reaches this point the teardown functions - # are called. Alternatively the same thing happens if another - # request was triggered from the test client - -It's easy to see the behavior from the command line: - ->>> app = Flask(__name__) ->>> @app.teardown_request -... def teardown_request(exception=None): -... print 'this runs after request' -... ->>> ctx = app.test_request_context() ->>> ctx.push() ->>> ctx.pop() -this runs after request ->>> - -Keep in mind that teardown callbacks are always executed, even if -before-request callbacks were not executed yet but an exception happened. -Certain parts of the test system might also temporarily create a request -context without calling the before-request handlers. Make sure to write -your teardown-request handlers in a way that they will never fail. - -.. _notes-on-proxies: - -Notes On Proxies ----------------- - -Some of the objects provided by Flask are proxies to other objects. The -reason behind this is that these proxies are shared between threads and -they have to dispatch to the actual object bound to a thread behind the -scenes as necessary. - -Most of the time you don't have to care about that, but there are some -exceptions where it is good to know that this object is an actual proxy: - -- The proxy objects do not fake their inherited types, so if you want to - perform actual instance checks, you have to do that on the instance - that is being proxied (see `_get_current_object` below). -- if the object reference is important (so for example for sending - :ref:`signals`) - -If you need to get access to the underlying object that is proxied, you -can use the :meth:`~werkzeug.local.LocalProxy._get_current_object` method:: - - app = current_app._get_current_object() - my_signal.send(app) - -Context Preservation on Error ------------------------------ - -If an error occurs or not, at the end of the request the request context -is popped and all data associated with it is destroyed. During -development however that can be problematic as you might want to have the -information around for a longer time in case an exception occurred. In -Flask 0.6 and earlier in debug mode, if an exception occurred, the -request context was not popped so that the interactive debugger can still -provide you with important information. - -Starting with Flask 0.7 you have finer control over that behavior by -setting the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable. By -default it's linked to the setting of ``DEBUG``. If the application is in -debug mode the context is preserved, in production mode it's not. - -Do not force activate ``PRESERVE_CONTEXT_ON_EXCEPTION`` in production mode -as it will cause your application to leak memory on exceptions. However -it can be useful during development to get the same error preserving -behavior as in development mode when attempting to debug an error that -only occurs under production settings. diff --git a/app/static/doc/flask-docs/_sources/security.txt b/app/static/doc/flask-docs/_sources/security.txt deleted file mode 100644 index 909ef53..0000000 --- a/app/static/doc/flask-docs/_sources/security.txt +++ /dev/null @@ -1,175 +0,0 @@ -Security Considerations -======================= - -Web applications usually face all kinds of security problems and it's very -hard to get everything right. Flask tries to solve a few of these things -for you, but there are a couple more you have to take care of yourself. - -.. _xss: - -Cross-Site Scripting (XSS) --------------------------- - -Cross site scripting is the concept of injecting arbitrary HTML (and with -it JavaScript) into the context of a website. To remedy this, developers -have to properly escape text so that it cannot include arbitrary HTML -tags. For more information on that have a look at the Wikipedia article -on `Cross-Site Scripting -`_. - -Flask configures Jinja2 to automatically escape all values unless -explicitly told otherwise. This should rule out all XSS problems caused -in templates, but there are still other places where you have to be -careful: - -- generating HTML without the help of Jinja2 -- calling :class:`~flask.Markup` on data submitted by users -- sending out HTML from uploaded files, never do that, use the - `Content-Disposition: attachment` header to prevent that problem. -- sending out textfiles from uploaded files. Some browsers are using - content-type guessing based on the first few bytes so users could - trick a browser to execute HTML. - -Another thing that is very important are unquoted attributes. While -Jinja2 can protect you from XSS issues by escaping HTML, there is one -thing it cannot protect you from: XSS by attribute injection. To counter -this possible attack vector, be sure to always quote your attributes with -either double or single quotes when using Jinja expressions in them: - -.. sourcecode:: html+jinja - - the text - -Why is this necessary? Because if you would not be doing that, an -attacker could easily inject custom JavaScript handlers. For example an -attacker could inject this piece of HTML+JavaScript: - -.. sourcecode:: html - - onmouseover=alert(document.cookie) - -When the user would then move with the mouse over the link, the cookie -would be presented to the user in an alert window. But instead of showing -the cookie to the user, a good attacker might also execute any other -JavaScript code. In combination with CSS injections the attacker might -even make the element fill out the entire page so that the user would -just have to have the mouse anywhere on the page to trigger the attack. - -Cross-Site Request Forgery (CSRF) ---------------------------------- - -Another big problem is CSRF. This is a very complex topic and I won't -outline it here in detail just mention what it is and how to theoretically -prevent it. - -If your authentication information is stored in cookies, you have implicit -state management. The state of "being logged in" is controlled by a -cookie, and that cookie is sent with each request to a page. -Unfortunately that includes requests triggered by 3rd party sites. If you -don't keep that in mind, some people might be able to trick your -application's users with social engineering to do stupid things without -them knowing. - -Say you have a specific URL that, when you sent `POST` requests to will -delete a user's profile (say `http://example.com/user/delete`). If an -attacker now creates a page that sends a post request to that page with -some JavaScript they just has to trick some users to load that page and -their profiles will end up being deleted. - -Imagine you were to run Facebook with millions of concurrent users and -someone would send out links to images of little kittens. When users -would go to that page, their profiles would get deleted while they are -looking at images of fluffy cats. - -How can you prevent that? Basically for each request that modifies -content on the server you would have to either use a one-time token and -store that in the cookie **and** also transmit it with the form data. -After receiving the data on the server again, you would then have to -compare the two tokens and ensure they are equal. - -Why does Flask not do that for you? The ideal place for this to happen is -the form validation framework, which does not exist in Flask. - -.. _json-security: - -JSON Security -------------- - -.. admonition:: ECMAScript 5 Changes - - Starting with ECMAScript 5 the behavior of literals changed. Now they - are not constructed with the constructor of ``Array`` and others, but - with the builtin constructor of ``Array`` which closes this particular - attack vector. - -JSON itself is a high-level serialization format, so there is barely -anything that could cause security problems, right? You can't declare -recursive structures that could cause problems and the only thing that -could possibly break are very large responses that can cause some kind of -denial of service at the receiver's side. - -However there is a catch. Due to how browsers work the CSRF issue comes -up with JSON unfortunately. Fortunately there is also a weird part of the -JavaScript specification that can be used to solve that problem easily and -Flask is kinda doing that for you by preventing you from doing dangerous -stuff. Unfortunately that protection is only there for -:func:`~flask.jsonify` so you are still at risk when using other ways to -generate JSON. - -So what is the issue and how to avoid it? The problem are arrays at -top-level in JSON. Imagine you send the following data out in a JSON -request. Say that's exporting the names and email addresses of all your -friends for a part of the user interface that is written in JavaScript. -Not very uncommon: - -.. sourcecode:: javascript - - [ - {"username": "admin", - "email": "admin@localhost"} - ] - -And it is doing that of course only as long as you are logged in and only -for you. And it is doing that for all `GET` requests to a certain URL, -say the URL for that request is -``http://example.com/api/get_friends.json``. - -So now what happens if a clever hacker is embedding this to his website -and social engineers a victim to visiting his site: - -.. sourcecode:: html - - - - - -If you know a bit of JavaScript internals you might know that it's -possible to patch constructors and register callbacks for setters. An -attacker can use this (like above) to get all the data you exported in -your JSON file. The browser will totally ignore the ``application/json`` -mimetype if ``text/javascript`` is defined as content type in the script -tag and evaluate that as JavaScript. Because top-level array elements are -allowed (albeit useless) and we hooked in our own constructor, after that -page loaded the data from the JSON response is in the `captured` array. - -Because it is a syntax error in JavaScript to have an object literal -(``{...}``) toplevel an attacker could not just do a request to an -external URL with the script tag to load up the data. So what Flask does -is to only allow objects as toplevel elements when using -:func:`~flask.jsonify`. Make sure to do the same when using an ordinary -JSON generate function. diff --git a/app/static/doc/flask-docs/_sources/shell.txt b/app/static/doc/flask-docs/_sources/shell.txt deleted file mode 100644 index 61b9dc0..0000000 --- a/app/static/doc/flask-docs/_sources/shell.txt +++ /dev/null @@ -1,93 +0,0 @@ -.. _shell: - -Working with the Shell -====================== - -.. versionadded:: 0.3 - -One of the reasons everybody loves Python is the interactive shell. It -basically allows you to execute Python commands in real time and -immediately get results back. Flask itself does not come with an -interactive shell, because it does not require any specific setup upfront, -just import your application and start playing around. - -There are however some handy helpers to make playing around in the shell a -more pleasant experience. The main issue with interactive console -sessions is that you're not triggering a request like a browser does which -means that :data:`~flask.g`, :data:`~flask.request` and others are not -available. But the code you want to test might depend on them, so what -can you do? - -This is where some helper functions come in handy. Keep in mind however -that these functions are not only there for interactive shell usage, but -also for unittesting and other situations that require a faked request -context. - -Generally it's recommended that you read the :ref:`request-context` -chapter of the documentation first. - -Creating a Request Context --------------------------- - -The easiest way to create a proper request context from the shell is by -using the :attr:`~flask.Flask.test_request_context` method which creates -us a :class:`~flask.ctx.RequestContext`: - ->>> ctx = app.test_request_context() - -Normally you would use the `with` statement to make this request object -active, but in the shell it's easier to use the -:meth:`~flask.ctx.RequestContext.push` and -:meth:`~flask.ctx.RequestContext.pop` methods by hand: - ->>> ctx.push() - -From that point onwards you can work with the request object until you -call `pop`: - ->>> ctx.pop() - -Firing Before/After Request ---------------------------- - -By just creating a request context, you still don't have run the code that -is normally run before a request. This might result in your database -being unavailable if you are connecting to the database in a -before-request callback or the current user not being stored on the -:data:`~flask.g` object etc. - -This however can easily be done yourself. Just call -:meth:`~flask.Flask.preprocess_request`: - ->>> ctx = app.test_request_context() ->>> ctx.push() ->>> app.preprocess_request() - -Keep in mind that the :meth:`~flask.Flask.preprocess_request` function -might return a response object, in that case just ignore it. - -To shutdown a request, you need to trick a bit before the after request -functions (triggered by :meth:`~flask.Flask.process_response`) operate on -a response object: - ->>> app.process_response(app.response_class()) - ->>> ctx.pop() - -The functions registered as :meth:`~flask.Flask.teardown_request` are -automatically called when the context is popped. So this is the perfect -place to automatically tear down resources that were needed by the request -context (such as database connections). - - -Further Improving the Shell Experience --------------------------------------- - -If you like the idea of experimenting in a shell, create yourself a module -with stuff you want to star import into your interactive session. There -you could also define some more helper methods for common things such as -initializing the database, dropping tables etc. - -Just put them into a module (like `shelltools` and import from there): - ->>> from shelltools import * diff --git a/app/static/doc/flask-docs/_sources/signals.txt b/app/static/doc/flask-docs/_sources/signals.txt deleted file mode 100644 index 0d1d9ee..0000000 --- a/app/static/doc/flask-docs/_sources/signals.txt +++ /dev/null @@ -1,255 +0,0 @@ -.. _signals: - -Signals -======= - -.. versionadded:: 0.6 - -Starting with Flask 0.6, there is integrated support for signalling in -Flask. This support is provided by the excellent `blinker`_ library and -will gracefully fall back if it is not available. - -What are signals? Signals help you decouple applications by sending -notifications when actions occur elsewhere in the core framework or -another Flask extensions. In short, signals allow certain senders to -notify subscribers that something happened. - -Flask comes with a couple of signals and other extensions might provide -more. Also keep in mind that signals are intended to notify subscribers -and should not encourage subscribers to modify data. You will notice that -there are signals that appear to do the same thing like some of the -builtin decorators do (eg: :data:`~flask.request_started` is very similar -to :meth:`~flask.Flask.before_request`). There are however difference in -how they work. The core :meth:`~flask.Flask.before_request` handler for -example is executed in a specific order and is able to abort the request -early by returning a response. In contrast all signal handlers are -executed in undefined order and do not modify any data. - -The big advantage of signals over handlers is that you can safely -subscribe to them for the split of a second. These temporary -subscriptions are helpful for unittesting for example. Say you want to -know what templates were rendered as part of a request: signals allow you -to do exactly that. - -Subscribing to Signals ----------------------- - -To subscribe to a signal, you can use the -:meth:`~blinker.base.Signal.connect` method of a signal. The first -argument is the function that should be called when the signal is emitted, -the optional second argument specifies a sender. To unsubscribe from a -signal, you can use the :meth:`~blinker.base.Signal.disconnect` method. - -For all core Flask signals, the sender is the application that issued the -signal. When you subscribe to a signal, be sure to also provide a sender -unless you really want to listen for signals of all applications. This is -especially true if you are developing an extension. - -Here for example a helper context manager that can be used to figure out -in a unittest which templates were rendered and what variables were passed -to the template:: - - from flask import template_rendered - from contextlib import contextmanager - - @contextmanager - def captured_templates(app): - recorded = [] - def record(sender, template, context): - recorded.append((template, context)) - template_rendered.connect(record, app) - try: - yield recorded - finally: - template_rendered.disconnect(record, app) - -This can now easily be paired with a test client:: - - with captured_templates(app) as templates: - rv = app.test_client().get('/') - assert rv.status_code == 200 - assert len(templates) == 1 - template, context = templates[0] - assert template.name == 'index.html' - assert len(context['items']) == 10 - -All the template rendering in the code issued by the application `app` -in the body of the `with` block will now be recorded in the `templates` -variable. Whenever a template is rendered, the template object as well as -context are appended to it. - -Additionally there is a convenient helper method -(:meth:`~blinker.base.Signal.connected_to`). that allows you to -temporarily subscribe a function to a signal with is a context manager on -its own. Because the return value of the context manager cannot be -specified that way one has to pass the list in as argument:: - - from flask import template_rendered - - def captured_templates(app, recorded): - def record(sender, template, context): - recorded.append((template, context)) - return template_rendered.connected_to(record, app) - -The example above would then look like this:: - - templates = [] - with captured_templates(app, templates): - ... - template, context = templates[0] - -.. admonition:: Blinker API Changes - - The :meth:`~blinker.base.Signal.connected_to` method arrived in Blinker - with version 1.1. - -Creating Signals ----------------- - -If you want to use signals in your own application, you can use the -blinker library directly. The most common use case are named signals in a -custom :class:`~blinker.base.Namespace`.. This is what is recommended -most of the time:: - - from blinker import Namespace - my_signals = Namespace() - -Now you can create new signals like this:: - - model_saved = my_signals.signal('model-saved') - -The name for the signal here makes it unique and also simplifies -debugging. You can access the name of the signal with the -:attr:`~blinker.base.NamedSignal.name` attribute. - -.. admonition:: For Extension Developers - - If you are writing a Flask extension and you want to gracefully degrade for - missing blinker installations, you can do so by using the - :class:`flask.signals.Namespace` class. - -Sending Signals ---------------- - -If you want to emit a signal, you can do so by calling the -:meth:`~blinker.base.Signal.send` method. It accepts a sender as first -argument and optionally some keyword arguments that are forwarded to the -signal subscribers:: - - class Model(object): - ... - - def save(self): - model_saved.send(self) - -Try to always pick a good sender. If you have a class that is emitting a -signal, pass `self` as sender. If you emitting a signal from a random -function, you can pass ``current_app._get_current_object()`` as sender. - -.. admonition:: Passing Proxies as Senders - - Never pass :data:`~flask.current_app` as sender to a signal. Use - ``current_app._get_current_object()`` instead. The reason for this is - that :data:`~flask.current_app` is a proxy and not the real application - object. - -Decorator Based Signal Subscriptions ------------------------------------- - -With Blinker 1.1 you can also easily subscribe to signals by using the new -:meth:`~blinker.base.NamedSignal.connect_via` decorator:: - - from flask import template_rendered - - @template_rendered.connect_via(app) - def when_template_rendered(sender, template, context): - print 'Template %s is rendered with %s' % (template.name, context) - -Core Signals ------------- - -.. when modifying this list, also update the one in api.rst - -The following signals exist in Flask: - -.. data:: flask.template_rendered - :noindex: - - This signal is sent when a template was successfully rendered. The - signal is invoked with the instance of the template as `template` - and the context as dictionary (named `context`). - - Example subscriber:: - - def log_template_renders(sender, template, context): - sender.logger.debug('Rendering template "%s" with context %s', - template.name or 'string template', - context) - - from flask import template_rendered - template_rendered.connect(log_template_renders, app) - -.. data:: flask.request_started - :noindex: - - This signal is sent before any request processing started but when the - request context was set up. Because the request context is already - bound, the subscriber can access the request with the standard global - proxies such as :class:`~flask.request`. - - Example subscriber:: - - def log_request(sender): - sender.logger.debug('Request context is set up') - - from flask import request_started - request_started.connect(log_request, app) - -.. data:: flask.request_finished - :noindex: - - This signal is sent right before the response is sent to the client. - It is passed the response to be sent named `response`. - - Example subscriber:: - - def log_response(sender, response): - sender.logger.debug('Request context is about to close down. ' - 'Response: %s', response) - - from flask import request_finished - request_finished.connect(log_response, app) - -.. data:: flask.got_request_exception - :noindex: - - This signal is sent when an exception happens during request processing. - It is sent *before* the standard exception handling kicks in and even - in debug mode, where no exception handling happens. The exception - itself is passed to the subscriber as `exception`. - - Example subscriber:: - - def log_exception(sender, exception): - sender.logger.debug('Got exception during processing: %s', exception) - - from flask import got_request_exception - got_request_exception.connect(log_exception, app) - -.. data:: flask.request_tearing_down - :noindex: - - This signal is sent when the request is tearing down. This is always - called, even if an exception is caused. Currently functions listening - to this signal are called after the regular teardown handlers, but this - is not something you can rely on. - - Example subscriber:: - - def close_db_connection(sender): - session.close() - - from flask import request_tearing_down - request_tearing_down.connect(close_db_connection, app) - -.. _blinker: http://pypi.python.org/pypi/blinker diff --git a/app/static/doc/flask-docs/_sources/styleguide.txt b/app/static/doc/flask-docs/_sources/styleguide.txt deleted file mode 100644 index d46ecd0..0000000 --- a/app/static/doc/flask-docs/_sources/styleguide.txt +++ /dev/null @@ -1,200 +0,0 @@ -Pocoo Styleguide -================ - -The Pocoo styleguide is the styleguide for all Pocoo Projects, including -Flask. This styleguide is a requirement for Patches to Flask and a -recommendation for Flask extensions. - -In general the Pocoo Styleguide closely follows :pep:`8` with some small -differences and extensions. - -General Layout --------------- - -Indentation: - 4 real spaces. No tabs, no exceptions. - -Maximum line length: - 79 characters with a soft limit for 84 if absolutely necessary. Try - to avoid too nested code by cleverly placing `break`, `continue` and - `return` statements. - -Continuing long statements: - To continue a statement you can use backslashes in which case you should - align the next line with the last dot or equal sign, or indent four - spaces:: - - this_is_a_very_long(function_call, 'with many parameters') \ - .that_returns_an_object_with_an_attribute - - MyModel.query.filter(MyModel.scalar > 120) \ - .order_by(MyModel.name.desc()) \ - .limit(10) - - If you break in a statement with parentheses or braces, align to the - braces:: - - this_is_a_very_long(function_call, 'with many parameters', - 23, 42, 'and even more') - - For lists or tuples with many items, break immediately after the - opening brace:: - - items = [ - 'this is the first', 'set of items', 'with more items', - 'to come in this line', 'like this' - ] - -Blank lines: - Top level functions and classes are separated by two lines, everything - else by one. Do not use too many blank lines to separate logical - segments in code. Example:: - - def hello(name): - print 'Hello %s!' % name - - - def goodbye(name): - print 'See you %s.' % name - - - class MyClass(object): - """This is a simple docstring""" - - def __init__(self, name): - self.name = name - - def get_annoying_name(self): - return self.name.upper() + '!!!!111' - -Expressions and Statements --------------------------- - -General whitespace rules: - - No whitespace for unary operators that are not words - (e.g.: ``-``, ``~`` etc.) as well on the inner side of parentheses. - - Whitespace is placed between binary operators. - - Good:: - - exp = -1.05 - value = (item_value / item_count) * offset / exp - value = my_list[index] - value = my_dict['key'] - - Bad:: - - exp = - 1.05 - value = ( item_value / item_count ) * offset / exp - value = (item_value/item_count)*offset/exp - value=( item_value/item_count ) * offset/exp - value = my_list[ index ] - value = my_dict ['key'] - -Yoda statements are a no-go: - Never compare constant with variable, always variable with constant: - - Good:: - - if method == 'md5': - pass - - Bad:: - - if 'md5' == method: - pass - -Comparisons: - - against arbitrary types: ``==`` and ``!=`` - - against singletons with ``is`` and ``is not`` (eg: ``foo is not - None``) - - never compare something with `True` or `False` (for example never - do ``foo == False``, do ``not foo`` instead) - -Negated containment checks: - use ``foo not in bar`` instead of ``not foo in bar`` - -Instance checks: - ``isinstance(a, C)`` instead of ``type(A) is C``, but try to avoid - instance checks in general. Check for features. - - -Naming Conventions ------------------- - -- Class names: ``CamelCase``, with acronyms kept uppercase (``HTTPWriter`` - and not ``HttpWriter``) -- Variable names: ``lowercase_with_underscores`` -- Method and function names: ``lowercase_with_underscores`` -- Constants: ``UPPERCASE_WITH_UNDERSCORES`` -- precompiled regular expressions: ``name_re`` - -Protected members are prefixed with a single underscore. Double -underscores are reserved for mixin classes. - -On classes with keywords, trailing underscores are appended. Clashes with -builtins are allowed and **must not** be resolved by appending an -underline to the variable name. If the function needs to access a -shadowed builtin, rebind the builtin to a different name instead. - -Function and method arguments: - - class methods: ``cls`` as first parameter - - instance methods: ``self`` as first parameter - - lambdas for properties might have the first parameter replaced - with ``x`` like in ``display_name = property(lambda x: x.real_name - or x.username)`` - - -Docstrings ----------- - -Docstring conventions: - All docstrings are formatted with reStructuredText as understood by - Sphinx. Depending on the number of lines in the docstring, they are - laid out differently. If it's just one line, the closing triple - quote is on the same line as the opening, otherwise the text is on - the same line as the opening quote and the triple quote that closes - the string on its own line:: - - def foo(): - """This is a simple docstring""" - - - def bar(): - """This is a longer docstring with so much information in there - that it spans three lines. In this case the closing triple quote - is on its own line. - """ - -Module header: - The module header consists of an utf-8 encoding declaration (if non - ASCII letters are used, but it is recommended all the time) and a - standard docstring:: - - # -*- coding: utf-8 -*- - """ - package.module - ~~~~~~~~~~~~~~ - - A brief description goes here. - - :copyright: (c) YEAR by AUTHOR. - :license: LICENSE_NAME, see LICENSE_FILE for more details. - """ - - Please keep in mind that proper copyrights and license files are a - requirement for approved Flask extensions. - - -Comments --------- - -Rules for comments are similar to docstrings. Both are formatted with -reStructuredText. If a comment is used to document an attribute, put a -colon after the opening pound sign (``#``):: - - class User(object): - #: the name of the user as unicode string - name = Column(String) - #: the sha1 hash of the password + inline salt - pw_hash = Column(String) diff --git a/app/static/doc/flask-docs/_sources/templating.txt b/app/static/doc/flask-docs/_sources/templating.txt deleted file mode 100644 index bd940b0..0000000 --- a/app/static/doc/flask-docs/_sources/templating.txt +++ /dev/null @@ -1,188 +0,0 @@ -Templates -========= - -Flask leverages Jinja2 as template engine. You are obviously free to use -a different template engine, but you still have to install Jinja2 to run -Flask itself. This requirement is necessary to enable rich extensions. -An extension can depend on Jinja2 being present. - -This section only gives a very quick introduction into how Jinja2 -is integrated into Flask. If you want information on the template -engine's syntax itself, head over to the official `Jinja2 Template -Documentation `_ for -more information. - -Jinja Setup ------------ - -Unless customized, Jinja2 is configured by Flask as follows: - -- autoescaping is enabled for all templates ending in ``.html``, - ``.htm``, ``.xml`` as well as ``.xhtml`` -- a template has the ability to opt in/out autoescaping with the - ``{% autoescape %}`` tag. -- Flask inserts a couple of global functions and helpers into the - Jinja2 context, additionally to the values that are present by - default. - -Standard Context ----------------- - -The following global variables are available within Jinja2 templates -by default: - -.. data:: config - :noindex: - - The current configuration object (:data:`flask.config`) - - .. versionadded:: 0.6 - -.. data:: request - :noindex: - - The current request object (:class:`flask.request`) - -.. data:: session - :noindex: - - The current session object (:class:`flask.session`) - -.. data:: g - :noindex: - - The request-bound object for global variables (:data:`flask.g`) - -.. function:: url_for - :noindex: - - The :func:`flask.url_for` function. - -.. function:: get_flashed_messages - :noindex: - - The :func:`flask.get_flashed_messages` function. - -.. admonition:: The Jinja Context Behaviour - - These variables are added to the context of variables, they are not - global variables. The difference is that by default these will not - show up in the context of imported templates. This is partially caused - by performance considerations, partially to keep things explicit. - - What does this mean for you? If you have a macro you want to import, - that needs to access the request object you have two possibilities: - - 1. you explicitly pass the request to the macro as parameter, or - the attribute of the request object you are interested in. - 2. you import the macro "with context". - - Importing with context looks like this: - - .. sourcecode:: jinja - - {% from '_helpers.html' import my_macro with context %} - -Standard Filters ----------------- - -These filters are available in Jinja2 additionally to the filters provided -by Jinja2 itself: - -.. function:: tojson - :noindex: - - This function converts the given object into JSON representation. This - is for example very helpful if you try to generate JavaScript on the - fly. - - Note that inside `script` tags no escaping must take place, so make - sure to disable escaping with ``|safe`` if you intend to use it inside - `script` tags: - - .. sourcecode:: html+jinja - - - - That the ``|tojson`` filter escapes forward slashes properly for you. - -Controlling Autoescaping ------------------------- - -Autoescaping is the concept of automatically escaping special characters -of you. Special characters in the sense of HTML (or XML, and thus XHTML) -are ``&``, ``>``, ``<``, ``"`` as well as ``'``. Because these characters -carry specific meanings in documents on their own you have to replace them -by so called "entities" if you want to use them for text. Not doing so -would not only cause user frustration by the inability to use these -characters in text, but can also lead to security problems. (see -:ref:`xss`) - -Sometimes however you will need to disable autoescaping in templates. -This can be the case if you want to explicitly inject HTML into pages, for -example if they come from a system that generate secure HTML like a -markdown to HTML converter. - -There are three ways to accomplish that: - -- In the Python code, wrap the HTML string in a :class:`~flask.Markup` - object before passing it to the template. This is in general the - recommended way. -- Inside the template, use the ``|safe`` filter to explicitly mark a - string as safe HTML (``{{ myvariable|safe }}``) -- Temporarily disable the autoescape system altogether. - -To disable the autoescape system in templates, you can use the ``{% -autoescape %}`` block: - -.. sourcecode:: html+jinja - - {% autoescape false %} -

autoescaping is disabled here -

{{ will_not_be_escaped }} - {% endautoescape %} - -Whenever you do this, please be very cautious about the variables you are -using in this block. - -Registering Filters -------------------- - -If you want to register your own filters in Jinja2 you have two ways to do -that. You can either put them by hand into the -:attr:`~flask.Flask.jinja_env` of the application or use the -:meth:`~flask.Flask.template_filter` decorator. - -The two following examples work the same and both reverse an object:: - - @app.template_filter('reverse') - def reverse_filter(s): - return s[::-1] - - def reverse_filter(s): - return s[::-1] - app.jinja_env.filters['reverse'] = reverse_filter - -In case of the decorator the argument is optional if you want to use the -function name as name of the filter. - -Context Processors ------------------- - -To inject new variables automatically into the context of a template -context processors exist in Flask. Context processors run before the -template is rendered and have the ability to inject new values into the -template context. A context processor is a function that returns a -dictionary. The keys and values of this dictionary are then merged with -the template context:: - - @app.context_processor - def inject_user(): - return dict(user=g.user) - -The context processor above makes a variable called `user` available in -the template with the value of `g.user`. This example is not very -interesting because `g` is available in templates anyways, but it gives an -idea how this works. diff --git a/app/static/doc/flask-docs/_sources/testing.txt b/app/static/doc/flask-docs/_sources/testing.txt deleted file mode 100644 index 1e00fe8..0000000 --- a/app/static/doc/flask-docs/_sources/testing.txt +++ /dev/null @@ -1,307 +0,0 @@ -.. _testing: - -Testing Flask Applications -========================== - - **Something that is untested is broken.** - -The origin of this quote is unknown and while it is not entirely correct, it is also -not far from the truth. Untested applications make it hard to -improve existing code and developers of untested applications tend to -become pretty paranoid. If an application has automated tests, you can -safely make changes and instantly know if anything breaks. - -Flask provides a way to test your application by exposing the Werkzeug -test :class:`~werkzeug.test.Client` and handling the context locals for you. -You can then use that with your favourite testing solution. In this documentation -we will use the :mod:`unittest` package that comes pre-installed with Python. - -The Application ---------------- - -First, we need an application to test; we will use the application from -the :ref:`tutorial`. If you don't have that application yet, get the -sources from `the examples`_. - -.. _the examples: - http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ - -The Testing Skeleton --------------------- - -In order to test the application, we add a second module -(`flaskr_tests.py`) and create a unittest skeleton there:: - - import os - import flaskr - import unittest - import tempfile - - class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() - flaskr.app.config['TESTING'] = True - self.app = flaskr.app.test_client() - flaskr.init_db() - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.app.config['DATABASE']) - - if __name__ == '__main__': - unittest.main() - -The code in the :meth:`~unittest.TestCase.setUp` method creates a new test -client and initializes a new database. This function is called before -each individual test function is run. To delete the database after the -test, we close the file and remove it from the filesystem in the -:meth:`~unittest.TestCase.tearDown` method. Additionally during setup the -``TESTING`` config flag is activated. What it does is disabling the error -catching during request handling so that you get better error reports when -performing test requests against the application. - -This test client will give us a simple interface to the application. We can -trigger test requests to the application, and the client will also keep track -of cookies for us. - -Because SQLite3 is filesystem-based we can easily use the tempfile module -to create a temporary database and initialize it. The -:func:`~tempfile.mkstemp` function does two things for us: it returns a -low-level file handle and a random file name, the latter we use as -database name. We just have to keep the `db_fd` around so that we can use -the :func:`os.close` function to close the file. - -If we now run the test suite, we should see the following output:: - - $ python flaskr_tests.py - - ---------------------------------------------------------------------- - Ran 0 tests in 0.000s - - OK - -Even though it did not run any actual tests, we already know that our flaskr -application is syntactically valid, otherwise the import would have died -with an exception. - -The First Test --------------- - -Now it's time to start testing the functionality of the application. -Let's check that the application shows "No entries here so far" if we -access the root of the application (``/``). To do this, we add a new -test method to our class, like this:: - - class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() - self.app = flaskr.app.test_client() - flaskr.init_db() - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.DATABASE) - - def test_empty_db(self): - rv = self.app.get('/') - assert 'No entries here so far' in rv.data - -Notice that our test functions begin with the word `test`; this allows -:mod:`unittest` to automatically identify the method as a test to run. - -By using `self.app.get` we can send an HTTP `GET` request to the application with -the given path. The return value will be a :class:`~flask.Flask.response_class` object. -We can now use the :attr:`~werkzeug.wrappers.BaseResponse.data` attribute to inspect -the return value (as string) from the application. In this case, we ensure that -``'No entries here so far'`` is part of the output. - -Run it again and you should see one passing test:: - - $ python flaskr_tests.py - . - ---------------------------------------------------------------------- - Ran 1 test in 0.034s - - OK - -Logging In and Out ------------------- - -The majority of the functionality of our application is only available for -the administrative user, so we need a way to log our test client in and out -of the application. To do this, we fire some requests to the login and logout -pages with the required form data (username and password). And because the -login and logout pages redirect, we tell the client to `follow_redirects`. - -Add the following two methods to your `FlaskrTestCase` class:: - - def login(self, username, password): - return self.app.post('/login', data=dict( - username=username, - password=password - ), follow_redirects=True) - - def logout(self): - return self.app.get('/logout', follow_redirects=True) - -Now we can easily test that logging in and out works and that it fails with -invalid credentials. Add this new test to the class:: - - def test_login_logout(self): - rv = self.login('admin', 'default') - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login('adminx', 'default') - assert 'Invalid username' in rv.data - rv = self.login('admin', 'defaultx') - assert 'Invalid password' in rv.data - -Test Adding Messages --------------------- - -We should also test that adding messages works. Add a new test method -like this:: - - def test_messages(self): - self.login('admin', 'default') - rv = self.app.post('/add', data=dict( - title='', - text='HTML allowed here' - ), follow_redirects=True) - assert 'No entries here so far' not in rv.data - assert '<Hello>' in rv.data - assert 'HTML allowed here' in rv.data - -Here we check that HTML is allowed in the text but not in the title, -which is the intended behavior. - -Running that should now give us three passing tests:: - - $ python flaskr_tests.py - ... - ---------------------------------------------------------------------- - Ran 3 tests in 0.332s - - OK - -For more complex tests with headers and status codes, check out the -`MiniTwit Example`_ from the sources which contains a larger test -suite. - - -.. _MiniTwit Example: - http://github.com/mitsuhiko/flask/tree/master/examples/minitwit/ - - -Other Testing Tricks --------------------- - -Besides using the test client as shown above, there is also the -:meth:`~flask.Flask.test_request_context` method that can be used -in combination with the `with` statement to activate a request context -temporarily. With this you can access the :class:`~flask.request`, -:class:`~flask.g` and :class:`~flask.session` objects like in view -functions. Here is a full example that demonstrates this approach:: - - app = flask.Flask(__name__) - - with app.test_request_context('/?name=Peter'): - assert flask.request.path == '/' - assert flask.request.args['name'] == 'Peter' - -All the other objects that are context bound can be used in the same -way. - -If you want to test your application with different configurations and -there does not seem to be a good way to do that, consider switching to -application factories (see :ref:`app-factories`). - -Note however that if you are using a test request context, the -:meth:`~flask.Flask.before_request` functions are not automatically called -same for :meth:`~flask.Flask.after_request` functions. However -:meth:`~flask.Flask.teardown_request` functions are indeed executed when -the test request context leaves the `with` block. If you do want the -:meth:`~flask.Flask.before_request` functions to be called as well, you -need to call :meth:`~flask.Flask.preprocess_request` yourself:: - - app = flask.Flask(__name__) - - with app.test_request_context('/?name=Peter'): - app.preprocess_request() - ... - -This can be necessary to open database connections or something similar -depending on how your application was designed. - -If you want to call the :meth:`~flask.Flask.after_request` functions you -need to call into :meth:`~flask.Flask.process_response` which however -requires that you pass it a response object:: - - app = flask.Flask(__name__) - - with app.test_request_context('/?name=Peter'): - resp = Response('...') - resp = app.process_response(resp) - ... - -This in general is less useful because at that point you can directly -start using the test client. - - -Keeping the Context Around --------------------------- - -.. versionadded:: 0.4 - -Sometimes it is helpful to trigger a regular request but still keep the -context around for a little longer so that additional introspection can -happen. With Flask 0.4 this is possible by using the -:meth:`~flask.Flask.test_client` with a `with` block:: - - app = flask.Flask(__name__) - - with app.test_client() as c: - rv = c.get('/?tequila=42') - assert request.args['tequila'] == '42' - -If you were to use just the :meth:`~flask.Flask.test_client` without -the `with` block, the `assert` would fail with an error because `request` -is no longer available (because you are trying to use it outside of the actual request). -However, keep in mind that any :meth:`~flask.Flask.after_request` functions -are already called at this point so your database connection and -everything involved is probably already closed down. - - -Accessing and Modifying Sessions --------------------------------- - -.. versionadded:: 0.8 - -Sometimes it can be very helpful to access or modify the sessions from the -test client. Generally there are two ways for this. If you just want to -ensure that a session has certain keys set to certain values you can just -keep the context around and access :data:`flask.session`:: - - with app.test_client() as c: - rv = c.get('/') - assert flask.session['foo'] == 42 - -This however does not make it possible to also modify the session or to -access the session before a request was fired. Starting with Flask 0.8 we -provide a so called “session transaction” which simulates the appropriate -calls to open a session in the context of the test client and to modify -it. At the end of the transaction the session is stored. This works -independently of the session backend used:: - - with app.test_client() as c: - with c.session_transaction() as sess: - sess['a_key'] = 'a value' - - # once this is reached the session was stored - -Note that in this case you have to use the ``sess`` object instead of the -:data:`flask.session` proxy. The object however itself will provide the -same interface. diff --git a/app/static/doc/flask-docs/_sources/tutorial/css.txt b/app/static/doc/flask-docs/_sources/tutorial/css.txt deleted file mode 100644 index 03f62ed..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/css.txt +++ /dev/null @@ -1,31 +0,0 @@ -.. _tutorial-css: - -Step 7: Adding Style -==================== - -Now that everything else works, it's time to add some style to the -application. Just create a stylesheet called `style.css` in the `static` -folder we created before: - -.. sourcecode:: css - - body { font-family: sans-serif; background: #eee; } - a, h1, h2 { color: #377BA8; } - h1, h2 { font-family: 'Georgia', serif; margin: 0; } - h1 { border-bottom: 2px solid #eee; } - h2 { font-size: 1.2em; } - - .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; - padding: 0.8em; background: white; } - .entries { list-style: none; margin: 0; padding: 0; } - .entries li { margin: 0.8em 1.2em; } - .entries li h2 { margin-left: -1em; } - .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } - .add-entry dl { font-weight: bold; } - .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; - margin-bottom: 1em; background: #fafafa; } - .flash { background: #CEE5F5; padding: 0.5em; - border: 1px solid #AACBE2; } - .error { background: #F0D6D6; padding: 0.5em; } - -Continue with :ref:`tutorial-testing`. diff --git a/app/static/doc/flask-docs/_sources/tutorial/dbcon.txt b/app/static/doc/flask-docs/_sources/tutorial/dbcon.txt deleted file mode 100644 index 99391a2..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/dbcon.txt +++ /dev/null @@ -1,57 +0,0 @@ -.. _tutorial-dbcon: - -Step 4: Request Database Connections ------------------------------------- - -Now we know how we can open database connections and use them for scripts, -but how can we elegantly do that for requests? We will need the database -connection in all our functions so it makes sense to initialize them -before each request and shut them down afterwards. - -Flask allows us to do that with the :meth:`~flask.Flask.before_request`, -:meth:`~flask.Flask.after_request` and :meth:`~flask.Flask.teardown_request` -decorators:: - - @app.before_request - def before_request(): - g.db = connect_db() - - @app.teardown_request - def teardown_request(exception): - g.db.close() - -Functions marked with :meth:`~flask.Flask.before_request` are called before -a request and passed no arguments. Functions marked with -:meth:`~flask.Flask.after_request` are called after a request and -passed the response that will be sent to the client. They have to return -that response object or a different one. They are however not guaranteed -to be executed if an exception is raised, this is where functions marked with -:meth:`~flask.Flask.teardown_request` come in. They get called after the -response has been constructed. They are not allowed to modify the request, and -their return values are ignored. If an exception occurred while the request was -being processed, it is passed to each function; otherwise, `None` is passed in. - -We store our current database connection on the special :data:`~flask.g` -object that Flask provides for us. This object stores information for one -request only and is available from within each function. Never store such -things on other objects because this would not work with threaded -environments. That special :data:`~flask.g` object does some magic behind -the scenes to ensure it does the right thing. - -Continue to :ref:`tutorial-views`. - -.. hint:: Where do I put this code? - - If you've been following along in this tutorial, you might be wondering - where to put the code from this step and the next. A logical place is to - group these module-level functions together, and put your new - ``before_request`` and ``teardown_request`` functions below your existing - ``init_db`` function (following the tutorial line-by-line). - - If you need a moment to find your bearings, take a look at how the `example - source`_ is organized. In Flask, you can put all of your application code - into a single Python module. You don't have to, and if your app :ref:`grows - larger `, it's a good idea not to. - -.. _example source: - http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ diff --git a/app/static/doc/flask-docs/_sources/tutorial/dbinit.txt b/app/static/doc/flask-docs/_sources/tutorial/dbinit.txt deleted file mode 100644 index b546a1a..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/dbinit.txt +++ /dev/null @@ -1,67 +0,0 @@ -.. _tutorial-dbinit: - -Step 3: Creating The Database -============================= - -Flaskr is a database powered application as outlined earlier, and more -precisely, an application powered by a relational database system. Such -systems need a schema that tells them how to store that information. So -before starting the server for the first time it's important to create -that schema. - -Such a schema can be created by piping the `schema.sql` file into the -`sqlite3` command as follows:: - - sqlite3 /tmp/flaskr.db < schema.sql - -The downside of this is that it requires the sqlite3 command to be -installed which is not necessarily the case on every system. Also one has -to provide the path to the database there which leaves some place for -errors. It's a good idea to add a function that initializes the database -for you to the application. - -If you want to do that, you first have to import the -:func:`contextlib.closing` function from the contextlib package. If you -want to use Python 2.5 it's also necessary to enable the `with` statement -first (`__future__` imports must be the very first import):: - - from __future__ import with_statement - from contextlib import closing - -Next we can create a function called `init_db` that initializes the -database. For this we can use the `connect_db` function we defined -earlier. Just add that function below the `connect_db` function:: - - def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - -The :func:`~contextlib.closing` helper function allows us to keep a -connection open for the duration of the `with` block. The -:func:`~flask.Flask.open_resource` method of the application object -supports that functionality out of the box, so it can be used in the -`with` block directly. This function opens a file from the resource -location (your `flaskr` folder) and allows you to read from it. We are -using this here to execute a script on the database connection. - -When we connect to a database we get a connection object (here called -`db`) that can give us a cursor. On that cursor there is a method to -execute a complete script. Finally we only have to commit the changes. -SQLite 3 and other transactional databases will not commit unless you -explicitly tell it to. - -Now it is possible to create a database by starting up a Python shell and -importing and calling that function:: - ->>> from flaskr import init_db ->>> init_db() - -.. admonition:: Troubleshooting - - If you get an exception later that a table cannot be found check that - you did call the `init_db` function and that your table names are - correct (singular vs. plural for example). - -Continue with :ref:`tutorial-dbcon` diff --git a/app/static/doc/flask-docs/_sources/tutorial/folders.txt b/app/static/doc/flask-docs/_sources/tutorial/folders.txt deleted file mode 100644 index 6108093..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/folders.txt +++ /dev/null @@ -1,23 +0,0 @@ -.. _tutorial-folders: - -Step 0: Creating The Folders -============================ - -Before we get started, let's create the folders needed for this -application:: - - /flaskr - /static - /templates - -The `flaskr` folder is not a python package, but just something where we -drop our files. Directly into this folder we will then put our database -schema as well as main module in the following steps. The files inside -the `static` folder are available to users of the application via `HTTP`. -This is the place where css and javascript files go. Inside the -`templates` folder Flask will look for `Jinja2`_ templates. The -templates you create later in the tutorial will go in this directory. - -Continue with :ref:`tutorial-schema`. - -.. _Jinja2: http://jinja.pocoo.org/2/ diff --git a/app/static/doc/flask-docs/_sources/tutorial/index.txt b/app/static/doc/flask-docs/_sources/tutorial/index.txt deleted file mode 100644 index 3f2d659..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/index.txt +++ /dev/null @@ -1,32 +0,0 @@ -.. _tutorial: - -Tutorial -======== - -You want to develop an application with Python and Flask? Here you have -the chance to learn that by example. In this tutorial we will create a -simple microblog application. It only supports one user that can create -text-only entries and there are no feeds or comments, but it still -features everything you need to get started. We will use Flask and SQLite -as database which comes out of the box with Python, so there is nothing -else you need. - -If you want the full sourcecode in advance or for comparison, check out -the `example source`_. - -.. _example source: - http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ - -.. toctree:: - :maxdepth: 2 - - introduction - folders - schema - setup - dbinit - dbcon - views - templates - css - testing diff --git a/app/static/doc/flask-docs/_sources/tutorial/introduction.txt b/app/static/doc/flask-docs/_sources/tutorial/introduction.txt deleted file mode 100644 index c72bbd7..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/introduction.txt +++ /dev/null @@ -1,33 +0,0 @@ -.. _tutorial-introduction: - -Introducing Flaskr -================== - -We will call our blogging application flaskr here, feel free to chose a -less web-2.0-ish name ;) Basically we want it to do the following things: - -1. let the user sign in and out with credentials specified in the - configuration. Only one user is supported. -2. when the user is logged in they can add new entries to the page - consisting of a text-only title and some HTML for the text. This HTML - is not sanitized because we trust the user here. -3. the page shows all entries so far in reverse order (newest on top) and - the user can add new ones from there if logged in. - -We will be using SQLite3 directly for that application because it's good -enough for an application of that size. For larger applications however -it makes a lot of sense to use `SQLAlchemy`_ that handles database -connections in a more intelligent way, allows you to target different -relational databases at once and more. You might also want to consider -one of the popular NoSQL databases if your data is more suited for those. - -Here a screenshot from the final application: - -.. image:: ../_static/flaskr.png - :align: center - :class: screenshot - :alt: screenshot of the final application - -Continue with :ref:`tutorial-folders`. - -.. _SQLAlchemy: http://www.sqlalchemy.org/ diff --git a/app/static/doc/flask-docs/_sources/tutorial/schema.txt b/app/static/doc/flask-docs/_sources/tutorial/schema.txt deleted file mode 100644 index c078667..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/schema.txt +++ /dev/null @@ -1,25 +0,0 @@ -.. _tutorial-schema: - -Step 1: Database Schema -======================= - -First we want to create the database schema. For this application only a -single table is needed and we only want to support SQLite so that is quite -easy. Just put the following contents into a file named `schema.sql` in -the just created `flaskr` folder: - -.. sourcecode:: sql - - drop table if exists entries; - create table entries ( - id integer primary key autoincrement, - title string not null, - text string not null - ); - -This schema consists of a single table called `entries` and each row in -this table has an `id`, a `title` and a `text`. The `id` is an -automatically incrementing integer and a primary key, the other two are -strings that must not be null. - -Continue with :ref:`tutorial-setup`. diff --git a/app/static/doc/flask-docs/_sources/tutorial/setup.txt b/app/static/doc/flask-docs/_sources/tutorial/setup.txt deleted file mode 100644 index e9e4d67..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/setup.txt +++ /dev/null @@ -1,90 +0,0 @@ -.. _tutorial-setup: - -Step 2: Application Setup Code -============================== - -Now that we have the schema in place we can create the application module. -Let's call it `flaskr.py` inside the `flaskr` folder. For starters we -will add the imports we will need as well as the config section. For -small applications it's a possibility to drop the configuration directly -into the module which we will be doing here. However a cleaner solution -would be to create a separate `.ini` or `.py` file and load that or import -the values from there. - -:: - - # all the imports - import sqlite3 - from flask import Flask, request, session, g, redirect, url_for, \ - abort, render_template, flash - - # configuration - DATABASE = '/tmp/flaskr.db' - DEBUG = True - SECRET_KEY = 'development key' - USERNAME = 'admin' - PASSWORD = 'default' - -Next we can create our actual application and initialize it with the -config from the same file:: - - # create our little application :) - app = Flask(__name__) - app.config.from_object(__name__) - -:meth:`~flask.Config.from_object` will look at the given object (if it's a -string it will import it) and then look for all uppercase variables -defined there. In our case, the configuration we just wrote a few lines -of code above. You can also move that into a separate file. - -It is also a good idea to be able to load a configuration from a -configurable file. This is what :meth:`~flask.Config.from_envvar` can -do:: - - app.config.from_envvar('FLASKR_SETTINGS', silent=True) - -That way someone can set an environment variable called -:envvar:`FLASKR_SETTINGS` to specify a config file to be loaded which will -then override the default values. The silent switch just tells Flask to -not complain if no such environment key is set. - -The `secret_key` is needed to keep the client-side sessions secure. -Choose that key wisely and as hard to guess and complex as possible. The -debug flag enables or disables the interactive debugger. Never leave -debug mode activated in a production system because it will allow users to -execute code on the server! - -We also add a method to easily connect to the database specified. That -can be used to open a connection on request and also from the interactive -Python shell or a script. This will come in handy later. - -:: - - def connect_db(): - return sqlite3.connect(app.config['DATABASE']) - -Finally we just add a line to the bottom of the file that fires up the -server if we want to run that file as a standalone application:: - - if __name__ == '__main__': - app.run() - -With that out of the way you should be able to start up the application -without problems. Do this with the following command:: - - python flaskr.py - -You will see a message telling you that server has started along with -the address at which you can access it. - -When you head over to the server in your browser you will get an 404 -page not found error because we don't have any views yet. But we will -focus on that a little later. First we should get the database working. - -.. admonition:: Externally Visible Server - - Want your server to be publicly available? Check out the - :ref:`externally visible server ` section for more - information. - -Continue with :ref:`tutorial-dbinit`. diff --git a/app/static/doc/flask-docs/_sources/tutorial/templates.txt b/app/static/doc/flask-docs/_sources/tutorial/templates.txt deleted file mode 100644 index 5ec5584..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/templates.txt +++ /dev/null @@ -1,111 +0,0 @@ -.. _tutorial-templates: - -Step 6: The Templates -===================== - -Now we should start working on the templates. If we request the URLs now -we would only get an exception that Flask cannot find the templates. The -templates are using `Jinja2`_ syntax and have autoescaping enabled by -default. This means that unless you mark a value in the code with -:class:`~flask.Markup` or with the ``|safe`` filter in the template, -Jinja2 will ensure that special characters such as ``<`` or ``>`` are -escaped with their XML equivalents. - -We are also using template inheritance which makes it possible to reuse -the layout of the website in all pages. - -Put the following templates into the `templates` folder: - -.. _Jinja2: http://jinja.pocoo.org/2/documentation/templates - -layout.html ------------ - -This template contains the HTML skeleton, the header and a link to log in -(or log out if the user was already logged in). It also displays the -flashed messages if there are any. The ``{% block body %}`` block can be -replaced by a block of the same name (``body``) in a child template. - -The :class:`~flask.session` dict is available in the template as well and -you can use that to check if the user is logged in or not. Note that in -Jinja you can access missing attributes and items of objects / dicts which -makes the following code work, even if there is no ``'logged_in'`` key in -the session: - -.. sourcecode:: html+jinja - - - Flaskr - -

-

Flaskr

-
- {% if not session.logged_in %} - log in - {% else %} - log out - {% endif %} -
- {% for message in get_flashed_messages() %} -
{{ message }}
- {% endfor %} - {% block body %}{% endblock %} -
- -show_entries.html ------------------ - -This template extends the `layout.html` template from above to display the -messages. Note that the `for` loop iterates over the messages we passed -in with the :func:`~flask.render_template` function. We also tell the -form to submit to your `add_entry` function and use `POST` as `HTTP` -method: - -.. sourcecode:: html+jinja - - {% extends "layout.html" %} - {% block body %} - {% if session.logged_in %} -
-
-
Title: -
-
Text: -
-
-
-
- {% endif %} -
    - {% for entry in entries %} -
  • {{ entry.title }}

    {{ entry.text|safe }} - {% else %} -
  • Unbelievable. No entries here so far - {% endfor %} -
- {% endblock %} - -login.html ----------- - -Finally the login template which basically just displays a form to allow -the user to login: - -.. sourcecode:: html+jinja - - {% extends "layout.html" %} - {% block body %} -

Login

- {% if error %}

Error: {{ error }}{% endif %} -

-
-
Username: -
-
Password: -
-
-
-
- {% endblock %} - -Continue with :ref:`tutorial-css`. diff --git a/app/static/doc/flask-docs/_sources/tutorial/testing.txt b/app/static/doc/flask-docs/_sources/tutorial/testing.txt deleted file mode 100644 index 34edd79..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/testing.txt +++ /dev/null @@ -1,10 +0,0 @@ -.. _tutorial-testing: - -Bonus: Testing the Application -============================== - -Now that you have finished the application and everything works as -expected, it's probably not a bad idea to add automated tests to simplify -modifications in the future. The application above is used as a basic -example of how to perform unittesting in the :ref:`testing` section of the -documentation. Go there to see how easy it is to test Flask applications. diff --git a/app/static/doc/flask-docs/_sources/tutorial/views.txt b/app/static/doc/flask-docs/_sources/tutorial/views.txt deleted file mode 100644 index 93bec3b..0000000 --- a/app/static/doc/flask-docs/_sources/tutorial/views.txt +++ /dev/null @@ -1,98 +0,0 @@ -.. _tutorial-views: - -Step 5: The View Functions -========================== - -Now that the database connections are working we can start writing the -view functions. We will need four of them: - -Show Entries ------------- - -This view shows all the entries stored in the database. It listens on the -root of the application and will select title and text from the database. -The one with the highest id (the newest entry) will be on top. The rows -returned from the cursor are tuples with the columns ordered like specified -in the select statement. This is good enough for small applications like -here, but you might want to convert them into a dict. If you are -interested in how to do that, check out the :ref:`easy-querying` example. - -The view function will pass the entries as dicts to the -`show_entries.html` template and return the rendered one:: - - @app.route('/') - def show_entries(): - cur = g.db.execute('select title, text from entries order by id desc') - entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] - return render_template('show_entries.html', entries=entries) - -Add New Entry -------------- - -This view lets the user add new entries if they are logged in. This only -responds to `POST` requests, the actual form is shown on the -`show_entries` page. If everything worked out well we will -:func:`~flask.flash` an information message to the next request and -redirect back to the `show_entries` page:: - - @app.route('/add', methods=['POST']) - def add_entry(): - if not session.get('logged_in'): - abort(401) - g.db.execute('insert into entries (title, text) values (?, ?)', - [request.form['title'], request.form['text']]) - g.db.commit() - flash('New entry was successfully posted') - return redirect(url_for('show_entries')) - -Note that we check that the user is logged in here (the `logged_in` key is -present in the session and `True`). - -.. admonition:: Security Note - - Be sure to use question marks when building SQL statements, as done in the - example above. Otherwise, your app will be vulnerable to SQL injection when - you use string formatting to build SQL statements. - See :ref:`sqlite3` for more. - -Login and Logout ----------------- - -These functions are used to sign the user in and out. Login checks the -username and password against the ones from the configuration and sets the -`logged_in` key in the session. If the user logged in successfully, that -key is set to `True`, and the user is redirected back to the `show_entries` -page. In addition, a message is flashed that informs the user that he or -she was logged in successfully. If an error occurred, the template is -notified about that, and the user is asked again:: - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - if request.form['username'] != app.config['USERNAME']: - error = 'Invalid username' - elif request.form['password'] != app.config['PASSWORD']: - error = 'Invalid password' - else: - session['logged_in'] = True - flash('You were logged in') - return redirect(url_for('show_entries')) - return render_template('login.html', error=error) - -The logout function, on the other hand, removes that key from the session -again. We use a neat trick here: if you use the :meth:`~dict.pop` method -of the dict and pass a second parameter to it (the default), the method -will delete the key from the dictionary if present or do nothing when that -key is not in there. This is helpful because now we don't have to check -if the user was logged in. - -:: - - @app.route('/logout') - def logout(): - session.pop('logged_in', None) - flash('You were logged out') - return redirect(url_for('show_entries')) - -Continue with :ref:`tutorial-templates`. diff --git a/app/static/doc/flask-docs/_sources/unicode.txt b/app/static/doc/flask-docs/_sources/unicode.txt deleted file mode 100644 index 413ea84..0000000 --- a/app/static/doc/flask-docs/_sources/unicode.txt +++ /dev/null @@ -1,107 +0,0 @@ -Unicode in Flask -================ - -Flask like Jinja2 and Werkzeug is totally Unicode based when it comes to -text. Not only these libraries, also the majority of web related Python -libraries that deal with text. If you don't know Unicode so far, you -should probably read `The Absolute Minimum Every Software Developer -Absolutely, Positively Must Know About Unicode and Character Sets -`_. This part of the -documentation just tries to cover the very basics so that you have a -pleasant experience with Unicode related things. - -Automatic Conversion --------------------- - -Flask has a few assumptions about your application (which you can change -of course) that give you basic and painless Unicode support: - -- the encoding for text on your website is UTF-8 -- internally you will always use Unicode exclusively for text except - for literal strings with only ASCII character points. -- encoding and decoding happens whenever you are talking over a protocol - that requires bytes to be transmitted. - -So what does this mean to you? - -HTTP is based on bytes. Not only the protocol, also the system used to -address documents on servers (so called URIs or URLs). However HTML which -is usually transmitted on top of HTTP supports a large variety of -character sets and which ones are used, are transmitted in an HTTP header. -To not make this too complex Flask just assumes that if you are sending -Unicode out you want it to be UTF-8 encoded. Flask will do the encoding -and setting of the appropriate headers for you. - -The same is true if you are talking to databases with the help of -SQLAlchemy or a similar ORM system. Some databases have a protocol that -already transmits Unicode and if they do not, SQLAlchemy or your other ORM -should take care of that. - -The Golden Rule ---------------- - -So the rule of thumb: if you are not dealing with binary data, work with -Unicode. What does working with Unicode in Python 2.x mean? - -- as long as you are using ASCII charpoints only (basically numbers, - some special characters of latin letters without umlauts or anything - fancy) you can use regular string literals (``'Hello World'``). -- if you need anything else than ASCII in a string you have to mark - this string as Unicode string by prefixing it with a lowercase `u`. - (like ``u'Hänsel und Gretel'``) -- if you are using non-Unicode characters in your Python files you have - to tell Python which encoding your file uses. Again, I recommend - UTF-8 for this purpose. To tell the interpreter your encoding you can - put the ``# -*- coding: utf-8 -*-`` into the first or second line of - your Python source file. -- Jinja is configured to decode the template files from UTF-8. So make - sure to tell your editor to save the file as UTF-8 there as well. - -Encoding and Decoding Yourself ------------------------------- - -If you are talking with a filesystem or something that is not really based -on Unicode you will have to ensure that you decode properly when working -with Unicode interface. So for example if you want to load a file on the -filesystem and embed it into a Jinja2 template you will have to decode it -from the encoding of that file. Here the old problem that text files do -not specify their encoding comes into play. So do yourself a favour and -limit yourself to UTF-8 for text files as well. - -Anyways. To load such a file with Unicode you can use the built-in -:meth:`str.decode` method:: - - def read_file(filename, charset='utf-8'): - with open(filename, 'r') as f: - return f.read().decode(charset) - -To go from Unicode into a specific charset such as UTF-8 you can use the -:meth:`unicode.encode` method:: - - def write_file(filename, contents, charset='utf-8'): - with open(filename, 'w') as f: - f.write(contents.encode(charset)) - -Configuring Editors -------------------- - -Most editors save as UTF-8 by default nowadays but in case your editor is -not configured to do this you have to change it. Here some common ways to -set your editor to store as UTF-8: - -- Vim: put ``set enc=utf-8`` to your ``.vimrc`` file. - -- Emacs: either use an encoding cookie or put this into your ``.emacs`` - file:: - - (prefer-coding-system 'utf-8) - (setq default-buffer-file-coding-system 'utf-8) - -- Notepad++: - - 1. Go to *Settings -> Preferences ...* - 2. Select the "New Document/Default Directory" tab - 3. Select "UTF-8 without BOM" as encoding - - It is also recommended to use the Unix newline format, you can select - it in the same panel but this is not a requirement. diff --git a/app/static/doc/flask-docs/_sources/upgrading.txt b/app/static/doc/flask-docs/_sources/upgrading.txt deleted file mode 100644 index 0ba46c1..0000000 --- a/app/static/doc/flask-docs/_sources/upgrading.txt +++ /dev/null @@ -1,324 +0,0 @@ -Upgrading to Newer Releases -=========================== - -Flask itself is changing like any software is changing over time. Most of -the changes are the nice kind, the kind where you don't have to change -anything in your code to profit from a new release. - -However every once in a while there are changes that do require some -changes in your code or there are changes that make it possible for you to -improve your own code quality by taking advantage of new features in -Flask. - -This section of the documentation enumerates all the changes in Flask from -release to release and how you can change your code to have a painless -updating experience. - -If you want to use the `easy_install` command to upgrade your Flask -installation, make sure to pass it the ``-U`` parameter:: - - $ easy_install -U Flask - -Version 0.8 ------------ - -Flask introduced a new session interface system. We also noticed that -there was a naming collision between `flask.session` the module that -implements sessions and :data:`flask.session` which is the global session -object. With that introduction we moved the implementation details for -the session system into a new module called :mod:`flask.sessions`. If you -used the previously undocumented session support we urge you to upgrade. - -If invalid JSON data was submitted Flask will now raise a -:exc:`~werkzeug.exceptions.BadRequest` exception instead of letting the -default :exc:`ValueError` bubble up. This has the advantage that you no -longer have to handle that error to avoid an internal server error showing -up for the user. If you were catching this down explicitly in the past -as `ValueError` you will need to change this. - -Due to a bug in the test client Flask 0.7 did not trigger teardown -handlers when the test client was used in a with statement. This was -since fixed but might require some changes in your testsuites if you -relied on this behavior. - -Version 0.7 ------------ - -In Flask 0.7 we cleaned up the code base internally a lot and did some -backwards incompatible changes that make it easier to implement larger -applications with Flask. Because we want to make upgrading as easy as -possible we tried to counter the problems arising from these changes by -providing a script that can ease the transition. - -The script scans your whole application and generates an unified diff with -changes it assumes are safe to apply. However as this is an automated -tool it won't be able to find all use cases and it might miss some. We -internally spread a lot of deprecation warnings all over the place to make -it easy to find pieces of code that it was unable to upgrade. - -We strongly recommend that you hand review the generated patchfile and -only apply the chunks that look good. - -If you are using git as version control system for your project we -recommend applying the patch with ``path -p1 < patchfile.diff`` and then -using the interactive commit feature to only apply the chunks that look -good. - -To apply the upgrade script do the following: - -1. Download the script: `flask-07-upgrade.py - `_ -2. Run it in the directory of your application:: - - python flask-07-upgrade.py > patchfile.diff - -3. Review the generated patchfile. -4. Apply the patch:: - - patch -p1 < patchfile.diff - -5. If you were using per-module template folders you need to move some - templates around. Previously if you had a folder named ``templates`` - next to a blueprint named ``admin`` the implicit template path - automatically was ``admin/index.html`` for a template file called - ``templates/index.html``. This no longer is the case. Now you need - to name the template ``templates/admin/index.html``. The tool will - not detect this so you will have to do that on your own. - -Please note that deprecation warnings are disabled by default starting -with Python 2.7. In order to see the deprecation warnings that might be -emitted you have to enabled them with the :mod:`warnings` module. - -If you are working with windows and you lack the `patch` command line -utility you can get it as part of various Unix runtime environments for -windows including cygwin, msysgit or ming32. Also source control systems -like svn, hg or git have builtin support for applying unified diffs as -generated by the tool. Check the manual of your version control system -for more information. - -Bug in Request Locals -````````````````````` - -Due to a bug in earlier implementations the request local proxies now -raise a :exc:`RuntimeError` instead of an :exc:`AttributeError` when they -are unbound. If you caught these exceptions with :exc:`AttributeError` -before, you should catch them with :exc:`RuntimeError` now. - -Additionally the :func:`~flask.send_file` function is now issuing -deprecation warnings if you depend on functionality that will be removed -in Flask 1.0. Previously it was possible to use etags and mimetypes -when file objects were passed. This was unreliable and caused issues -for a few setups. If you get a deprecation warning, make sure to -update your application to work with either filenames there or disable -etag attaching and attach them yourself. - -Old code:: - - return send_file(my_file_object) - return send_file(my_file_object) - -New code:: - - return send_file(my_file_object, add_etags=False) - -.. _upgrading-to-new-teardown-handling: - -Upgrading to new Teardown Handling -`````````````````````````````````` - -We streamlined the behavior of the callbacks for request handling. For -things that modify the response the :meth:`~flask.Flask.after_request` -decorators continue to work as expected, but for things that absolutely -must happen at the end of request we introduced the new -:meth:`~flask.Flask.teardown_request` decorator. Unfortunately that -change also made after-request work differently under error conditions. -It's not consistently skipped if exceptions happen whereas previously it -might have been called twice to ensure it is executed at the end of the -request. - -If you have database connection code that looks like this:: - - @app.after_request - def after_request(response): - g.db.close() - return response - -You are now encouraged to use this instead:: - - @app.teardown_request - def after_request(exception): - if hasattr(g, 'db'): - g.db.close() - -On the upside this change greatly improves the internal code flow and -makes it easier to customize the dispatching and error handling. This -makes it now a lot easier to write unit tests as you can prevent closing -down of database connections for a while. You can take advantage of the -fact that the teardown callbacks are called when the response context is -removed from the stack so a test can query the database after request -handling:: - - with app.test_client() as client: - resp = client.get('/') - # g.db is still bound if there is such a thing - - # and here it's gone - -Manual Error Handler Attaching -`````````````````````````````` - -While it is still possible to attach error handlers to -:attr:`Flask.error_handlers` it's discouraged to do so and in fact -deprecated. In generaly we no longer recommend custom error handler -attaching via assignments to the underlying dictionary due to the more -complex internal handling to support arbitrary exception classes and -blueprints. See :meth:`Flask.errorhandler` for more information. - -The proper upgrade is to change this:: - - app.error_handlers[403] = handle_error - -Into this:: - - app.register_error_handler(403, handle_error) - -Alternatively you should just attach the function with a decorator:: - - @app.errorhandler(403) - def handle_error(e): - ... - -(Note that :meth:`register_error_handler` is new in Flask 0.7) - -Blueprint Support -````````````````` - -Blueprints replace the previous concept of “Modules” in Flask. They -provide better semantics for various features and work better with large -applications. The update script provided should be able to upgrade your -applications automatically, but there might be some cases where it fails -to upgrade. What changed? - -- Blueprints need explicit names. Modules had an automatic name - guesssing scheme where the shortname for the module was taken from the - last part of the import module. The upgrade script tries to guess - that name but it might fail as this information could change at - runtime. -- Blueprints have an inverse behavior for :meth:`url_for`. Previously - ``.foo`` told :meth:`url_for` that it should look for the endpoint - `foo` on the application. Now it means “relative to current module”. - The script will inverse all calls to :meth:`url_for` automatically for - you. It will do this in a very eager way so you might end up with - some unnecessary leading dots in your code if you're not using - modules. -- Blueprints do not automatically provide static folders. They will - also no longer automatically export templates from a folder called - `templates` next to their location however but it can be enabled from - the constructor. Same with static files: if you want to continue - serving static files you need to tell the constructor explicitly the - path to the static folder (which can be relative to the blueprint's - module path). -- Rendering templates was simplified. Now the blueprints can provide - template folders which are added to a general template searchpath. - This means that you need to add another subfolder with the blueprint's - name into that folder if you want ``blueprintname/template.html`` as - the template name. - -If you continue to use the `Module` object which is deprecated, Flask will -restore the previous behavior as good as possible. However we strongly -recommend upgrading to the new blueprints as they provide a lot of useful -improvement such as the ability to attach a blueprint multiple times, -blueprint specific error handlers and a lot more. - - -Version 0.6 ------------ - -Flask 0.6 comes with a backwards incompatible change which affects the -order of after-request handlers. Previously they were called in the order -of the registration, now they are called in reverse order. This change -was made so that Flask behaves more like people expected it to work and -how other systems handle request pre- and postprocessing. If you -depend on the order of execution of post-request functions, be sure to -change the order. - -Another change that breaks backwards compatibility is that context -processors will no longer override values passed directly to the template -rendering function. If for example `request` is as variable passed -directly to the template, the default context processor will not override -it with the current request object. This makes it easier to extend -context processors later to inject additional variables without breaking -existing template not expecting them. - -Version 0.5 ------------ - -Flask 0.5 is the first release that comes as a Python package instead of a -single module. There were a couple of internal refactoring so if you -depend on undocumented internal details you probably have to adapt the -imports. - -The following changes may be relevant to your application: - -- autoescaping no longer happens for all templates. Instead it is - configured to only happen on files ending with ``.html``, ``.htm``, - ``.xml`` and ``.xhtml``. If you have templates with different - extensions you should override the - :meth:`~flask.Flask.select_jinja_autoescape` method. -- Flask no longer supports zipped applications in this release. This - functionality might come back in future releases if there is demand - for this feature. Removing support for this makes the Flask internal - code easier to understand and fixes a couple of small issues that make - debugging harder than necessary. -- The `create_jinja_loader` function is gone. If you want to customize - the Jinja loader now, use the - :meth:`~flask.Flask.create_jinja_environment` method instead. - -Version 0.4 ------------ - -For application developers there are no changes that require changes in -your code. In case you are developing on a Flask extension however, and -that extension has a unittest-mode you might want to link the activation -of that mode to the new ``TESTING`` flag. - -Version 0.3 ------------ - -Flask 0.3 introduces configuration support and logging as well as -categories for flashing messages. All these are features that are 100% -backwards compatible but you might want to take advantage of them. - -Configuration Support -````````````````````` - -The configuration support makes it easier to write any kind of application -that requires some sort of configuration. (Which most likely is the case -for any application out there). - -If you previously had code like this:: - - app.debug = DEBUG - app.secret_key = SECRET_KEY - -You no longer have to do that, instead you can just load a configuration -into the config object. How this works is outlined in :ref:`config`. - -Logging Integration -``````````````````` - -Flask now configures a logger for you with some basic and useful defaults. -If you run your application in production and want to profit from -automatic error logging, you might be interested in attaching a proper log -handler. Also you can start logging warnings and errors into the logger -when appropriately. For more information on that, read -:ref:`application-errors`. - -Categories for Flash Messages -````````````````````````````` - -Flash messages can now have categories attached. This makes it possible -to render errors, warnings or regular messages differently for example. -This is an opt-in feature because it requires some rethinking in the code. - -Read all about that in the :ref:`message-flashing-pattern` pattern. diff --git a/app/static/doc/flask-docs/_sources/views.txt b/app/static/doc/flask-docs/_sources/views.txt deleted file mode 100644 index 441620a..0000000 --- a/app/static/doc/flask-docs/_sources/views.txt +++ /dev/null @@ -1,227 +0,0 @@ -.. _views: - -Pluggable Views -=============== - -.. versionadded:: 0.7 - -Flask 0.7 introduces pluggable views inspired by the generic views from -Django which are based on classes instead of functions. The main -intention is that you can replace parts of the implementations and this -way have customizable pluggable views. - -Basic Principle ---------------- - -Consider you have a function that loads a list of objects from the -database and renders into a template:: - - @app.route('/users/') - def show_users(page): - users = User.query.all() - return render_template('users.html', users=users) - -This is simple and flexible, but if you want to provide this view in a -generic fashion that can be adapted to other models and templates as well -you might want more flexibility. This is where pluggable class based -views come into place. As the first step to convert this into a class -based view you would do this:: - - - from flask.views import View - - class ShowUsers(View): - - def dispatch_request(self): - users = User.query.all() - return render_template('users.html', objects=users) - - app.add_url_rule('/users/', ShowUsers.as_view('show_users')) - -As you can see what you have to do is to create a subclass of -:class:`flask.views.View` and implement -:meth:`~flask.views.View.dispatch_request`. Then we have to convert that -class into an actual view function by using the -:meth:`~flask.views.View.as_view` class method. The string you pass to -that function is the name of the endpoint that view will then have. But -this by itself is not helpful, so let's refactor the code a bit:: - - - from flask.views import View - - class ListView(View): - - def get_template_name(self): - raise NotImplementedError() - - def render_template(self, context): - return render_template(self.get_template_name(), **context) - - def dispatch_request(self): - context = {'objects': self.get_objects()} - return self.render_template(context) - - class UserView(ListView): - - def get_template_name(self): - return 'users.html' - - def get_objects(self): - return User.query.all() - -This of course is not that helpful for such a small example, but it's good -enough to explain the basic principle. When you have a class based view -the question comes up what `self` points to. The way this works is that -whenever the request is dispatched a new instance of the class is created -and the :meth:`~flask.views.View.dispatch_request` method is called with -the parameters from the URL rule. The class itself is instanciated with -the parameters passed to the :meth:`~flask.views.View.as_view` function. -For instance you can write a class like this:: - - class RenderTemplateView(View): - def __init__(self, template_name): - self.template_name = template_name - def dispatch_request(self): - return render_template(self.template_name) - -And then you can register it like this:: - - app.add_url_rule('/about', view_func=RenderTemplateView.as_view( - 'about_page', template_name='about.html')) - -Method Hints ------------- - -Pluggable views are attached to the application like a regular function by -either using :func:`~flask.Flask.route` or better -:meth:`~flask.Flask.add_url_rule`. That however also means that you would -have to provide the names of the HTTP methods the view supports when you -attach this. In order to move that information to the class you can -provide a :attr:`~flask.views.View.methods` attribute that has this -information:: - - class MyView(View): - methods = ['GET', 'POST'] - - def dispatch_request(self): - if request.method == 'POST': - ... - ... - - app.add_url_rule('/myview', view_func=MyView.as_view('myview')) - -Method Based Dispatching ------------------------- - -For RESTful APIs it's especially helpful to execute a different function -for each HTTP method. With the :class:`flask.views.MethodView` you can -easily do that. Each HTTP method maps to a function with the same name -(just in lowercase):: - - from flask.views import MethodView - - class UserAPI(MethodView): - - def get(self): - users = User.query.all() - ... - - def post(self): - user = User.from_form_data(request.form) - ... - - app.add_url_rule('/users/', view_func=UserAPI.as_view('users')) - -That way you also don't have to provide the -:attr:`~flask.views.View.methods` attribute. It's automatically set based -on the methods defined in the class. - -Decorating Views ----------------- - -Since the view class itself is not the view function that is added to the -routing system it does not make much sense to decorate the class itself. -Instead you either have to decorate the return value of -:meth:`~flask.views.View.as_view` by hand:: - - view = rate_limited(UserAPI.as_view('users')) - app.add_url_rule('/users/', view_func=view) - -Starting with Flask 0.8 there is also an alternative way where you can -specify a list of decorators to apply in the class declaration:: - - class UserAPI(MethodView): - decorators = [rate_limited] - -Due to the implicit self from the caller's perspective you cannot use -regular view decorators on the individual methods of the view however, -keep this in mind. - -Method Views for APIs ---------------------- - -Web APIs are often working very closely with HTTP verbs so it makes a lot -of sense to implement such an API based on the -:class:`~flask.views.MethodView`. That said, you will notice that the API -will require different URL rules that go to the same method view most of -the time. For instance consider that you are exposing a user object on -the web: - -=============== =============== ====================================== -URL Method Description ---------------- --------------- -------------------------------------- -``/users/`` ``GET`` Gives a list of all users -``/users/`` ``POST`` Creates a new user -``/users/`` ``GET`` Shows a single user -``/users/`` ``PUT`` Updates a single user -``/users/`` ``DELETE`` Deletes a single user -=============== =============== ====================================== - -So how would you go about doing that with the -:class:`~flask.views.MethodView`? The trick is to take advantage of the -fact that you can provide multiple rules to the same view. - -Let's assume for the moment the view would look like this:: - - class UserAPI(MethodView): - - def get(self, user_id): - if user_id is None: - # return a list of users - pass - else: - # expose a single user - pass - - def post(self): - # create a new user - pass - - def delete(self, user_id): - # delete a single user - pass - - def put(self, user_id): - # update a single user - pass - -So how do we hook this up with the routing system? By adding two rules -and explicitly mentioning the methods for each:: - - user_view = UserAPI.as_view('user_api') - app.add_url_rule('/users/', defaults={'user_id': None}, - view_func=user_view, methods=['GET', 'POST']) - app.add_url_rule('/users/', view_func=user_view, - methods=['GET', 'PUT', 'DELETE']) - -If you have a lot of APIs that look similar you can refactor that -registration code:: - - def register_api(view, endpoint, url, pk='id', pk_type='int'): - view_func = view.as_view(endpoint) - app.add_url_rule(url, defaults={pk: None}, - view_func=view_func, methods=['GET', 'POST']) - app.add_url_rule('%s<%s:%s>' % (url, pk), view_func=view_func, - methods=['GET', 'PUT', 'DELETE']) - - register_api(UserAPI, 'user_api', '/users/', pk='user_id') diff --git a/app/static/doc/flask-docs/_static/ajax-loader.gif b/app/static/doc/flask-docs/_static/ajax-loader.gif deleted file mode 100644 index 61faf8c..0000000 --- a/app/static/doc/flask-docs/_static/ajax-loader.gif +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/basic.css b/app/static/doc/flask-docs/_static/basic.css deleted file mode 100644 index f0379f3..0000000 --- a/app/static/doc/flask-docs/_static/basic.css +++ /dev/null @@ -1,540 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar input[type="text"] { - width: 170px; -} - -div.sphinxsidebar input[type="submit"] { - width: 30px; -} - -img { - border: 0; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- general body styles --------------------------------------------------- */ - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.field-list ul { - padding-left: 1em; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.field-list td, table.field-list th { - border: 0 !important; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, .highlighted { - background-color: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.refcount { - color: #060; -} - -.optional { - font-size: 1.3em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -tt.descclassname { - background-color: transparent; -} - -tt.xref, a tt { - background-color: transparent; - font-weight: bold; -} - -h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/app/static/doc/flask-docs/_static/comment-bright.png b/app/static/doc/flask-docs/_static/comment-bright.png deleted file mode 100644 index 551517b..0000000 --- a/app/static/doc/flask-docs/_static/comment-bright.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/comment-close.png b/app/static/doc/flask-docs/_static/comment-close.png deleted file mode 100644 index 09b54be..0000000 --- a/app/static/doc/flask-docs/_static/comment-close.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/comment.png b/app/static/doc/flask-docs/_static/comment.png deleted file mode 100644 index 92feb52..0000000 --- a/app/static/doc/flask-docs/_static/comment.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/debugger.png b/app/static/doc/flask-docs/_static/debugger.png deleted file mode 100644 index 4f47229..0000000 --- a/app/static/doc/flask-docs/_static/debugger.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/doctools.js b/app/static/doc/flask-docs/_static/doctools.js deleted file mode 100644 index 8b9bd2c..0000000 --- a/app/static/doc/flask-docs/_static/doctools.js +++ /dev/null @@ -1,247 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilties for all documentation. - * - * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -} - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s == 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * small function to check if an array contains - * a given item. - */ -jQuery.contains = function(arr, item) { - for (var i = 0; i < arr.length; i++) { - if (arr[i] == item) - return true; - } - return false; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node) { - if (node.nodeType == 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { - var span = document.createElement("span"); - span.className = className; - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this); - }); - } - } - return this.each(function() { - highlight(this); - }); -}; - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated == 'undefined') - return string; - return (typeof translated == 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated == 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('.sidebar .this-page-menu')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) == 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this == '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/app/static/doc/flask-docs/_static/down-pressed.png b/app/static/doc/flask-docs/_static/down-pressed.png deleted file mode 100644 index 6f7ad78..0000000 --- a/app/static/doc/flask-docs/_static/down-pressed.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/down.png b/app/static/doc/flask-docs/_static/down.png deleted file mode 100644 index 3003a88..0000000 --- a/app/static/doc/flask-docs/_static/down.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/file.png b/app/static/doc/flask-docs/_static/file.png deleted file mode 100644 index d18082e..0000000 --- a/app/static/doc/flask-docs/_static/file.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/flask.png b/app/static/doc/flask-docs/_static/flask.png deleted file mode 100644 index 5c603cc..0000000 --- a/app/static/doc/flask-docs/_static/flask.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/flaskr.png b/app/static/doc/flask-docs/_static/flaskr.png deleted file mode 100644 index 07d027d..0000000 --- a/app/static/doc/flask-docs/_static/flaskr.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/flasky.css b/app/static/doc/flask-docs/_static/flasky.css deleted file mode 100644 index 48bebc8..0000000 --- a/app/static/doc/flask-docs/_static/flasky.css +++ /dev/null @@ -1,387 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * :copyright: Copyright 2010 by Armin Ronacher. - * :license: Flask Design License, see LICENSE for details. - */ - - - - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 17px; - background-color: #c0c0c0; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -div.related { - display: none; -} - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebar { - font-size: 14px; - line-height: 1.5; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0 0 20px 0; - margin: 0; - text-align: center; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: 'Garamond', 'Georgia', serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: 'Georgia', serif; - font-size: 1em; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #ddd; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #eaeaea; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - background: #fafafa; - margin: 20px -30px; - padding: 10px 30px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -div.admonition tt.xref, div.admonition a tt { - border-bottom: 1px solid #fafafa; -} - -dd div.admonition { - margin-left: -60px; - padding-left: 60px; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: white; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -img.screenshot { -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -tt.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #eee; - background: #fdfdfd; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td.label { - width: 0px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #eee; - padding: 7px 30px; - margin: 15px -30px; - line-height: 1.3em; -} - -dl pre, blockquote pre, li pre { - margin-left: -60px; - padding-left: 60px; -} - -dl dl pre { - margin-left: -90px; - padding-left: 90px; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid white; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt { - background: #EEE; -} diff --git a/app/static/doc/flask-docs/_static/jquery.js b/app/static/doc/flask-docs/_static/jquery.js deleted file mode 100644 index 7c24308..0000000 --- a/app/static/doc/flask-docs/_static/jquery.js +++ /dev/null @@ -1,154 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/app/static/doc/flask-docs/_static/logo-full.png b/app/static/doc/flask-docs/_static/logo-full.png deleted file mode 100644 index 5deaf1b..0000000 --- a/app/static/doc/flask-docs/_static/logo-full.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/minus.png b/app/static/doc/flask-docs/_static/minus.png deleted file mode 100644 index da1c562..0000000 --- a/app/static/doc/flask-docs/_static/minus.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/no.png b/app/static/doc/flask-docs/_static/no.png deleted file mode 100644 index 4ac1083..0000000 --- a/app/static/doc/flask-docs/_static/no.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/plus.png b/app/static/doc/flask-docs/_static/plus.png deleted file mode 100644 index b3cb374..0000000 --- a/app/static/doc/flask-docs/_static/plus.png +++ /dev/null Binary files differ diff --git a/app/static/doc/flask-docs/_static/pygments.css b/app/static/doc/flask-docs/_static/pygments.css deleted file mode 100644 index ee96fae..0000000 --- a/app/static/doc/flask-docs/_static/pygments.css +++ /dev/null @@ -1,70 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #f8f8f8; } -.highlight .c { color: #8f5902; font-style: italic } /* Comment */ -.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ -.highlight .g { color: #000000 } /* Generic */ -.highlight .k { color: #004461; font-weight: bold } /* Keyword */ -.highlight .l { color: #000000 } /* Literal */ -.highlight .n { color: #000000 } /* Name */ -.highlight .o { color: #582800 } /* Operator */ -.highlight .x { color: #000000 } /* Other */ -.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ -.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #8f5902 } /* Comment.Preproc */ -.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #a40000 } /* Generic.Deleted */ -.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #ef2929 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #808080 } /* Generic.Output */ -.highlight .gp { color: #745334 } /* Generic.Prompt */ -.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ -.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ -.highlight .ld { color: #000000 } /* Literal.Date */ -.highlight .m { color: #990000 } /* Literal.Number */ -.highlight .s { color: #4e9a06 } /* Literal.String */ -.highlight .na { color: #c4a000 } /* Name.Attribute */ -.highlight .nb { color: #004461 } /* Name.Builtin */ -.highlight .nc { color: #000000 } /* Name.Class */ -.highlight .no { color: #000000 } /* Name.Constant */ -.highlight .nd { color: #808080 } /* Name.Decorator */ -.highlight .ni { color: #ce5c00 } /* Name.Entity */ -.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #000000 } /* Name.Function */ -.highlight .nl { color: #f57900 } /* Name.Label */ -.highlight .nn { color: #000000 } /* Name.Namespace */ -.highlight .nx { color: #000000 } /* Name.Other */ -.highlight .py { color: #000000 } /* Name.Property */ -.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #000000 } /* Name.Variable */ -.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ -.highlight .mf { color: #990000 } /* Literal.Number.Float */ -.highlight .mh { color: #990000 } /* Literal.Number.Hex */ -.highlight .mi { color: #990000 } /* Literal.Number.Integer */ -.highlight .mo { color: #990000 } /* Literal.Number.Oct */ -.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ -.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ -.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ -.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ -.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ -.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ -.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ -.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ -.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ -.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ -.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #000000 } /* Name.Variable.Class */ -.highlight .vg { color: #000000 } /* Name.Variable.Global */ -.highlight .vi { color: #000000 } /* Name.Variable.Instance */ -.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/app/static/doc/flask-docs/_static/searchtools.js b/app/static/doc/flask-docs/_static/searchtools.js deleted file mode 100644 index 6ed5ac8..0000000 --- a/app/static/doc/flask-docs/_static/searchtools.js +++ /dev/null @@ -1,556 +0,0 @@ -/* - * searchtools.js_t - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilties for the full-text search. - * - * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * helper function to return a node containing the - * search summary for a given text. keywords is a list - * of stemmed words, hlwords is the list of normal, unstemmed - * words. the first one is used to find the occurance, the - * latter for highlighting it. - */ - -jQuery.makeSearchSummary = function(text, keywords, hlwords) { - var textLower = text.toLowerCase(); - var start = 0; - $.each(keywords, function() { - var i = textLower.indexOf(this.toLowerCase()); - if (i > -1) - start = i; - }); - start = Math.max(start - 120, 0); - var excerpt = ((start > 0) ? '...' : '') + - $.trim(text.substr(start, 240)) + - ((start + 240 - text.length) ? '...' : ''); - var rv = $('
').text(excerpt); - $.each(hlwords, function() { - rv = rv.highlightText(this, 'highlighted'); - }); - return rv; -} - - -/** - * Porter Stemmer - */ -var Stemmer = function() { - - var step2list = { - ational: 'ate', - tional: 'tion', - enci: 'ence', - anci: 'ance', - izer: 'ize', - bli: 'ble', - alli: 'al', - entli: 'ent', - eli: 'e', - ousli: 'ous', - ization: 'ize', - ation: 'ate', - ator: 'ate', - alism: 'al', - iveness: 'ive', - fulness: 'ful', - ousness: 'ous', - aliti: 'al', - iviti: 'ive', - biliti: 'ble', - logi: 'log' - }; - - var step3list = { - icate: 'ic', - ative: '', - alize: 'al', - iciti: 'ic', - ical: 'ic', - ful: '', - ness: '' - }; - - var c = "[^aeiou]"; // consonant - var v = "[aeiouy]"; // vowel - var C = c + "[^aeiouy]*"; // consonant sequence - var V = v + "[aeiou]*"; // vowel sequence - - var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 - var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 - var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 - var s_v = "^(" + C + ")?" + v; // vowel in stem - - this.stemWord = function (w) { - var stem; - var suffix; - var firstch; - var origword = w; - - if (w.length < 3) - return w; - - var re; - var re2; - var re3; - var re4; - - firstch = w.substr(0,1); - if (firstch == "y") - w = firstch.toUpperCase() + w.substr(1); - - // Step 1a - re = /^(.+?)(ss|i)es$/; - re2 = /^(.+?)([^s])s$/; - - if (re.test(w)) - w = w.replace(re,"$1$2"); - else if (re2.test(w)) - w = w.replace(re2,"$1$2"); - - // Step 1b - re = /^(.+?)eed$/; - re2 = /^(.+?)(ed|ing)$/; - if (re.test(w)) { - var fp = re.exec(w); - re = new RegExp(mgr0); - if (re.test(fp[1])) { - re = /.$/; - w = w.replace(re,""); - } - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1]; - re2 = new RegExp(s_v); - if (re2.test(stem)) { - w = stem; - re2 = /(at|bl|iz)$/; - re3 = new RegExp("([^aeiouylsz])\\1$"); - re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re2.test(w)) - w = w + "e"; - else if (re3.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - else if (re4.test(w)) - w = w + "e"; - } - } - - // Step 1c - re = /^(.+?)y$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(s_v); - if (re.test(stem)) - w = stem + "i"; - } - - // Step 2 - re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step2list[suffix]; - } - - // Step 3 - re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step3list[suffix]; - } - - // Step 4 - re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; - re2 = /^(.+?)(s|t)(ion)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - if (re.test(stem)) - w = stem; - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1] + fp[2]; - re2 = new RegExp(mgr1); - if (re2.test(stem)) - w = stem; - } - - // Step 5 - re = /^(.+?)e$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - re2 = new RegExp(meq1); - re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) - w = stem; - } - re = /ll$/; - re2 = new RegExp(mgr1); - if (re.test(w) && re2.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - - // and turn initial Y back to y - if (firstch == "y") - w = firstch.toLowerCase() + w.substr(1); - return w; - } -} - - -/** - * Search Module - */ -var Search = { - - _index : null, - _queued_query : null, - _pulse_status : -1, - - init : function() { - var params = $.getQueryParameters(); - if (params.q) { - var query = params.q[0]; - $('input[name="q"]')[0].value = query; - this.performSearch(query); - } - }, - - loadIndex : function(url) { - $.ajax({type: "GET", url: url, data: null, success: null, - dataType: "script", cache: true}); - }, - - setIndex : function(index) { - var q; - this._index = index; - if ((q = this._queued_query) !== null) { - this._queued_query = null; - Search.query(q); - } - }, - - hasIndex : function() { - return this._index !== null; - }, - - deferQuery : function(query) { - this._queued_query = query; - }, - - stopPulse : function() { - this._pulse_status = 0; - }, - - startPulse : function() { - if (this._pulse_status >= 0) - return; - function pulse() { - Search._pulse_status = (Search._pulse_status + 1) % 4; - var dotString = ''; - for (var i = 0; i < Search._pulse_status; i++) - dotString += '.'; - Search.dots.text(dotString); - if (Search._pulse_status > -1) - window.setTimeout(pulse, 500); - }; - pulse(); - }, - - /** - * perform a search for something - */ - performSearch : function(query) { - // create the required interface elements - this.out = $('#search-results'); - this.title = $('

' + _('Searching') + '

').appendTo(this.out); - this.dots = $('').appendTo(this.title); - this.status = $('

').appendTo(this.out); - this.output = $('