Skip to content
This repository
Browse code

Added interactive Python docs, fixed part style.

  • Loading branch information...
commit ef0dc1800f7558abbefe070f361b97b9161b2452 1 parent 9d98ad5
Armin Ronacher authored
4  CHANGES
@@ -13,6 +13,10 @@ Release date to be announced
13 13
   log request handling exceptions to that logger when not in debug
14 14
   mode.  This makes it possible to receive mails on server errors
15 15
   for example.
  16
+- added support for context binding that does not require the use of
  17
+  the with statement for playing in the console.
  18
+- the request context is now available within the with statement making
  19
+  it possible to further push the request context or pop it.
16 20
 
17 21
 Version 0.2
18 22
 -----------
43  docs/contents.rst.inc
... ...
@@ -0,0 +1,43 @@
  1
+User's Guide
  2
+------------
  3
+
  4
+This part of the documentation is written text and should give you an idea
  5
+how to work with Flask.  It's a series of step-by-step instructions for
  6
+web development.
  7
+
  8
+.. toctree::
  9
+   :maxdepth: 2
  10
+
  11
+   foreword
  12
+   installation
  13
+   quickstart
  14
+   tutorial/index
  15
+   testing
  16
+   errorhandling
  17
+   shell
  18
+   patterns/index
  19
+   deploying/index
  20
+   becomingbig
  21
+
  22
+API Reference
  23
+-------------
  24
+
  25
+If you are looking for information on a specific function, class or
  26
+method, this part of the documentation is for you.
  27
+
  28
+.. toctree::
  29
+   :maxdepth: 2
  30
+
  31
+   api
  32
+
  33
+Additional Notes
  34
+----------------
  35
+
  36
+Design notes, legal information and changelog are here for the interested.
  37
+
  38
+.. toctree::
  39
+   :maxdepth: 2
  40
+
  41
+   design
  42
+   license
  43
+   changelog
8  docs/flaskstyle.sty
... ...
@@ -1,4 +1,3 @@
1  
-\pagenumbering{arabic}
2 1
 \definecolor{TitleColor}{rgb}{0,0,0}
3 2
 \definecolor{InnerLinkColor}{rgb}{0,0,0}
4 3
 
@@ -72,9 +71,10 @@
72 71
 
73 72
 \renewcommand\thepart{\@Roman\c@part}
74 73
 \renewcommand\part{%
  74
+   \pagestyle{empty}
75 75
    \if@noskipsec \leavevmode \fi
76 76
    \cleardoublepage
77  
-   \vspace*{8cm}%
  77
+   \vspace*{6cm}%
78 78
    \@afterindentfalse
79 79
    \secdef\@part\@spart}
80 80
 
@@ -85,7 +85,7 @@
85 85
     \else
