forked from orbit-oss/flask
Added interactive Python docs, fixed part style.
This commit is contained in:
parent
9d98ad5e07
commit
ef0dc1800f
8 changed files with 215 additions and 81 deletions
4
CHANGES
4
CHANGES
|
|
@ -13,6 +13,10 @@ Release date to be announced
|
||||||
log request handling exceptions to that logger when not in debug
|
log request handling exceptions to that logger when not in debug
|
||||||
mode. This makes it possible to receive mails on server errors
|
mode. This makes it possible to receive mails on server errors
|
||||||
for example.
|
for example.
|
||||||
|
- added support for context binding that does not require the use of
|
||||||
|
the with statement for playing in the console.
|
||||||
|
- the request context is now available within the with statement making
|
||||||
|
it possible to further push the request context or pop it.
|
||||||
|
|
||||||
Version 0.2
|
Version 0.2
|
||||||
-----------
|
-----------
|
||||||
|
|
|
||||||
43
docs/contents.rst.inc
Normal file
43
docs/contents.rst.inc
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
User's Guide
|
||||||
|
------------
|
||||||
|
|
||||||
|
This part of the documentation is written text and should give you an idea
|
||||||
|
how to work with Flask. It's a series of step-by-step instructions for
|
||||||
|
web development.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
foreword
|
||||||
|
installation
|
||||||
|
quickstart
|
||||||
|
tutorial/index
|
||||||
|
testing
|
||||||
|
errorhandling
|
||||||
|
shell
|
||||||
|
patterns/index
|
||||||
|
deploying/index
|
||||||
|
becomingbig
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
-------------
|
||||||
|
|
||||||
|
If you are looking for information on a specific function, class or
|
||||||
|
method, this part of the documentation is for you.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
api
|
||||||
|
|
||||||
|
Additional Notes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Design notes, legal information and changelog are here for the interested.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
design
|
||||||
|
license
|
||||||
|
changelog
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
\pagenumbering{arabic}
|
|
||||||
\definecolor{TitleColor}{rgb}{0,0,0}
|
\definecolor{TitleColor}{rgb}{0,0,0}
|
||||||
\definecolor{InnerLinkColor}{rgb}{0,0,0}
|
\definecolor{InnerLinkColor}{rgb}{0,0,0}
|
||||||
|
|
||||||
|
|
@ -72,9 +71,10 @@
|
||||||
|
|
||||||
\renewcommand\thepart{\@Roman\c@part}
|
\renewcommand\thepart{\@Roman\c@part}
|
||||||
\renewcommand\part{%
|
\renewcommand\part{%
|
||||||
|
\pagestyle{empty}
|
||||||
\if@noskipsec \leavevmode \fi
|
\if@noskipsec \leavevmode \fi
|
||||||
\cleardoublepage
|
\cleardoublepage
|
||||||
\vspace*{8cm}%
|
\vspace*{6cm}%
|
||||||
\@afterindentfalse
|
\@afterindentfalse
|
||||||
\secdef\@part\@spart}
|
\secdef\@part\@spart}
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
\else
|
\else
|
||||||
\addcontentsline{toc}{part}{#1}%
|
\addcontentsline{toc}{part}{#1}%
|
||||||
\fi
|
\fi
|
||||||
{\parindent \z@ \center
|
{\parindent \z@ %\center
|
||||||
\interlinepenalty \@M
|
\interlinepenalty \@M
|
||||||
\normalfont
|
\normalfont
|
||||||
\ifnum \c@secnumdepth >\m@ne
|
\ifnum \c@secnumdepth >\m@ne
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
\vskip 8ex
|
\vskip 8ex
|
||||||
\@afterheading}
|
\@afterheading}
|
||||||
\def\@spart#1{%
|
\def\@spart#1{%
|
||||||
{\parindent \z@ \center
|
{\parindent \z@ %\center
|
||||||
\interlinepenalty \@M
|
\interlinepenalty \@M
|
||||||
\normalfont
|
\normalfont
|
||||||
\huge \bfseries #1\par}%
|
\huge \bfseries #1\par}%
|
||||||
|
|
|
||||||
|
|
@ -27,45 +27,4 @@ following links:
|
||||||
.. _Jinja2: http://jinja.pocoo.org/2/
|
.. _Jinja2: http://jinja.pocoo.org/2/
|
||||||
.. _Werkzeug: http://werkzeug.pocoo.org/
|
.. _Werkzeug: http://werkzeug.pocoo.org/
|
||||||
|
|
||||||
User's Guide
|
.. include:: contents.rst.inc
|
||||||
------------
|
|
||||||
|
|
||||||
This part of the documentation is written text and should give you an idea
|
|
||||||
how to work with Flask. It's a series of step-by-step instructions for
|
|
||||||
web development.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
foreword
|
|
||||||
installation
|
|
||||||
quickstart
|
|
||||||
tutorial/index
|
|
||||||
testing
|
|
||||||
errorhandling
|
|
||||||
patterns/index
|
|
||||||
deploying/index
|
|
||||||
becomingbig
|
|
||||||
|
|
||||||
API Reference
|
|
||||||
-------------
|
|
||||||
|
|
||||||
If you are looking for information on a specific function, class or
|
|
||||||
method, this part of the documentation is for you:
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
api
|
|
||||||
|
|
||||||
Additional Notes
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Design notes, legal information and changelog are here for the interested:
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
design
|
|
||||||
license
|
|
||||||
changelog
|
|
||||||
|
|
|
||||||
|
|
@ -3,36 +3,4 @@
|
||||||
Flask Documentation
|
Flask Documentation
|
||||||
===================
|
===================
|
||||||
|
|
||||||
User's Guide
|
.. include:: contents.rst.inc
|
||||||
------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
|
|
||||||
foreword
|
|
||||||
installation
|
|
||||||
quickstart
|
|
||||||
tutorial/index
|
|
||||||
testing
|
|
||||||
errorhandling
|
|
||||||
patterns/index
|
|
||||||
deploying/index
|
|
||||||
becomingbig
|
|
||||||
|
|
||||||
API Reference
|
|
||||||
-------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
|
|
||||||
api
|
|
||||||
|
|
||||||
Additional Notes
|
|
||||||
----------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
|
|
||||||
design
|
|
||||||
license
|
|
||||||
changelog
|
|
||||||
|
|
|
||||||
110
docs/shell.rst
Normal file
110
docs/shell.rst
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
Working with the Shell
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. versionadded:: 0.5
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 "<stdin>", line 1, in <module>
|
||||||
|
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 request context:
|
||||||
|
|
||||||
|
>>> ctx = app.test_request_context('/?next=http://example.com/')
|
||||||
|
|
||||||
|
This context can be used in two ways. Either with the `with` statement
|
||||||
|
(which unfortunately is not very handy for shell sessions). The
|
||||||
|
alternative way is to call the `push` and `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()
|
||||||
|
>>> redirect_url()
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
AttributeError: 'NoneType' object has no attribute 'request'
|
||||||
|
|
||||||
|
|
||||||
|
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 probably results in your database
|
||||||
|
being unavailable, 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())
|
||||||
|
<Response 0 bytes [200 OK]>
|
||||||
|
>>> ctx.pop()
|
||||||
|
|
||||||
|
|
||||||
|
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 *
|
||||||
37
flask.py
37
flask.py
|
|
@ -147,15 +147,24 @@ class _RequestContext(object):
|
||||||
except HTTPException, e:
|
except HTTPException, e:
|
||||||
self.request.routing_exception = e
|
self.request.routing_exception = e
|
||||||
|
|
||||||
def __enter__(self):
|
def push(self):
|
||||||
|
"""Binds the request context."""
|
||||||
_request_ctx_stack.push(self)
|
_request_ctx_stack.push(self)
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
"""Pops the request context."""
|
||||||
|
_request_ctx_stack.pop()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.push()
|
||||||
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, tb):
|
def __exit__(self, exc_type, exc_value, tb):
|
||||||
# do not pop the request stack if we are in debug mode and an
|
# do not pop the request stack if we are in debug mode and an
|
||||||
# exception happened. This will allow the debugger to still
|
# exception happened. This will allow the debugger to still
|
||||||
# access the request object in the interactive shell.
|
# access the request object in the interactive shell.
|
||||||
if tb is None or not self.app.debug:
|
if tb is None or not self.app.debug:
|
||||||
_request_ctx_stack.pop()
|
self.pop()
|
||||||
|
|
||||||
|
|
||||||
def url_for(endpoint, **values):
|
def url_for(endpoint, **values):
|
||||||
|
|
@ -1202,6 +1211,30 @@ class Flask(_PackageBoundObject):
|
||||||
with app.request_context(environ):
|
with app.request_context(environ):
|
||||||
do_something_with(request)
|
do_something_with(request)
|
||||||
|
|
||||||
|
The object returned can also be used without the `with` statement
|
||||||
|
which is useful for working in the shell. The example above is
|
||||||
|
doing exactly the same as this code::
|
||||||
|
|
||||||
|
ctx = app.request_context(environ)
|
||||||
|
ctx.push()
|
||||||
|
try:
|
||||||
|
do_something_with(request)
|
||||||
|
finally:
|
||||||
|
ctx.pop()
|
||||||
|
|
||||||
|
The big advantage of this approach is that you can use it without
|
||||||
|
the try/finally statement in a shell for interactive testing:
|
||||||
|
|
||||||
|
>>> ctx = app.test_request_context()
|
||||||
|
>>> ctx.bind()
|
||||||
|
>>> request.path
|
||||||
|
u'/'
|
||||||
|
>>> ctx.unbind()
|
||||||
|
|
||||||
|
.. versionchanged:: 0.5
|
||||||
|
Added support for non-with statement usage and `with` statement
|
||||||
|
is now passed the ctx object.
|
||||||
|
|
||||||
:param environ: a WSGI environment
|
:param environ: a WSGI environment
|
||||||
"""
|
"""
|
||||||
return _RequestContext(self, environ)
|
return _RequestContext(self, environ)
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,23 @@ class ContextTestCase(unittest.TestCase):
|
||||||
with app.test_request_context('/meh'):
|
with app.test_request_context('/meh'):
|
||||||
assert meh() == 'http://localhost/meh'
|
assert meh() == 'http://localhost/meh'
|
||||||
|
|
||||||
|
def test_manual_context_binding(self):
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return 'Hello %s!' % flask.request.args['name']
|
||||||
|
|
||||||
|
ctx = app.test_request_context('/?name=World')
|
||||||
|
ctx.push()
|
||||||
|
assert index() == 'Hello World!'
|
||||||
|
ctx.pop()
|
||||||
|
try:
|
||||||
|
index()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert 0, 'expected runtime error'
|
||||||
|
|
||||||
|
|
||||||
class BasicFunctionalityTestCase(unittest.TestCase):
|
class BasicFunctionalityTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue