Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added interactive Python docs, fixed part style.

  • Loading branch information...
commit ef0dc1800f7558abbefe070f361b97b9161b2452 1 parent 9d98ad5
@mitsuhiko authored
View
4 CHANGES
@@ -13,6 +13,10 @@ Release date to be announced
log request handling exceptions to that logger when not in debug
mode. This makes it possible to receive mails on server errors
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
-----------
View
43 docs/contents.rst.inc
@@ -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
View
8 docs/flaskstyle.sty
@@ -1,4 +1,3 @@
-\pagenumbering{arabic}
\definecolor{TitleColor}{rgb}{0,0,0}
\definecolor{InnerLinkColor}{rgb}{0,0,0}
@@ -72,9 +71,10 @@
\renewcommand\thepart{\@Roman\c@part}
\renewcommand\part{%
+ \pagestyle{empty}
\if@noskipsec \leavevmode \fi
\cleardoublepage
- \vspace*{8cm}%
+ \vspace*{6cm}%
\@afterindentfalse
\secdef\@part\@spart}
@@ -85,7 +85,7 @@
\else
\addcontentsline{toc}{part}{#1}%
\fi
- {\parindent \z@ \center
+ {\parindent \z@ %\center
\interlinepenalty \@M
\normalfont
\ifnum \c@secnumdepth >\m@ne
@@ -98,7 +98,7 @@
\vskip 8ex
\@afterheading}
\def\@spart#1{%
- {\parindent \z@ \center
+ {\parindent \z@ %\center
\interlinepenalty \@M
\normalfont
\huge \bfseries #1\par}%
View
43 docs/index.rst
@@ -27,45 +27,4 @@ following links:
.. _Jinja2: http://jinja.pocoo.org/2/
.. _Werkzeug: http://werkzeug.pocoo.org/
-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
- 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
+.. include:: contents.rst.inc
View
34 docs/latexindex.rst
@@ -3,36 +3,4 @@
Flask Documentation
===================
-User's Guide
-------------
-
-.. 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
+.. include:: contents.rst.inc
View
110 docs/shell.rst
@@ -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 *
View
37 flask.py
@@ -147,15 +147,24 @@ def __init__(self, app, environ):
except HTTPException, e:
self.request.routing_exception = e
- def __enter__(self):
+ def push(self):
+ """Binds the request context."""
_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):
# do not pop the request stack if we are in debug mode and an
# exception happened. This will allow the debugger to still
# access the request object in the interactive shell.
if tb is None or not self.app.debug:
- _request_ctx_stack.pop()
+ self.pop()
def url_for(endpoint, **values):
@@ -1202,6 +1211,30 @@ def request_context(self, environ):
with app.request_context(environ):
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
"""
return _RequestContext(self, environ)
View
17 tests/flask_tests.py
@@ -53,6 +53,23 @@ def meh():
with app.test_request_context('/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):
Please sign in to comment.
Something went wrong with that request. Please try again.