86 86
       \addcontentsline{toc}{part}{#1}%
87 87
     \fi
88  
-    {\parindent \z@ \center
  88
+    {\parindent \z@ %\center
89 89
      \interlinepenalty \@M
90 90
      \normalfont
91 91
      \ifnum \c@secnumdepth >\m@ne
@@ -98,7 +98,7 @@
98 98
     \vskip 8ex
99 99
     \@afterheading}
100 100
 \def\@spart#1{%
101  
-    {\parindent \z@ \center
  101
+    {\parindent \z@ %\center
102 102
      \interlinepenalty \@M
103 103
      \normalfont
104 104
      \huge \bfseries #1\par}%
43  docs/index.rst
Source Rendered
@@ -27,45 +27,4 @@ following links:
27 27
 .. _Jinja2: http://jinja.pocoo.org/2/
28 28
 .. _Werkzeug: http://werkzeug.pocoo.org/
29 29
 
30  
-User's Guide
31  
-------------
32  
-
33  
-This part of the documentation is written text and should give you an idea
34  
-how to work with Flask.  It's a series of step-by-step instructions for
35  
-web development.
36  
-
37  
-.. toctree::
38  
-   :maxdepth: 2
39  
-
40  
-   foreword
41  
-   installation
42  
-   quickstart
43  
-   tutorial/index
44  
-   testing
45  
-   errorhandling
46  
-   patterns/index
47  
-   deploying/index
48  
-   becomingbig
49  
-
50  
-API Reference
51  
--------------
52  
-
53  
-If you are looking for information on a specific function, class or
54  
-method, this part of the documentation is for you:
55  
-
56  
-.. toctree::
57  
-   :maxdepth: 2
58  
-
59  
-   api
60  
-
61  
-Additional Notes
62  
-----------------
63  
-
64  
-Design notes, legal information and changelog are here for the interested:
65  
-
66  
-.. toctree::
67  
-   :maxdepth: 2
68  
-
69  
-   design
70  
-   license
71  
-   changelog
  30
+.. include:: contents.rst.inc
34  docs/latexindex.rst
Source Rendered
@@ -3,36 +3,4 @@
3 3
 Flask Documentation
4 4
 ===================
5 5
 
6  
-User's Guide
7  
-------------
8  
-
9  
-.. toctree::
10  
-   :maxdepth: 3
11  
-
12  
-   foreword
13  
-   installation
14  
-   quickstart
15  
-   tutorial/index
16  
-   testing
17  
-   errorhandling
18  
-   patterns/index
19  
-   deploying/index
20  
-   becomingbig
21  
-
22  
-API Reference
23  
--------------
24  
-
25  
-.. toctree::
26  
-   :maxdepth: 3
27  
-
28  
-   api
29  
-
30  
-Additional Notes
31  
-----------------
32  
-
33  
-.. toctree::
34  
-   :maxdepth: 3
35  
-
36  
-   design
37  
-   license
38  
-   changelog
  6
+.. include:: contents.rst.inc
110  docs/shell.rst
Source Rendered
... ...
@@ -0,0 +1,110 @@
  1
+Working with the Shell
  2
+======================
  3
+
  4
+.. versionadded:: 0.5
  5
+
  6
+One of the reasons everybody loves Python is the interactive shell.  It
  7
+basically allows you to execute Python commands in real time and
  8
+immediately get results back.  Flask itself does not come with an
  9
+interactive shell, because it does not require any specific setup upfront,
  10
+just import your application and start playing around.
  11
+
  12
+There are however some handy helpers to make playing around in the shell a
  13
+more pleasant experience.  The main issue with interactive console
  14
+sessions is that you're not triggering a request like a browser does which
  15
+means that :data:`~flask.g`, :data:`~flask.request` and others are not
  16
+available.  But the code you want to test might depend on them, so what
  17
+can you do?
  18
+
  19
+This is where some helper functions come in handy.  Keep in mind however
  20
+that these functions are not only there for interactive shell usage, but
  21
+also for unittesting and other situations that require a faked request
  22
+context.
  23
+
  24
+Diving into Context Locals
  25
+--------------------------
  26
+
  27
+Say you have a utility function that returns the URL the user should be
  28
+redirected to.  Imagine it would always redirect to the URL's ``next``
  29
+parameter or the HTTP referrer or the index page::
  30
+
  31
+    from flask import request, url_for
  32
+
  33
+    def redirect_url():
  34
+        return request.args.get('next') or \
  35
+               request.referrer or \
  36
+               url_for('index')
  37
+
  38
+As you can see, it accesses the request object.  If you try to run this
  39
+from a plain Python shell, this is the exception you will see:
  40
+
  41
+>>> redirect_url()
  42
+Traceback (most recent call last):
  43
+  File "<stdin>", line 1, in <module>
  44
+AttributeError: 'NoneType' object has no attribute 'request'
  45
+
  46
+That makes a lot of sense because we currently do not have a request we
  47
+could access.  So we have to make a request and bind it to the current
  48
+context.  The :attr:`~flask.Flask.test_request_context` method can create
  49
+us a request context:
  50
+
  51
+>>> ctx = app.test_request_context('/?next=http://example.com/')
  52
+
  53
+This context can be used in two ways.  Either with the `with` statement
  54
+(which unfortunately is not very handy for shell sessions).  The
  55
+alternative way is to call the `push` and `pop` methods:
  56
+
  57
+>>> ctx.push()
  58
+
  59
+From that point onwards you can work with the request object:
  60
+
  61
+>>> redirect_url()
  62
+u'http://example.com/'
  63
+
  64
+Until you call `pop`:
  65
+
  66
+>>> ctx.pop()
  67
+>>> redirect_url()
  68
+Traceback (most recent call last):
  69
+  File "<stdin>", line 1, in <module>
  70
+AttributeError: 'NoneType' object has no attribute 'request'
  71
+
  72
+
  73
+Firing Before/After Request
  74
+---------------------------
  75
+
  76
+By just creating a request context, you still don't have run the code that
  77
+is normally run before a request.  This probably results in your database
  78
+being unavailable, the current user not being stored on the
  79
+:data:`~flask.g` object etc.
  80
+
  81
+This however can easily be done yourself.  Just call
  82
+:meth:`~flask.Flask.preprocess_request`:
  83
+
  84
+>>> ctx = app.test_request_context()
  85
+>>> ctx.push()
  86
+>>> app.preprocess_request()
  87
+
  88
+Keep in mind that the :meth:`~flask.Flask.preprocess_request` function
  89
+might return a response object, in that case just ignore it.
  90
+
  91
+To shutdown a request, you need to trick a bit before the after request
  92
+functions (triggered by :meth:`~flask.Flask.process_response`) operate on
  93
+a response object:
  94
+
  95
+>>> app.process_response(app.response_class())
  96
+<Response 0 bytes [200 OK]>
  97
+>>> ctx.pop()
  98
+
  99
+
  100
+Further Improving the Shell Experience
  101
+--------------------------------------
  102
+
  103
+If you like the idea of experimenting in a shell, create yourself a module
  104
+with stuff you want to star import into your interactive session.  There
  105
+you could also define some more helper methods for common things such as
  106
+initializing the database, dropping tables etc.
  107
+
  108
+Just put them into a module (like `shelltools` and import from there):
  109
+
  110
+>>> from shelltools import *
37  flask.py
@@ -147,15 +147,24 @@ def __init__(self, app, environ):
147 147
         except HTTPException, e:
148 148
             self.request.routing_exception = e
149 149
 
150  
-    def __enter__(self):
  150
+    def push(self):
  151
+        """Binds the request context."""
151 152
         _request_ctx_stack.push(self)
152 153
 
  154
+    def pop(self):
  155
+        """Pops the request context."""
  156
+        _request_ctx_stack.pop()
  157
+
  158
+    def __enter__(self):
  159
+        self.push()
  160
+        return self
  161
+
153 162
     def __exit__(self, exc_type, exc_value, tb):
154 163
         # do not pop the request stack if we are in debug mode and an
155 164
         # exception happened.  This will allow the debugger to still
156 165
         # access the request object in the interactive shell.
157 166
         if tb is None or not self.app.debug:
158  
-            _request_ctx_stack.pop()
  167
+            self.pop()
159 168
 
160 169
 
161 170
 def url_for(endpoint, **values):
@@ -1202,6 +1211,30 @@ def request_context(self, environ):
1202 1211
             with app.request_context(environ):
1203 1212
                 do_something_with(request)
1204 1213
 
  1214
+        The object returned can also be used without the `with` statement
  1215
+        which is useful for working in the shell.  The example above is
  1216
+        doing exactly the same as this code::
  1217
+
  1218
+            ctx = app.request_context(environ)
  1219
+            ctx.push()
  1220
+            try:
  1221
+                do_something_with(request)
  1222
+            finally:
  1223
+                ctx.pop()
  1224
+
  1225
+        The big advantage of this approach is that you can use it without
  1226
+        the try/finally statement in a shell for interactive testing:
  1227
+
  1228
+        >>> ctx = app.test_request_context()
  1229
+        >>> ctx.bind()
  1230
+        >>> request.path
  1231
+        u'/'
  1232
+        >>> ctx.unbind()
  1233
+
  1234
+        .. versionchanged:: 0.5
  1235
+           Added support for non-with statement usage and `with` statement
  1236
+           is now passed the ctx object.
  1237
+
1205 1238
         :param environ: a WSGI environment
1206 1239
         """
1207 1240
         return _RequestContext(self, environ)
17  tests/flask_tests.py
@@ -53,6 +53,23 @@ def meh():
53 53
         with app.test_request_context('/meh'):
54 54
             assert meh() == 'http://localhost/meh'
55 55
 
  56
+    def test_manual_context_binding(self):
  57
+        app = flask.Flask(__name__)
  58
+        @app.route('/')
  59
+        def index():
  60
+            return 'Hello %s!' % flask.request.args['name']
  61
+
  62
+        ctx = app.test_request_context('/?name=World')
  63
+        ctx.push()
  64
+        assert index() == 'Hello World!'
  65
+        ctx.pop()
  66
+        try:
  67
+            index()
  68
+        except AttributeError:
  69
+            pass
  70
+        else:
  71
+            assert 0, 'expected runtime error'
  72
+
56 73
 
57 74
 class BasicFunctionalityTestCase(unittest.TestCase):
58 75
 

0 notes on commit ef0dc18

Please sign in to comment.
Something went wrong with that request. Please try again.