From cdb17c55b36b2b126ce318dbba2fe2ed9bae8bfa Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 21 Apr 2010 18:07:08 +0200 Subject: [PATCH] Moved website into separate branch --- .gitignore | 2 +- AUTHORS | 14 - CHANGES | 21 - LICENSE | 32 - Makefile | 17 - README | 31 - .../_mailinglist => _mailinglist}/.ignore | 0 artwork/logo-full.svg | 329 ------- docs/.gitignore | 1 - docs/Makefile | 118 --- docs/_static/debugger.png | Bin 123545 -> 0 bytes docs/_static/flask.png | Bin 9925 -> 0 bytes docs/_static/flaskr.png | Bin 53571 -> 0 bytes docs/_static/logo-full.png | Bin 23478 -> 0 bytes docs/_templates/sidebarintro.html | 13 - docs/_templates/sidebarlogo.html | 3 - docs/_themes/flasky/static/flasky.css_t | 344 -------- docs/_themes/flasky/theme.conf | 3 - docs/api.rst | 262 ------ docs/becomingbig.rst | 57 -- docs/changelog.rst | 1 - docs/conf.py | 247 ------ docs/deploying/cgi.rst | 42 - docs/deploying/fastcgi.rst | 128 --- docs/deploying/index.rst | 19 - docs/deploying/mod_wsgi.rst | 80 -- docs/deploying/others.rst | 48 -- docs/design.rst | 147 ---- docs/flaskext.py | 86 -- docs/foreword.rst | 94 -- docs/index.rst | 68 -- docs/installation.rst | 169 ---- docs/license.rst | 21 - docs/make.bat | 139 --- docs/patterns/flashing.rst | 81 -- docs/patterns/index.rst | 22 - docs/patterns/jquery.rst | 167 ---- docs/patterns/packages.rst | 86 -- docs/patterns/sqlalchemy.rst | 193 ----- docs/patterns/sqlite3.rst | 87 -- docs/patterns/templateinheritance.rst | 69 -- docs/patterns/wtforms.rst | 113 --- docs/quickstart.rst | 618 -------------- docs/testing.rst | 197 ----- docs/tutorial/css.rst | 27 - docs/tutorial/dbcon.rst | 33 - docs/tutorial/dbinit.rst | 63 -- docs/tutorial/folders.rst | 19 - docs/tutorial/index.rst | 32 - docs/tutorial/introduction.rst | 29 - docs/tutorial/schema.rst | 21 - docs/tutorial/setup.rst | 69 -- docs/tutorial/templates.rst | 107 --- docs/tutorial/testing.rst | 9 - docs/tutorial/views.rst | 87 -- examples/flaskr/README | 26 - examples/flaskr/flaskr.py | 98 --- examples/flaskr/flaskr_tests.py | 70 -- examples/flaskr/schema.sql | 6 - examples/flaskr/static/style.css | 18 - examples/flaskr/templates/layout.html | 17 - examples/flaskr/templates/login.html | 14 - examples/flaskr/templates/show_entries.html | 21 - examples/jqueryexample/jqueryexample.py | 29 - examples/jqueryexample/templates/index.html | 21 - examples/jqueryexample/templates/layout.html | 10 - examples/minitwit/README | 26 - examples/minitwit/minitwit.py | 249 ------ examples/minitwit/minitwit_tests.py | 149 ---- examples/minitwit/schema.sql | 21 - examples/minitwit/static/style.css | 178 ---- examples/minitwit/templates/layout.html | 32 - examples/minitwit/templates/login.html | 16 - examples/minitwit/templates/register.html | 19 - examples/minitwit/templates/timeline.html | 49 -- flask.py | 801 ------------------ website/flask_website.py => flask_website.py | 0 setup.py | 71 -- {website/static => static}/logo.png | Bin {website/static => static}/mailinglist.js | 0 {website/static => static}/mailinglist.png | Bin {website/static => static}/mask.png | Bin {website/static => static}/ship.png | Bin {website/static => static}/style.css | 0 .../sync-librelist.py => sync-librelist.py | 0 {website/templates => templates}/404.html | 0 {website/templates => templates}/index.html | 0 {website/templates => templates}/layout.html | 0 .../mailinglist/archive.html | 0 .../mailinglist/index.html | 0 .../mailinglist/layout.html | 0 .../mailinglist/show_thread.html | 0 tests/flask_tests.py | 316 ------- tests/static/index.html | 1 - tests/templates/_macro.html | 1 - tests/templates/context_template.html | 1 - tests/templates/escaping_template.html | 6 - 97 files changed, 1 insertion(+), 6930 deletions(-) delete mode 100644 AUTHORS delete mode 100644 CHANGES delete mode 100644 LICENSE delete mode 100644 Makefile delete mode 100644 README rename {website/_mailinglist => _mailinglist}/.ignore (100%) delete mode 100755 artwork/logo-full.svg delete mode 100644 docs/.gitignore delete mode 100644 docs/Makefile delete mode 100644 docs/_static/debugger.png delete mode 100644 docs/_static/flask.png delete mode 100644 docs/_static/flaskr.png delete mode 100644 docs/_static/logo-full.png delete mode 100644 docs/_templates/sidebarintro.html delete mode 100644 docs/_templates/sidebarlogo.html delete mode 100644 docs/_themes/flasky/static/flasky.css_t delete mode 100644 docs/_themes/flasky/theme.conf delete mode 100644 docs/api.rst delete mode 100644 docs/becomingbig.rst delete mode 100644 docs/changelog.rst delete mode 100644 docs/conf.py delete mode 100644 docs/deploying/cgi.rst delete mode 100644 docs/deploying/fastcgi.rst delete mode 100644 docs/deploying/index.rst delete mode 100644 docs/deploying/mod_wsgi.rst delete mode 100644 docs/deploying/others.rst delete mode 100644 docs/design.rst delete mode 100644 docs/flaskext.py delete mode 100644 docs/foreword.rst delete mode 100644 docs/index.rst delete mode 100644 docs/installation.rst delete mode 100644 docs/license.rst delete mode 100644 docs/make.bat delete mode 100644 docs/patterns/flashing.rst delete mode 100644 docs/patterns/index.rst delete mode 100644 docs/patterns/jquery.rst delete mode 100644 docs/patterns/packages.rst delete mode 100644 docs/patterns/sqlalchemy.rst delete mode 100644 docs/patterns/sqlite3.rst delete mode 100644 docs/patterns/templateinheritance.rst delete mode 100644 docs/patterns/wtforms.rst delete mode 100644 docs/quickstart.rst delete mode 100644 docs/testing.rst delete mode 100644 docs/tutorial/css.rst delete mode 100644 docs/tutorial/dbcon.rst delete mode 100644 docs/tutorial/dbinit.rst delete mode 100644 docs/tutorial/folders.rst delete mode 100644 docs/tutorial/index.rst delete mode 100644 docs/tutorial/introduction.rst delete mode 100644 docs/tutorial/schema.rst delete mode 100644 docs/tutorial/setup.rst delete mode 100644 docs/tutorial/templates.rst delete mode 100644 docs/tutorial/testing.rst delete mode 100644 docs/tutorial/views.rst delete mode 100644 examples/flaskr/README delete mode 100644 examples/flaskr/flaskr.py delete mode 100644 examples/flaskr/flaskr_tests.py delete mode 100644 examples/flaskr/schema.sql delete mode 100644 examples/flaskr/static/style.css delete mode 100644 examples/flaskr/templates/layout.html delete mode 100644 examples/flaskr/templates/login.html delete mode 100644 examples/flaskr/templates/show_entries.html delete mode 100644 examples/jqueryexample/jqueryexample.py delete mode 100644 examples/jqueryexample/templates/index.html delete mode 100644 examples/jqueryexample/templates/layout.html delete mode 100644 examples/minitwit/README delete mode 100644 examples/minitwit/minitwit.py delete mode 100644 examples/minitwit/minitwit_tests.py delete mode 100644 examples/minitwit/schema.sql delete mode 100644 examples/minitwit/static/style.css delete mode 100644 examples/minitwit/templates/layout.html delete mode 100644 examples/minitwit/templates/login.html delete mode 100644 examples/minitwit/templates/register.html delete mode 100644 examples/minitwit/templates/timeline.html delete mode 100644 flask.py rename website/flask_website.py => flask_website.py (100%) delete mode 100644 setup.py rename {website/static => static}/logo.png (100%) rename {website/static => static}/mailinglist.js (100%) rename {website/static => static}/mailinglist.png (100%) rename {website/static => static}/mask.png (100%) rename {website/static => static}/ship.png (100%) rename {website/static => static}/style.css (100%) rename website/sync-librelist.py => sync-librelist.py (100%) rename {website/templates => templates}/404.html (100%) rename {website/templates => templates}/index.html (100%) rename {website/templates => templates}/layout.html (100%) rename {website/templates => templates}/mailinglist/archive.html (100%) rename {website/templates => templates}/mailinglist/index.html (100%) rename {website/templates => templates}/mailinglist/layout.html (100%) rename {website/templates => templates}/mailinglist/show_thread.html (100%) delete mode 100644 tests/flask_tests.py delete mode 100644 tests/static/index.html delete mode 100644 tests/templates/_macro.html delete mode 100644 tests/templates/context_template.html delete mode 100644 tests/templates/escaping_template.html diff --git a/.gitignore b/.gitignore index f250e7a5..59d86186 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ *.pyo env dist -website/_mailinglist/* +_mailinglist/* *.egg-info diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 2c125e11..00000000 --- a/AUTHORS +++ /dev/null @@ -1,14 +0,0 @@ -Flask is written and maintained by Armin Ronacher and -various contributors: - -Development Lead -```````````````` - -- Armin Ronacher - -Patches and Suggestions -``````````````````````` - -- Chris Edgemon -- Chris Grindstaff -- Florent Xicluna diff --git a/CHANGES b/CHANGES deleted file mode 100644 index ce7289da..00000000 --- a/CHANGES +++ /dev/null @@ -1,21 +0,0 @@ -Flask Changelog -=============== - -Here you can see the full list of changes between each Flask release. - -Version 0.2 ------------ - -[unreleased; current development version] - -- various bugfixes -- integrated JSON support -- added :func:`~flask.get_template_attribute` helper function. -- :meth:`~flask.Flask.add_url_rule` can now also register a - view function. -- server listens on 127.0.0.1 by default now to fix issues with chrome. - -Version 0.1 ------------ - -First public preview release. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 6a8df19e..00000000 --- a/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS -for more details. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -* The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 0be5e6bc..00000000 --- a/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -.PHONY: clean-pyc test - -all: clean-pyc test - -test: - python tests/flask_tests.py - -clean-pyc: - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - -upload-website: - scp -r website/* pocoo.org:/var/www/flask.pocoo.org/ - -upload-docs: - $(MAKE) -C docs dirhtml && scp -r docs/_build/dirhtml/* pocoo.org:/var/www/flask.pocoo.org/docs/ diff --git a/README b/README deleted file mode 100644 index 73e0bbf1..00000000 --- a/README +++ /dev/null @@ -1,31 +0,0 @@ - - // Flask // - - because sometimes a pocket knife is not enough - - - ~ What is Flask? - - Flask is a microframework for Python based on Werkzeug - and Jinja2. It's intended for small scale applications - and was developped with best intentions in mind. - - ~ Is it ready? - - A preview release is out now, and I'm hoping for some - input about what you want from a microframework and - how it should look like. Consider the API to slightly - improve over time. - - ~ What do I need? - - Jinja 2.4 and Werkzeug 0.6.1. `easy_install` will - install them for you if you do `easy_install Flask==dev`. - I encourage you to use a virtualenv. Check the docs for - complete installation and usage instructions. - - ~ Where are the docs? - - Go to http://flask.pocoo.org/ for a prebuilt version of - the current documentation. Otherwise build them yourself - from the sphinx sources in the docs folder. diff --git a/website/_mailinglist/.ignore b/_mailinglist/.ignore similarity index 100% rename from website/_mailinglist/.ignore rename to _mailinglist/.ignore diff --git a/artwork/logo-full.svg b/artwork/logo-full.svg deleted file mode 100755 index 43465a4d..00000000 --- a/artwork/logo-full.svg +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index e35d8850..00000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 52d78d9e..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,118 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp epub latex changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) _build/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/Flask" - @echo "# ln -s _build/devhelp $$HOME/.local/share/devhelp/Flask" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ - "run these through (pdf)latex." - -latexpdf: latex - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex - @echo "Running LaTeX files through pdflatex..." - make -C _build/latex all-pdf - @echo "pdflatex finished; the PDF files are in _build/latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/_static/debugger.png b/docs/_static/debugger.png deleted file mode 100644 index 4f47229d6a24d5e42980c274591b1de30d7ff0d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123545 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 z 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 z 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 diff --git a/docs/_static/flaskr.png b/docs/_static/flaskr.png deleted file mode 100644 index 07d027dd973f6ecf02986d98bc8bf541e174c057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53571 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ÐNKC!{nB=)@lkWiHYwoId6sR_vl!q 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 S^>upy0000About Flask -

- Flask is a micro webdevelopment framework for Python. You are currently - looking at the documentation of the development version. Things are - not stable yet, but if you have some feedback, - let me know. -

-

Useful Links

- diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html deleted file mode 100644 index 3bc7f762..00000000 --- a/docs/_templates/sidebarlogo.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/docs/_themes/flasky/static/flasky.css_t b/docs/_themes/flasky/static/flasky.css_t deleted file mode 100644 index 04c5c5f6..00000000 --- a/docs/_themes/flasky/static/flasky.css_t +++ /dev/null @@ -1,344 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- flasky theme based on nature theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 17px; - background-color: #ddd; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - background: #fafafa; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 30px 30px; - min-height: 34em; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - position: absolute; - right: 0; - margin-top: -70px; - text-align: right; - color: #888; - padding: 10px; - font-size: 14px; -} - -div.footer a { - color: #888; - text-decoration: underline; -} - -div.related { - line-height: 32px; - color: #888; -} - -div.related ul { - padding: 0 0 0 10px; -} - -div.related a { - color: #444; -} - -div.sphinxsidebar { - font-size: 14px; - line-height: 1.5; -} - -div.sphinxsidebarwrapper { - padding: 0 20px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 20px 0 10px 0; - margin: 0; - text-align: center; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: 'Garamond', 'Georgia', serif; - color: #222; - font-size: 24px; - font-weight: normal; - margin: 20px 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar a { - color: #444; - text-decoration: none; -} - -div.sphinxsidebar a:hover { - text-decoration: underline; -} - -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 { - padding-bottom: 40px; /* saved for footer */ -} - -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: 20px; 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: white; - 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 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; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -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; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td { - padding: 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -pre { - background: #eee; - padding: 7px 30px; - margin: 15px -30px; - line-height: 1.3em; -} - -dl 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; -} - -a:hover tt { - background: #EEE; -} diff --git a/docs/_themes/flasky/theme.conf b/docs/_themes/flasky/theme.conf deleted file mode 100644 index cb9eb465..00000000 --- a/docs/_themes/flasky/theme.conf +++ /dev/null @@ -1,3 +0,0 @@ -[theme] -inherit = basic -stylesheet = flasky.css diff --git a/docs/api.rst b/docs/api.rst deleted file mode 100644 index d285dbfd..00000000 --- a/docs/api.rst +++ /dev/null @@ -1,262 +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: - -Incoming Request Data ---------------------- - -.. autoclass:: Request - -.. 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. - - The request object is an instance of a :class:`~werkzeug.Request` - subclass and provides all of the attributes Werkzeug defines. This - just shows a quick overview of the most important ones. - - .. attribute:: form - - A :class:`~werkzeug.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.MultiDict` with the parsed contents of the query - string. (The part in the URL after the question mark). - - .. attribute:: values - - A :class:`~werkzeug.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:: data - - Contains the incoming request data as string in case it came with - a mimetype Flask does not handle. - - .. attribute:: files - - A :class:`~werkzeug.MultiDict` with files uploaded as part of a - `POST` or `PUT` request. Each file is stored as - :class:`~werkzeug.FileStorage` object. It basically behaves like a - standard file object you know from Python, with the difference that - it also has a :meth:`~werkzeug.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`` - `url` ``http://www.example.com/myapplication/page.html`` - `base_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. - - .. attribute:: json - - Contains the parsed body of the JSON request if the mimetype of - the incoming data was `application/json`. This requires Python 2.6 - or an installed version of simplejson. - -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 he knows 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. - - 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 - - -Application Globals -------------------- - -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. - - -Useful Functions and Classes ----------------------------- - -.. autofunction:: url_for - -.. function:: abort(code) - - Raises an :exc:`~werkzeug.exception.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:: 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 diff --git a/docs/becomingbig.rst b/docs/becomingbig.rst deleted file mode 100644 index 02344720..00000000 --- a/docs/becomingbig.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. _becomingbig: - -Becoming Big -============ - -Your application is becoming more and more complex? Flask is really not -designed for large scale applications and does not attempt to do so, but -that does not mean you picked the wrong tool in the first place. - -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 is literally a single file. -What that means for large applications is that it's probably a good idea -to take the code from Flask and put it into a new module within the -applications and expand on that. - -What Could Be Improved? ------------------------ - -For instance it makes a lot of sense to change the way endpoints (the -names of the functions / URL rules) are handled to also take the module -name into account. Right now the function name is the URL name, but -imagine you have a large application consisting of multiple components. -In that case, it makes a lot of sense to use dotted names for the URL -endpoints. - -Here are some suggestions for how Flask can be modified to better -accomodate large-scale applications: - -- implement dotted names for URL endpoints -- get rid of the decorator function registering which causes a lot - of troubles for applications that have circular dependencies. It - also requires that the whole application is imported when the system - initializes or certain URLs will not be available right away. A - better solution would be to have one module with all URLs in there and - specifing the target functions explicitly or by name and importing - them when needed. -- switch to explicit request object passing. This requires more typing - (because you now have something to pass around) but it makes it a - whole lot easier to debug hairy situations and to test the code. -- integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the - core framework. - -.. _Babel: http://babel.edgewall.org/ -.. _SQLAlchemy: http://www.sqlalchemy.org/ - -Why does Flask not do all that by Default? ------------------------------------------- - -There is a huge difference between a small application that only has to -handle a couple of requests per second and with an overall code complexity -of less than 4000 lines of code and something of larger scale. At some -point it becomes important to integrate external systems, different -storage backends and more. - -If Flask was designed with all these contingencies in mind, it would be a -much more complex framework and harder to get started with. diff --git a/docs/changelog.rst b/docs/changelog.rst deleted file mode 100644 index d6c5f48c..00000000 --- a/docs/changelog.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../CHANGES diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 03e27217..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Flask documentation build configuration file, created by -# sphinx-quickstart on Tue Apr 6 15:24:58 2010. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.append(os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Flask' -copyright = u'2010, Armin Ronacher' - -import pkg_resources - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -release = __import__('pkg_resources').get_distribution('Flask').version -version = '.'.join(release.split('.')[:2]) - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'flaskext.FlaskyStyle' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = 'flasky' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['_themes'] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. Do not set, template magic! -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], - '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', - 'sourcelink.html', 'searchbox.html'] -} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_use_modindex = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Flaskdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' - -# The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'Flask.tex', u'Flask Documentation', - u'Armin Ronacher', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_use_modindex = True - - -# -- Options for Epub output --------------------------------------------------- - -# Bibliographic Dublin Core info. -#epub_title = '' -#epub_author = '' -#epub_publisher = '' -#epub_copyright = '' - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -intersphinx_mapping = { - 'http://docs.python.org/dev': None, - 'http://werkzeug.pocoo.org/documentation/dev/': None, - 'http://www.sqlalchemy.org/docs/': None, - 'http://wtforms.simplecodes.com/docs/0.5/': None -} diff --git a/docs/deploying/cgi.rst b/docs/deploying/cgi.rst deleted file mode 100644 index 15b5ff1d..00000000 --- a/docs/deploying/cgi.rst +++ /dev/null @@ -1,42 +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 less-than-optimal -performance. - -This is also the way you can use a Flask application on Google's -`AppEngine`_, there however the execution does happen in a CGI-like -environment. The application's performance is unaffected because of that. - -.. _AppEngine: http://code.google.com/appengine/ - -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) - -If you're running Python 2.4 you will need the :mod:`wsgiref` package. Python -2.5 and higher ship this as part of the standard library. - -Server Setup ------------- - -Usually there are two ways to configure the server. Either just copy the -`.cgi` into a `cgi-bin` (and use `mod_rerwite` 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. diff --git a/docs/deploying/fastcgi.rst b/docs/deploying/fastcgi.rst deleted file mode 100644 index b549ddfd..00000000 --- a/docs/deploying/fastcgi.rst +++ /dev/null @@ -1,128 +0,0 @@ -FastCGI -======= - -A very popular deployment setup on servers like `lighttpd`_ and `nginx`_ -is FastCGI. 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. - -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 - - WSGIServer(app).run() - -This is enough for Apache to work, however lighttpd and nginx need a -socket 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:: - - # chmod +x /var/www/yourapplication/yourapplication.fcgi - -Configuring lighttpd --------------------- - -A basic FastCGI configuration for lighttpd looks like that:: - - fastcgi.server = ("/yourapplication" => - "yourapplication" => ( - "socket" => "/tmp/yourapplication-fcgi.sock", - "bin-path" => "/var/www/yourapplication/yourapplication.fcgi", - "check-local" => "disable" - ) - ) - -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. - -Configuring nginx ------------------ - -Installing FastCGI applications on nginx is a bit tricky because by default -some FastCGI parameters are not properly forwarded. - -A basic FastCGI configuration for nginx looks like this:: - - location /yourapplication/ { - include fastcgi_params; - if ($uri ~ ^/yourapplication/(.*)?) { - set $path_url $1; - } - fastcgi_param PATH_INFO $path_url; - fastcgi_param SCRIPT_NAME /yourapplication; - 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 easier because you don't have to figure -out how to calculate `PATH_INFO` and `SCRIPT_NAME`:: - - location /yourapplication/ { - include fastcgi_params; - fastcgi_param PATH_INFO $fastcgi_script_name; - fastcgi_param SCRIPT_NAME ""; - fastcgi_pass unix:/tmp/yourapplication-fcgi.sock; - } - -Since Nginx doesn't load FastCGI apps, you have to do it by yourself. You -can either write an `init.d` script for that or execute it inside a screen -session:: - - $ 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.fcg", 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. - -.. _lighttpd: http://www.lighttpd.net/ -.. _nginx: http://nginx.net/ -.. _flup: http://trac.saddi.com/flup diff --git a/docs/deploying/index.rst b/docs/deploying/index.rst deleted file mode 100644 index a59e4e9a..00000000 --- a/docs/deploying/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -Deployment Options -================== - -Depending on what you have available there are multiple ways to run Flask -applications. A very common method is to use the builtin server during -development and maybe behind a proxy for simple applications, but there -are more options available. - -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 application object -is the actual WSGI application. - -.. toctree:: - :maxdepth: 2 - - mod_wsgi - cgi - fastcgi - others diff --git a/docs/deploying/mod_wsgi.rst b/docs/deploying/mod_wsgi.rst deleted file mode 100644 index a7bbc114..00000000 --- a/docs/deploying/mod_wsgi.rst +++ /dev/null @@ -1,80 +0,0 @@ -mod_wsgi (Apache) -================= - -If you are using the `Apache`_ webserver you should consider using `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:: - - # apt-get install libapache2-mod-wsgi - -On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by using -pkg_add:: - - # 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/ diff --git a/docs/deploying/others.rst b/docs/deploying/others.rst deleted file mode 100644 index 4e2f966c..00000000 --- a/docs/deploying/others.rst +++ /dev/null @@ -1,48 +0,0 @@ -Other Servers -============= - -There are popular servers written in Python that allow the execution of -WSGI applications as well. Keep in mind though that some of these servers -were written for very specific applications and might not work as well for -standard WSGI application such as Flask powered ones. - - -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/ diff --git a/docs/design.rst b/docs/design.rst deleted file mode 100644 index c4fd32dd..00000000 --- a/docs/design.rst +++ /dev/null @@ -1,147 +0,0 @@ -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 class at -the time. There are ways to fake multiple application 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 laying -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 instanciation 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`). - -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. - - -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 depencencies 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 asyncronous 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. diff --git a/docs/flaskext.py b/docs/flaskext.py deleted file mode 100644 index 33f47449..00000000 --- a/docs/flaskext.py +++ /dev/null @@ -1,86 +0,0 @@ -# flasky extensions. flasky pygments style based on tango style -from pygments.style import Style -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Whitespace, Punctuation, Other, Literal - - -class FlaskyStyle(Style): - background_color = "#f8f8f8" - default_style = "" - - styles = { - # No corresponding class for the following: - #Text: "", # class: '' - Whitespace: "underline #f8f8f8", # class: 'w' - Error: "#a40000 border:#ef2929", # class: 'err' - Other: "#000000", # class 'x' - - Comment: "italic #8f5902", # class: 'c' - Comment.Preproc: "noitalic", # class: 'cp' - - Keyword: "bold #004461", # class: 'k' - Keyword.Constant: "bold #004461", # class: 'kc' - Keyword.Declaration: "bold #004461", # class: 'kd' - Keyword.Namespace: "bold #004461", # class: 'kn' - Keyword.Pseudo: "bold #004461", # class: 'kp' - Keyword.Reserved: "bold #004461", # class: 'kr' - Keyword.Type: "bold #004461", # class: 'kt' - - Operator: "#582800", # class: 'o' - Operator.Word: "bold #004461", # class: 'ow' - like keywords - - Punctuation: "bold #000000", # class: 'p' - - # because special names such as Name.Class, Name.Function, etc. - # are not recognized as such later in the parsing, we choose them - # to look the same as ordinary variables. - Name: "#000000", # class: 'n' - Name.Attribute: "#c4a000", # class: 'na' - to be revised - Name.Builtin: "#004461", # class: 'nb' - Name.Builtin.Pseudo: "#3465a4", # class: 'bp' - Name.Class: "#000000", # class: 'nc' - to be revised - Name.Constant: "#000000", # class: 'no' - to be revised - Name.Decorator: "#888", # class: 'nd' - to be revised - Name.Entity: "#ce5c00", # class: 'ni' - Name.Exception: "bold #cc0000", # class: 'ne' - Name.Function: "#000000", # class: 'nf' - Name.Property: "#000000", # class: 'py' - Name.Label: "#f57900", # class: 'nl' - Name.Namespace: "#000000", # class: 'nn' - to be revised - Name.Other: "#000000", # class: 'nx' - Name.Tag: "bold #004461", # class: 'nt' - like a keyword - Name.Variable: "#000000", # class: 'nv' - to be revised - Name.Variable.Class: "#000000", # class: 'vc' - to be revised - Name.Variable.Global: "#000000", # class: 'vg' - to be revised - Name.Variable.Instance: "#000000", # class: 'vi' - to be revised - - Number: "#990000", # class: 'm' - - Literal: "#000000", # class: 'l' - Literal.Date: "#000000", # class: 'ld' - - String: "#4e9a06", # class: 's' - String.Backtick: "#4e9a06", # class: 'sb' - String.Char: "#4e9a06", # class: 'sc' - String.Doc: "italic #8f5902", # class: 'sd' - like a comment - String.Double: "#4e9a06", # class: 's2' - String.Escape: "#4e9a06", # class: 'se' - String.Heredoc: "#4e9a06", # class: 'sh' - String.Interpol: "#4e9a06", # class: 'si' - String.Other: "#4e9a06", # class: 'sx' - String.Regex: "#4e9a06", # class: 'sr' - String.Single: "#4e9a06", # class: 's1' - String.Symbol: "#4e9a06", # class: 'ss' - - Generic: "#000000", # class: 'g' - Generic.Deleted: "#a40000", # class: 'gd' - Generic.Emph: "italic #000000", # class: 'ge' - Generic.Error: "#ef2929", # class: 'gr' - Generic.Heading: "bold #000080", # class: 'gh' - Generic.Inserted: "#00A000", # class: 'gi' - Generic.Output: "#888", # class: 'go' - Generic.Prompt: "#745334", # class: 'gp' - Generic.Strong: "bold #000000", # class: 'gs' - Generic.Subheading: "bold #800080", # class: 'gu' - Generic.Traceback: "bold #a40000", # class: 'gt' - } diff --git a/docs/foreword.rst b/docs/foreword.rst deleted file mode 100644 index deeff8ca..00000000 --- a/docs/foreword.rst +++ /dev/null @@ -1,94 +0,0 @@ -Foreword -======== - -Read this before you get started with Flask. This hopefully answers some -questions about the intention of the project, what it aims at and when you -should or should not be using it. - -What does Micro Mean? ---------------------- - -The micro in microframework for me means on the one hand being small in -size and complexity but on the other hand also that the complexity of the -applications that are written with these frameworks do not exceed a -certain size. A microframework like Flask sacrifices a few things in -order to be approachable and to be as concise as possible. - -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 also does not scale well to large applications. -It's especially painful for more complex unittests and when you suddenly -have to deal with code being executed outside of the context of a request -(for example if you have cronjobs). - -Flask provides some tools to deal with the downsides of this approach but -the core problem of this approach obviously stays. It is also based on -convention over configuration which means that a lot of things are -preconfigured in Flask and will work well for smaller applications but not -so much for larger ones (where and how it looks for templates, static -files etc.) - -But don't worry if your application suddenly grows larger than it was -initially and you're afraid Flask might not grow with it. Even with -larger frameworks you sooner or later will find out that you need -something the framework just cannot do for you without modification. -If you are ever in that situation, check out the :ref:`becomingbig` -chapter. - -A Framework and An Example --------------------------- - -Flask is not only a microframework, it is also an example. Based on -Flask, there will be a series of blog posts that explain how to create a -framework. Flask itself is just one way to implement a framework on top -of existing libraries. Unlike many other microframeworks Flask does not -try to implement anything on its own, it reuses existing code. - -Web Development is Dangerous ----------------------------- - -I'm not even 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 in a secure manner. - -Unfortunately there are many ways 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. - -Whenever something is dangerous where you have to watch out, the -documentation will tell you so. Some of the security concerns of web -development are far more complex than one might think and often we all end -up in situations where we think "well, this is just far fetched, how could -that possibly be exploited" and then an intelligent guy comes along and -figures a way out to exploit that application. And don't think, your -application is not important enough for hackers to take notice. Depending -ont he kind of attack, chances are there are automated botnets out there -trying to figure out how to fill your database with viagra adverisments. - -So always keep that in mind when doing web development. - -Target Audience ---------------- - -Is Flask for you? Is your application small-ish (less than 4000 lines of -Python code) and does not depend on too complex database structures, Flask -is the Framework for you. It was designed from the ground up to be easy -to use, based on established principles, good intentions and on top of two -established libraries in widespread usage. - -Flask serves two purposes: it's an example of how to create a minimal and -opinionated framework on top of Werkzeug to show how this can be done, and -to provide people with a simple tool to prototype larger applications or -to implement small and medium sized applications. - -If you suddenly discover that your application grows larger than -originally intended, head over to the :ref:`becomingbig` section to see -some possible solutions for larger applications. - -Satisfied? Then head over to the :ref:`installation`. diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 1f3b6460..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,68 +0,0 @@ -Welcome to Flask -================ - -.. image:: _static/logo-full.png - :alt: The Flask Logo with Subtitle - :class: floatingflask - -Welcome to Flask's documentation. This documentation is divided in -different parts. I would suggest to get started with the -:ref:`installation` and then heading over to the :ref:`quickstart`. -Besides the quickstart there is also a more detailed :ref:`tutorial` that -shows how to create a complete (albeit small) application with Flask. If -you rather want to dive into all the internal parts of Flask, check out -the :ref:`api` documentation. Common patterns are described in the -:ref:`patterns` section. - -Flask also depends on two external libraries: the `Jinja2`_ template -engine and the `Werkzeug`_ WSGI toolkit. both of which are not documented -here. If you want to dive into their documentation check out the -following links: - -- `Jinja2 Documentation `_ -- `Werkzeug Documentation `_ - -.. _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 - patterns/index - deploying/index - becomingbig - -Additional Notes ----------------- - -Design notes, legal information and changelog are here for the interested: - -.. toctree:: - :maxdepth: 2 - - design - license - changelog - -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 diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index bb85b405..00000000 --- a/docs/installation.rst +++ /dev/null @@ -1,169 +0,0 @@ -.. _installation: - -Installation -============ - -Flask is a microframework and yet it depends on external libraries. There -are various ways how you can install that library and this explains each -way and why there are multiple ways. - -Flask depends on two external libraries: `Werkzeug -`_ and `Jinja2 `_. -The first on is responsible for interfacing WSGI the latter to render -templates. Now you are maybe asking, what is WSGI? WSGI is a standard -in Python that is basically responsible for ensuring that your application -is behaving in a specific way that you can run it on different -environments (for example on a local development server, on an Apache2, on -lighttpd, on Google's App Engine or whatever you have in mind). - -So how do you get all that on your computer in no time? The most kick-ass -method is virtualenv, so let's look at that first. - -virtualenv ----------- - -Virtualenv is what you want to use during development and in production if -you have shell access. So first: what does virtualenv do? If you are -like me and you like Python, chances are you want to use it for another -project as well. Now the more projects you have, the more likely it is -that you will be working with different versions of Python itself or a -library involved. Because let's face it: quite often libraries break -backwards compatibility and it's unlikely that your application will -not have any dependencies, that just won't happen. So virtualenv for the -rescue! - -It basically makes it possible to have multiple side-by-side -"installations" of Python, each for your own project. It's not actually -an installation but a clever way to keep things separated. - -So let's see how that works! - -If you are on OS X or Linux chances are that one of the following two -commands will for for you:: - - $ sudo easy_install virtualenv - -or even better:: - - $ sudo pip install virtualenv - -Changes are you have virtualenv installed on your system then. Maybe it's -even in your package manager (on ubuntu try ``sudo apt-get install -python-virtualenv``). - -If you are on Windows and missing the `easy_install` command you have to -install it first. Check the :ref:`windows-easy-install` section for more -information about how to do that. Once you have it installed, run the -same commands as above, but without the `sudo` part. - -So now that you have virtualenv running just fire up a shell and create -your own environment. I usually create a folder and a `env` folder -within:: - - $ mkdir myproject - $ cd myproject - $ virtualenv env - New python executable in env/bin/python - Installing setuptools............done. - -Now you only have to activate it, whenever you work with it. On OS X and -Linux do the following:: - - $ source env/bin/activate - -If you are a Windows user, the following command is for you:: - - $ env\scripts\activate - -Either way, you should now be using your virtualenv (see how the prompt of -your shell has changed to show the virtualenv). - -Now you can just enter the following command to get Flask activated in -your virtualenv:: - - $ easy_install Flask - -A few seconds later you are good to go. - - -System Wide Installation ------------------------- - -This is possible as well, but I would not recommend it. Just run -`easy_install` with root rights:: - - sudo easy_install Flask - -(Run it in an Admin shell on Windows systems and without the `sudo`). - - -Leaving on the Edge -------------------- - -You want to work with the latest version of Flask, there are two ways: you -can either let `easy_install` pull in the development version or tell it -to operate on a git checkout. Either way it's recommended to do that in a -virtualenv. - -Get the git checkout in a new virtualenv and run in develop mode:: - - $ git clone http://github.com/mitsuhiko/flask.git - Initialized empty Git repository in ~/dev/flask/.git/ - $ cd flask - $ virtualenv env - $ source env/bin/activate - New python executable in env/bin/python - Installing setuptools............done. - $ python setup.py develop - ... - Finished processing dependencies for Flask - -This will pull in the depdenencies and activate the git head as current -version. Then you just have to ``git pull origin`` to get the latest -version. - -To just get the development version without git, do this instead:: - - $ mkdir flask - $ cd flask - $ virtualenv env - $ source env/bin/activate - New python executable in env/bin/python - Installing setuptools............done. - $ easy_install Flask==dev - ... - Finished processing dependencies for Flask==dev - -.. _windows-easy-install: - -`easy_install` on Windows -------------------------- - -On Windows installation of `easy_install` is a little bit tricker because -on Windows slightly different rules apply, but it's not a biggy. The -easiest way to accomplish that is downloading the `ez_setup.py`_ file and -running it. (Double clicking should do the trick) - -Once you have done that it's important to add the `easy_install` command -and other Python scripts to the path. To do that you have to add the -Python installation's Script folder to the `PATH` variable. - -To do that, click right on your "Computer" desktop icon and click -"Properties". On Windows Vista and Windows 7 then click on "Advanced System -settings", on Windows XP click on the "Advanced" tab instead. Then click -on the "Environment variables" button and double click on the "Path" -variable in the "System variables" section. - -There append the path of your Python interpreter's Script folder to the -end of the last (make sure you delimit it from existing values with a -semicolon). Assuming you are using Python 2.6 on the default path, add -the following value:: - - ;C:\Python26\Scripts - -Then you are done. To check if it worked, open the cmd and execute -"easy_install". If you have UAC enabled it should prompt you for admin -privileges. - - -.. _ez_setup.py: http://peak.telecommunity.com/dist/ez_setup.py diff --git a/docs/license.rst b/docs/license.rst deleted file mode 100644 index 918a75b1..00000000 --- a/docs/license.rst +++ /dev/null @@ -1,21 +0,0 @@ -License -======= - -Flask is licensed under a three clause `BSD License`_. It basically -means: do whatever you want with it as long as the copyright in Flask -sticks around, the conditions are not modified and the disclaimer is -present. Furthermore you must not use the names of the authors to promote -derivates of the software without written consent. - -.. _BSD License: - http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29 - -Authors -------- - -.. include:: ../AUTHORS - -License Text ------------- - -.. include:: ../LICENSE diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 3ad12879..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,139 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Flask.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Flask.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% _build/devhelp - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/docs/patterns/flashing.rst b/docs/patterns/flashing.rst deleted file mode 100644 index fca9a9e1..00000000 --- a/docs/patterns/flashing.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. _message-flashing-pattern: - -Message Flashing -================ - -Good applications and user interfaces are all about feedback. If the user -does not get enough feedback he will probably end up hating the -application. Flask provides a really simple way to give feedback to a -user with the flashing system. The flashing system basically makes it -possible to record a message at the end of a request and access it next -request and only next request. This is usually combined with a layout -template that does this. - -So here a full example:: - - from flask import flash, redirect, url_for, render_template - - @app.route('/') - def index(): - return render_template('index.html') - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - if request.form['username'] != 'admin' or \ - request.form['password'] != 'secret': - error = 'Invalid credentials' - else: - flash('You were sucessfully logged in') - return redirect(url_for('index')) - return render_template('login.html', error=error) - -And here the ``layout.html`` template which does the magic: - -.. sourcecode:: html+jinja - - - My Application - {% with messages = get_flashed_messages() %} - {% if messages %} -
    - {% for message in messages %} -
  • {{ message }}
  • - {% endfor %} -
- {% endif %} - {% endwith %} - {% block body %}{% endblock %} - -And here the index.html template: - -.. sourcecode:: html+jinja - - {% extends "layout.html" %} - {% block body %} -

Overview

-

Do you want to log in? - {% endblock %} - -And of course the login template: - -.. sourcecode:: html+jinja - - {% extends "layout.html" %} - {% block body %} -

Login

- {% if error %} -

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

-
-
Username: -
-
Password: -
-
-

-

- {% endblock %} diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst deleted file mode 100644 index 8122deb7..00000000 --- a/docs/patterns/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. _patterns: - -Patterns for Flask -================== - -Certain things are common enough that the changes are high you will find -them in most web applications. For example quite a lot of applications -are using relational databases and user authentication. In that case, -changes are they will open a database connection at the beginning of the -request and get the information of the currently logged in user. At the -end of the request, the database connection is closed again. - -.. toctree:: - :maxdepth: 2 - - packages - sqlite3 - sqlalchemy - wtforms - templateinheritance - flashing - jquery diff --git a/docs/patterns/jquery.rst b/docs/patterns/jquery.rst deleted file mode 100644 index f087e6f0..00000000 --- a/docs/patterns/jquery.rst +++ /dev/null @@ -1,167 +0,0 @@ -AJAX with jQuery -================ - -`jQuery`_ is a small JavaScript library commonly used to simplify working -with the DOM and JavaScript in general. It is the perfect tool to make -web applications more dynamic by exchanging JSON between server and -client. - -JSON itself is a very lightweight transport format, very similar to how -Python primitives (numbers, strings, dicts and lists) look like which is -widely supported and very easy to parse. It became popular a few years -ago and quickly replaced XML as transport format in web applications. - -If you have Python 2.6 JSON will work out of the box, in Python 2.5 you -will have to install the `simplejson`_ library from PyPI. - -.. _jQuery: http://jquery.com/ -.. _simplejson: http://pypi.python.org/pypi/simplejson - -Loading jQuery --------------- - -In order to use jQuery, you have to download it first and place it in the -static folder of your application and then ensure it's loaded. Ideally -you have a layout template that is used for all pages where you just have -to add a script statement to your `head` to load jQuery: - -.. sourcecode:: html - - - -Another method is using Google's `AJAX Libraries API -`_ to load jQuery: - -.. sourcecode:: html - - - -In this case you don't have to put jQuery into your static folder, it will -instead be loaded from Google directly. This has the advantage that your -website will probably load faster for users if they were to at least one -other website before using the same jQuery version from Google because it -will already be in the browser cache. Downside is that if you don't have -network connectivity during development jQuery will not load. - -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 did could answer that question for -us, but if we are using jQuery we should better 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.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 --------- - -You 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 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/docs/patterns/packages.rst b/docs/patterns/packages.rst deleted file mode 100644 index 4d54e49c..00000000 --- a/docs/patterns/packages.rst +++ /dev/null @@ -1,86 +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 - ... - -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. Do the importing at - the *bottom* of the file. - -Here 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!' - -.. 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. diff --git a/docs/patterns/sqlalchemy.rst b/docs/patterns/sqlalchemy.rst deleted file mode 100644 index 32d41c08..00000000 --- a/docs/patterns/sqlalchemy.rst +++ /dev/null @@ -1,193 +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 three very common ways to use SQLAlchemy. I will outline each -of them here: - -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') - db_session = scoped_session(sessionmaker(autocommit=False, - autoflush=False, - bind=engine)) - Base = declarative_base() - Base.query = db_session.query_property() - - def init_db(): - 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.after_request - def shutdown_session(response): - db_session.remove() - return response - -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, self.email) - -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/reference/ext/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') - 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.after_request - def shutdown_session(response): - db_session.remove() - return response - -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') - 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/docs/patterns/sqlite3.rst b/docs/patterns/sqlite3.rst deleted file mode 100644 index c11e837d..00000000 --- a/docs/patterns/sqlite3.rst +++ /dev/null @@ -1,87 +0,0 @@ -.. _sqlite3: - -Using SQLite 3 with Flask -========================= - -In Flask you can implement 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.after_request` -decorators in combination with the special :class:`~flask.g` object. - -So here 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.after_request - def after_request(response): - g.db.close() - return response - -.. _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 formattings 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/docs/patterns/templateinheritance.rst b/docs/patterns/templateinheritance.rst deleted file mode 100644 index 8a1a306d..00000000 --- a/docs/patterns/templateinheritance.rst +++ /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 to 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/docs/patterns/wtforms.rst b/docs/patterns/wtforms.rst deleted file mode 100644 index 4a836975..00000000 --- a/docs/patterns/wtforms.rst +++ /dev/null @@ -1,113 +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. - -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()]) - confirm = PasswordField('Repeat Password', [validators.EqualTo( - 'confirm', message='Passwords must match')]) - 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') - 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 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. They 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/docs/quickstart.rst b/docs/quickstart.rst deleted file mode 100644 index e0f0749f..00000000 --- a/docs/quickstart.rst +++ /dev/null @@ -1,618 +0,0 @@ -.. _quickstart: - -Quickstart -========== - -Eager to get started? This page gives a good introduction in how to gets -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 that:: - - 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. -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. - - -Debug Mode ----------- - -Now that :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 -applciation object:: - - app.debug = True - app.run() - -Or pass it to run:: - - app.run(debug=True) - -Both will have exactly the same effect. - -.. admonition:: Attention - - The interactive debugger however does not work in forking environments - which makes it nearly impossible to use on production servers but the - debugger still allows the execution of arbitrary code which makes it a - major security risk and **must never be used on production machines** - because of that. - -Screenshot of the debugger in action: - -.. image:: _static/debugger.png - :align: center - :class: screenshot - :alt: screenshot of debugger in action - - -Routing -------- - -As you have seen above, the :meth:`~flask.Flask.route` decorator is used -to bind a function to a URL. But there is more to it! You can make -certain parts of the URL dynamic and attach multiple rules to a function. - -Here some examples:: - - @app.route('/') - def index(): - return 'Index Page' - - @app.route('/hello') - def hello(): - return 'Hello World' - - -Variable Rules -`````````````` - -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 he will like the page and come back next time. - -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 specifed by specifying a -rule with ````. Here 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 -=========== =========================================== - -URL Building -```````````` - -If it can match URLs, can it also generate them? Of course you 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. Here 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('profile', username='John Doe') -... -/ -/login -/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 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. - -You have no idea what an HTTP method is? Worry not, here quick -introduction in 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: just *get* me the information stored on - that page and send them to me. This is probably the most common - method. - -`HEAD` - The Browser tells the server: get me the information, but I am 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 not deliver the actual contents. 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 this is any useful, but there are some good - reasons to do that. Consider the connection is lost during - transmission, in that situation a system between the browser and the - server might sent 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 that the given location. - -Now the interesting part is that in HTML4 and XHTML1, the only methods a -form might submit to the server are `GET` and `POST`. But with JavaScript -and future HTML standards you can use other methods as well. Furthermore -HTTP became quite popular lately and there are more things than browsers -that are speaking HTTP. (Your revision control system for instance might -speak HTTP) - -.. _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 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 -pacakge 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 `Jinja2 Template Documentation -`_ for more information. - -Here 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 a basic introduction in 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' - -.. [#] Unsure what that :class:`~flask.g` object is? It's something you - can store information on yourself, 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 just a standard -global object, but actually a proxy to an object that is 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 unittesting or something different. 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 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`), but just mention some of -the most common operations. First of all you have to import it from the -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 a full example of the two -attributes mentioned above:: - - @app.route('/login', method=['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 a bit user unfriendly. - -For a full list of methods and attribtues on that object, head over to the -:class:`~flask.request` documentation. - - -File Uploads -```````````` - -Obviously you can handle uploaded files with Flask just as easy. Just -make sure not to forget to set the ``enctype="multipart/form-data"`` -attribtue 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.FileStorage.save` method that allows you to store that -file on the filesystem of the server. Here a simple example 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.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.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)) - ... - -Cookies -``````` - -To access cookies you can use the :attr:`~flask.request.cookies` -attribute. Again this 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. - - -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 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 he 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 translats to: all went well. - -.. _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 signes the cookies cryptographically. What this means is that -the user could look at the contents of your cookie but not modify it, -unless he knows 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 session, redirect, url_for, escape - - @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) - - # set the secret key. keep this really secret: - app.secret_key = 'the secret key' - -The here mentioned :func:`~flask.escape` does escaping for you if you are -not using the template engine (like in this example). - -Message Flashing ----------------- - -Good applications and user interfaces are all about feedback. If the user -does not get enough feedback he will probably end up hating the -application. Flask provides a really simple way to give feedback to a -user with the flashing system. The flashing system basically makes it -possible to record a message at the end of a request and access it next -request and only next request. This is usually combined with a layout -template that does this. - -To flash a message use the :func:`~flask.flash` method, to get hold of the -messages you can use :func:`~flask.get_flashed_messages` which is also -available in the templates. Check out the :ref:`message-flashing-pattern` -for a full example. diff --git a/docs/testing.rst b/docs/testing.rst deleted file mode 100644 index 0901792b..00000000 --- a/docs/testing.rst +++ /dev/null @@ -1,197 +0,0 @@ -.. _testing: - -Testing Flask Applications -========================== - - **Something that is untested is broken.** - -Not sure where that is coming from, and it's not entirely correct, but -also not that 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 however has automated tests, you -can safely change things and you will instantly know if your change broke -something. - -Flask gives you a couple of ways to test applications. It mainly does -that by exposing the Werkzeug test :class:`~werkzeug.Client` class to your -code 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 preinstalled with each Python -installation. - -The Application ---------------- - -First we need an application to test for functionality. For the testing -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 that, 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.DATABASE = tempfile.mkstemp() - self.app = flaskr.app.test_client() - flaskr.init_db() - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.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. That function is called before -each individual test function. To delete the database after the test, we -close the file and remove it from the filesystem in the -:meth:`~unittest.TestCase.tearDown` method. What the test client does is -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 that testsuite, we should see the following output:: - - $ python flaskr_tests.py - - ---------------------------------------------------------------------- - Ran 0 tests in 0.000s - - OK - -Even though it did not run any tests, we already know that our flaskr -application is syntactically valid, otherwise the import would have died -with an exception. - -The First Test --------------- - -Now we can add the first test. Let's check that the application shows -"No entries here so far" if we access the root of the application (``/``). -For that we modify our created test case class so that it looks like -this:: - - class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - self.db_fd, flaskr.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 - -Test functions begin with the word `test`. Every function named like that -will be picked up automatically. 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.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 - -Of course you can submit forms with the test client as well, which we will -use now to log our user in. - -Logging In and Out ------------------- - -The majority of the functionality of our application is only available for -the administration user. So we need a way to log our test client in to the -application and out of it again. For that we fire some requests to the -login and logout pages with the required form data (username and -password). 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 if 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(flaskr.USERNAME, flaskr.PASSWORD) - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login(flaskr.USERNAME + 'x', flaskr.PASSWORD) - assert 'Invalid username' in rv.data - rv = self.login(flaskr.USERNAME, flaskr.PASSWORD + 'x') - assert 'Invalid password' in rv.data - -Test Adding Messages --------------------- - -Now we can also test that adding messages works. Add a new test method -like this:: - - def test_messages(self): - self.login(flaskr.USERNAME, flaskr.PASSWORD) - 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. That one contains a larger test -suite. - - -.. _MiniTwit Example: - http://github.com/mitsuhiko/flask/tree/master/examples/minitwit/ diff --git a/docs/tutorial/css.rst b/docs/tutorial/css.rst deleted file mode 100644 index c2a6ba5b..00000000 --- a/docs/tutorial/css.rst +++ /dev/null @@ -1,27 +0,0 @@ -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; } diff --git a/docs/tutorial/dbcon.rst b/docs/tutorial/dbcon.rst deleted file mode 100644 index 9741dabb..00000000 --- a/docs/tutorial/dbcon.rst +++ /dev/null @@ -1,33 +0,0 @@ -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` and -:meth:`~flask.Flask.after_request` decorators:: - - @app.before_request - def before_request(): - g.db = connect_db() - - @app.after_request - def after_request(response): - g.db.close() - return response - -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. In this case we just return it -unchanged. - -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. diff --git a/docs/tutorial/dbinit.rst b/docs/tutorial/dbinit.rst deleted file mode 100644 index 0dc87d58..00000000 --- a/docs/tutorial/dbinit.rst +++ /dev/null @@ -1,63 +0,0 @@ -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). diff --git a/docs/tutorial/folders.rst b/docs/tutorial/folders.rst deleted file mode 100644 index 80697a94..00000000 --- a/docs/tutorial/folders.rst +++ /dev/null @@ -1,19 +0,0 @@ -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. Drop all the -templates there. - -.. _Jinja2: http://jinja.pocoo.org/2/ diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst deleted file mode 100644 index 3f2d659e..00000000 --- a/docs/tutorial/index.rst +++ /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/docs/tutorial/introduction.rst b/docs/tutorial/introduction.rst deleted file mode 100644 index 04396a9d..00000000 --- a/docs/tutorial/introduction.rst +++ /dev/null @@ -1,29 +0,0 @@ -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 he or she 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 - -.. _SQLAlchemy: http://www.sqlalchemy.org/ diff --git a/docs/tutorial/schema.rst b/docs/tutorial/schema.rst deleted file mode 100644 index ed329539..00000000 --- a/docs/tutorial/schema.rst +++ /dev/null @@ -1,21 +0,0 @@ -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. diff --git a/docs/tutorial/setup.rst b/docs/tutorial/setup.rst deleted file mode 100644 index 24b76561..00000000 --- a/docs/tutorial/setup.rst +++ /dev/null @@ -1,69 +0,0 @@ -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:: - - # create our little application :) - app = Flask(__name__) - app.secret_key = SECRET_KEY - app.debug = DEBUG - -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 -executed 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(DATABASE) - -Finally we just add a line to the bottom of the file that fires up the -server if we run that file as standalone application:: - - if __name__ == '__main__': - app.run() - -With that out of the way you should be able to start up the application -without problems. When you head over to the server 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:: Troubleshooting - - If you notice later that the browser cannot connect to the server - during development, you might want to try this line instead:: - - app.run(host='127.0.0.1') - - In a nutshell: Werkzeug starts up as IPv6 on many operating systems by - default and not every browser is happy with that. This forces IPv4 - usage. diff --git a/docs/tutorial/templates.rst b/docs/tutorial/templates.rst deleted file mode 100644 index 66b1dec6..00000000 --- a/docs/tutorial/templates.rst +++ /dev/null @@ -1,107 +0,0 @@ -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 %} diff --git a/docs/tutorial/testing.rst b/docs/tutorial/testing.rst deleted file mode 100644 index 3d1aa806..00000000 --- a/docs/tutorial/testing.rst +++ /dev/null @@ -1,9 +0,0 @@ -Bonus: Testing the Application -=============================== - -Now that you have finished the application and everything works as -expected, it's probably not the best 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/docs/tutorial/views.rst b/docs/tutorial/views.rst deleted file mode 100644 index 29be65fa..00000000 --- a/docs/tutorial/views.rst +++ /dev/null @@ -1,87 +0,0 @@ -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) 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 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 he's 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`). - -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 that case also a message is flashed that informs the user he or -she was logged in successfully. If an error occoured the template is -notified about that and the user asked again:: - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - if request.form['username'] != USERNAME: - error = 'Invalid username' - elif request.form['password'] != 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 was not in there. This is helpful because we don't have to check in -that case 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')) diff --git a/examples/flaskr/README b/examples/flaskr/README deleted file mode 100644 index 4a9a02c6..00000000 --- a/examples/flaskr/README +++ /dev/null @@ -1,26 +0,0 @@ - - / Flaskr / - - a minimal blog application - - - ~ What is Flaskr? - - A sqlite powered thumble blog application - - ~ How do I use it? - - 1. edit the configuration in the flaskr.py file - - 2. fire up a python shell and run this: - - >>> from flaskr import init_db; init_db() - - 3. now you can run the flaskr.py file with your - python interpreter and the application will - greet you on http://localhost:5000/ - - ~ Is it tested? - - You betcha. Run the `flaskr_tests.py` file to see - the tests pass. diff --git a/examples/flaskr/flaskr.py b/examples/flaskr/flaskr.py deleted file mode 100644 index f2a8b341..00000000 --- a/examples/flaskr/flaskr.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Flaskr - ~~~~~~ - - A microblog example application written as Flask tutorial with - Flask and sqlite3. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from __future__ import with_statement -import sqlite3 -from contextlib import closing -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' - -# create our little application :) -app = Flask(__name__) -app.secret_key = SECRET_KEY -app.debug = DEBUG - - -def connect_db(): - """Returns a new connection to the database.""" - return sqlite3.connect(DATABASE) - - -def init_db(): - """Creates the database tables.""" - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -@app.before_request -def before_request(): - """Make sure we are connected to the database each request.""" - g.db = connect_db() - - -@app.after_request -def after_request(response): - """Closes the database again at the end of the request.""" - g.db.close() - return response - - -@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) - - -@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')) - - -@app.route('/login', methods=['GET', 'POST']) -def login(): - error = None - if request.method == 'POST': - if request.form['username'] != USERNAME: - error = 'Invalid username' - elif request.form['password'] != 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) - - -@app.route('/logout') -def logout(): - session.pop('logged_in', None) - flash('You were logged out') - return redirect(url_for('show_entries')) - - -if __name__ == '__main__': - app.run() diff --git a/examples/flaskr/flaskr_tests.py b/examples/flaskr/flaskr_tests.py deleted file mode 100644 index 9421cca6..00000000 --- a/examples/flaskr/flaskr_tests.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Flaskr Tests - ~~~~~~~~~~~~ - - Tests the Flaskr application. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import os -import flaskr -import unittest -import tempfile - - -class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - """Before each test, set up a blank database""" - self.db_fd, flaskr.DATABASE = tempfile.mkstemp() - self.app = flaskr.app.test_client() - flaskr.init_db() - - def tearDown(self): - """Get rid of the database again after each test.""" - os.close(self.db_fd) - os.unlink(flaskr.DATABASE) - - 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) - - # testing functions - - def test_empty_db(self): - """Start with a blank database.""" - rv = self.app.get('/') - assert 'No entries here so far' in rv.data - - def test_login_logout(self): - """Make sure login and logout works""" - rv = self.login(flaskr.USERNAME, flaskr.PASSWORD) - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login(flaskr.USERNAME + 'x', flaskr.PASSWORD) - assert 'Invalid username' in rv.data - rv = self.login(flaskr.USERNAME, flaskr.PASSWORD + 'x') - assert 'Invalid password' in rv.data - - def test_messages(self): - """Test that messages work""" - self.login(flaskr.USERNAME, flaskr.PASSWORD) - 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 - - -if __name__ == '__main__': - unittest.main() diff --git a/examples/flaskr/schema.sql b/examples/flaskr/schema.sql deleted file mode 100644 index 970cca77..00000000 --- a/examples/flaskr/schema.sql +++ /dev/null @@ -1,6 +0,0 @@ -drop table if exists entries; -create table entries ( - id integer primary key autoincrement, - title string not null, - text string not null -); diff --git a/examples/flaskr/static/style.css b/examples/flaskr/static/style.css deleted file mode 100644 index 4f3b71d8..00000000 --- a/examples/flaskr/static/style.css +++ /dev/null @@ -1,18 +0,0 @@ -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; } diff --git a/examples/flaskr/templates/layout.html b/examples/flaskr/templates/layout.html deleted file mode 100644 index cbdb9650..00000000 --- a/examples/flaskr/templates/layout.html +++ /dev/null @@ -1,17 +0,0 @@ - -Flaskr - -
-

Flaskr

-
- {% if not session.logged_in %} - log in - {% else %} - log out - {% endif %} -
- {% for message in get_flashed_messages() %} -
{{ message }}
- {% endfor %} - {% block body %}{% endblock %} -
diff --git a/examples/flaskr/templates/login.html b/examples/flaskr/templates/login.html deleted file mode 100644 index 6f70bb76..00000000 --- a/examples/flaskr/templates/login.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "layout.html" %} -{% block body %} -

Login

- {% if error %}

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

-
-
Username: -
-
Password: -
-
-
-
-{% endblock %} diff --git a/examples/flaskr/templates/show_entries.html b/examples/flaskr/templates/show_entries.html deleted file mode 100644 index fabe65ec..00000000 --- a/examples/flaskr/templates/show_entries.html +++ /dev/null @@ -1,21 +0,0 @@ -{% 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 %} diff --git a/examples/jqueryexample/jqueryexample.py b/examples/jqueryexample/jqueryexample.py deleted file mode 100644 index 0e8caf3e..00000000 --- a/examples/jqueryexample/jqueryexample.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -""" - jQuery Example - ~~~~~~~~~~~~~~ - - A simple application that shows how Flask and jQuery get along. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from flask import Flask, jsonify, render_template, request -app = Flask(__name__) - - -@app.route('/_add_numbers') -def add_numbers(): - """Add two numbers server side, ridiculous but well...""" - 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') - - -if __name__ == '__main__': - app.run() diff --git a/examples/jqueryexample/templates/index.html b/examples/jqueryexample/templates/index.html deleted file mode 100644 index 0545516d..00000000 --- a/examples/jqueryexample/templates/index.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "layout.html" %} -{% block body %} - -

jQuery Example

-

+ - = - ? -

calculate server side -{% endblock %} diff --git a/examples/jqueryexample/templates/layout.html b/examples/jqueryexample/templates/layout.html deleted file mode 100644 index 0b5f3a7e..00000000 --- a/examples/jqueryexample/templates/layout.html +++ /dev/null @@ -1,10 +0,0 @@ - -jQuery Example - - - -{% block body %}{% endblock %} diff --git a/examples/minitwit/README b/examples/minitwit/README deleted file mode 100644 index 065674a9..00000000 --- a/examples/minitwit/README +++ /dev/null @@ -1,26 +0,0 @@ - - / MiniTwit / - - because writing todo lists is not fun - - - ~ What is MiniTwit? - - A SQLite and Flask powered twitter clone - - ~ How do I use it? - - 1. edit the configuration in the minitwit.py file - - 2. fire up a python shell and run this: - - >>> from minitwit import init_db; init_db() - - 3. now you can run the minitwit.py file with your - python interpreter and the application will - greet you on http://localhost:5000/ - - ~ Is it tested? - - You betcha. Run the `minitwit_tests.py` file to - see the tests pass. diff --git a/examples/minitwit/minitwit.py b/examples/minitwit/minitwit.py deleted file mode 100644 index 07ffe4c7..00000000 --- a/examples/minitwit/minitwit.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- coding: utf-8 -*- -""" - MiniTwit - ~~~~~~~~ - - A microblogging application written with Flask and sqlite3. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from __future__ import with_statement -import time -import sqlite3 -from hashlib import md5 -from datetime import datetime -from contextlib import closing -from flask import Flask, request, session, url_for, redirect, \ - render_template, abort, g, flash -from werkzeug import check_password_hash, generate_password_hash - - -# configuration -DATABASE = '/tmp/minitwit.db' -PER_PAGE = 30 -DEBUG = True -SECRET_KEY = 'development key' - -# create our little application :) -app = Flask(__name__) - - -def connect_db(): - """Returns a new connection to the database.""" - return sqlite3.connect(DATABASE) - - -def init_db(): - """Creates the database tables.""" - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -def query_db(query, args=(), one=False): - """Queries the database and returns a list of dictionaries.""" - 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 - - -def get_user_id(username): - """Convenience method to look up the id for a username.""" - rv = g.db.execute('select user_id from user where username = ?', - [username]).fetchone() - return rv[0] if rv else None - - -def format_datetime(timestamp): - """Format a timestamp for display.""" - return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d @ %H:%M') - - -def gravatar_url(email, size=80): - """Return the gravatar image for the given email address.""" - return 'http://www.gravatar.com/avatar/%s?d=identicon&s=%d' % \ - (md5(email.strip().lower().encode('utf-8')).hexdigest(), size) - - -@app.before_request -def before_request(): - """Make sure we are connected to the database each request and look - up the current user so that we know he's there. - """ - g.db = connect_db() - g.user = None - if 'user_id' in session: - g.user = query_db('select * from user where user_id = ?', - [session['user_id']], one=True) - - -@app.after_request -def after_request(response): - """Closes the database again at the end of the request.""" - g.db.close() - return response - - -@app.route('/') -def timeline(): - """Shows a users timeline or if no user is logged in it will - redirect to the public timeline. This timeline shows the user's - messages as well as all the messages of followed users. - """ - if not g.user: - return redirect(url_for('public_timeline')) - return render_template('timeline.html', messages=query_db(''' - select message.*, user.* from message, user - where message.author_id = user.user_id and ( - user.user_id = ? or - user.user_id in (select whom_id from follower - where who_id = ?)) - order by message.pub_date desc limit ?''', - [session['user_id'], session['user_id'], PER_PAGE])) - - -@app.route('/public') -def public_timeline(): - """Displays the latest messages of all users.""" - return render_template('timeline.html', messages=query_db(''' - select message.*, user.* from message, user - where message.author_id = user.user_id - order by message.pub_date desc limit ?''', [PER_PAGE])) - - -@app.route('/') -def user_timeline(username): - """Display's a users tweets.""" - profile_user = query_db('select * from user where username = ?', - [username], one=True) - if profile_user is None: - abort(404) - followed = False - if g.user: - followed = query_db('''select 1 from follower where - follower.who_id = ? and follower.whom_id = ?''', - [session['user_id'], profile_user['user_id']], - one=True) is not None - return render_template('timeline.html', messages=query_db(''' - select message.*, user.* from message, user where - user.user_id = message.author_id and user.user_id = ? - order by message.pub_date desc limit ?''', - [profile_user['user_id'], PER_PAGE]), followed=followed, - profile_user=profile_user) - - -@app.route('//follow') -def follow_user(username): - """Adds the current user as follower of the given user.""" - if not g.user: - abort(401) - whom_id = get_user_id(username) - if whom_id is None: - abort(404) - g.db.execute('insert into follower (who_id, whom_id) values (?, ?)', - [session['user_id'], whom_id]) - g.db.commit() - flash('You are now following "%s"' % username) - return redirect(url_for('user_timeline', username=username)) - - -@app.route('//unfollow') -def unfollow_user(username): - """Removes the current user as follower of the given user.""" - if not g.user: - abort(401) - whom_id = get_user_id(username) - if whom_id is None: - abort(404) - g.db.execute('delete from follower where who_id=? and whom_id=?', - [session['user_id'], whom_id]) - g.db.commit() - flash('You are no longer following "%s"' % username) - return redirect(url_for('user_timeline', username=username)) - - -@app.route('/add_message', methods=['POST']) -def add_message(): - """Registers a new message for the user.""" - if 'user_id' not in session: - abort(401) - if request.form['text']: - g.db.execute('''insert into message (author_id, text, pub_date) - values (?, ?, ?)''', (session['user_id'], request.form['text'], - int(time.time()))) - g.db.commit() - flash('Your message was recorded') - return redirect(url_for('timeline')) - - -@app.route('/login', methods=['GET', 'POST']) -def login(): - """Logs the user in.""" - if g.user: - return redirect(url_for('timeline')) - error = None - if request.method == 'POST': - user = query_db('''select * from user where - username = ?''', [request.form['username']], one=True) - if user is None: - error = 'Invalid username' - elif not check_password_hash(user['pw_hash'], - request.form['password']): - error = 'Invalid password' - else: - flash('You were logged in') - session['user_id'] = user['user_id'] - return redirect(url_for('timeline')) - return render_template('login.html', error=error) - - -@app.route('/register', methods=['GET', 'POST']) -def register(): - """Registers the user.""" - if g.user: - return redirect(url_for('timeline')) - error = None - if request.method == 'POST': - if not request.form['username']: - error = 'You have to enter a username' - elif not request.form['email'] or \ - '@' not in request.form['email']: - error = 'You have to enter a valid email address' - elif not request.form['password']: - error = 'You have to enter a password' - elif request.form['password'] != request.form['password2']: - error = 'The two passwords do not match' - elif get_user_id(request.form['username']) is not None: - error = 'The username is already taken' - else: - g.db.execute('''insert into user ( - username, email, pw_hash) values (?, ?, ?)''', - [request.form['username'], request.form['email'], - generate_password_hash(request.form['password'])]) - g.db.commit() - flash('You were successfully registered and can login now') - return redirect(url_for('login')) - return render_template('register.html', error=error) - - -@app.route('/logout') -def logout(): - """Logs the user out.""" - flash('You were logged out') - session.pop('user_id', None) - return redirect(url_for('public_timeline')) - - -# add some filters to jinja and set the secret key and debug mode -# from the configuration. -app.jinja_env.filters['datetimeformat'] = format_datetime -app.jinja_env.filters['gravatar'] = gravatar_url -app.secret_key = SECRET_KEY -app.debug = DEBUG - - -if __name__ == '__main__': - app.run() diff --git a/examples/minitwit/minitwit_tests.py b/examples/minitwit/minitwit_tests.py deleted file mode 100644 index 10962142..00000000 --- a/examples/minitwit/minitwit_tests.py +++ /dev/null @@ -1,149 +0,0 @@ -# -*- coding: utf-8 -*- -""" - MiniTwit Tests - ~~~~~~~~~~~~~~ - - Tests the MiniTwit application. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -import os -import minitwit -import unittest -import tempfile - - -class MiniTwitTestCase(unittest.TestCase): - - def setUp(self): - """Before each test, set up a blank database""" - self.db_fd, minitwit.DATABASE = tempfile.mkstemp() - self.app = minitwit.app.test_client() - minitwit.init_db() - - def tearDown(self): - """Get rid of the database again after each test.""" - os.close(self.db_fd) - os.unlink(minitwit.DATABASE) - - # helper functions - - def register(self, username, password, password2=None, email=None): - """Helper function to register a user""" - if password2 is None: - password2 = password - if email is None: - email = username + '@example.com' - return self.app.post('/register', data={ - 'username': username, - 'password': password, - 'password2': password2, - 'email': email, - }, follow_redirects=True) - - def login(self, username, password): - """Helper function to login""" - return self.app.post('/login', data={ - 'username': username, - 'password': password - }, follow_redirects=True) - - def register_and_login(self, username, password): - """Registers and logs in in one go""" - self.register(username, password) - return self.login(username, password) - - def logout(self): - """Helper function to logout""" - return self.app.get('/logout', follow_redirects=True) - - def add_message(self, text): - """Records a message""" - rv = self.app.post('/add_message', data={'text': text}, - follow_redirects=True) - if text: - assert 'Your message was recorded' in rv.data - return rv - - # testing functions - - def test_register(self): - """Make sure registering works""" - rv = self.register('user1', 'default') - assert 'You were successfully registered ' \ - 'and can login now' in rv.data - rv = self.register('user1', 'default') - assert 'The username is already taken' in rv.data - rv = self.register('', 'default') - assert 'You have to enter a username' in rv.data - rv = self.register('meh', '') - assert 'You have to enter a password' in rv.data - rv = self.register('meh', 'x', 'y') - assert 'The two passwords do not match' in rv.data - rv = self.register('meh', 'foo', email='broken') - assert 'You have to enter a valid email address' in rv.data - - def test_login_logout(self): - """Make sure logging in and logging out works""" - rv = self.register_and_login('user1', 'default') - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login('user1', 'wrongpassword') - assert 'Invalid password' in rv.data - rv = self.login('user2', 'wrongpassword') - assert 'Invalid username' in rv.data - - def test_message_recording(self): - """Check if adding messages works""" - self.register_and_login('foo', 'default') - self.add_message('test message 1') - self.add_message('') - rv = self.app.get('/') - assert 'test message 1' in rv.data - assert '<test message 2>' in rv.data - - def test_timelines(self): - """Make sure that timelines work""" - self.register_and_login('foo', 'default') - self.add_message('the message by foo') - self.logout() - self.register_and_login('bar', 'default') - self.add_message('the message by bar') - rv = self.app.get('/public') - assert 'the message by foo' in rv.data - assert 'the message by bar' in rv.data - - # bar's timeline should just show bar's message - rv = self.app.get('/') - assert 'the message by foo' not in rv.data - assert 'the message by bar' in rv.data - - # now let's follow foo - rv = self.app.get('/foo/follow', follow_redirects=True) - assert 'You are now following "foo"' in rv.data - - # we should now see foo's message - rv = self.app.get('/') - assert 'the message by foo' in rv.data - assert 'the message by bar' in rv.data - - # but on the user's page we only want the user's message - rv = self.app.get('/bar') - assert 'the message by foo' not in rv.data - assert 'the message by bar' in rv.data - rv = self.app.get('/foo') - assert 'the message by foo' in rv.data - assert 'the message by bar' not in rv.data - - # now unfollow and check if that worked - rv = self.app.get('/foo/unfollow', follow_redirects=True) - assert 'You are no longer following "foo"' in rv.data - rv = self.app.get('/') - assert 'the message by foo' not in rv.data - assert 'the message by bar' in rv.data - - -if __name__ == '__main__': - unittest.main() diff --git a/examples/minitwit/schema.sql b/examples/minitwit/schema.sql deleted file mode 100644 index b64afbed..00000000 --- a/examples/minitwit/schema.sql +++ /dev/null @@ -1,21 +0,0 @@ -drop table if exists user; -create table user ( - user_id integer primary key autoincrement, - username string not null, - email string not null, - pw_hash string not null -); - -drop table if exists follower; -create table follower ( - who_id integer, - whom_id integer -); - -drop table if exists message; -create table message ( - message_id integer primary key autoincrement, - author_id integer not null, - text string not null, - pub_date integer -); diff --git a/examples/minitwit/static/style.css b/examples/minitwit/static/style.css deleted file mode 100644 index ebbed8c9..00000000 --- a/examples/minitwit/static/style.css +++ /dev/null @@ -1,178 +0,0 @@ -body { - background: #CAECE9; - font-family: 'Trebuchet MS', sans-serif; - font-size: 14px; -} - -a { - color: #26776F; -} - -a:hover { - color: #333; -} - -input[type="text"], -input[type="password"] { - background: white; - border: 1px solid #BFE6E2; - padding: 2px; - font-family: 'Trebuchet MS', sans-serif; - font-size: 14px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - color: #105751; -} - -input[type="submit"] { - background: #105751; - border: 1px solid #073B36; - padding: 1px 3px; - font-family: 'Trebuchet MS', sans-serif; - font-size: 14px; - font-weight: bold; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - color: white; -} - -div.page { - background: white; - border: 1px solid #6ECCC4; - width: 700px; - margin: 30px auto; -} - -div.page h1 { - background: #6ECCC4; - margin: 0; - padding: 10px 14px; - color: white; - letter-spacing: 1px; - text-shadow: 0 0 3px #24776F; - font-weight: normal; -} - -div.page div.navigation { - background: #DEE9E8; - padding: 4px 10px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #eee; - color: #888; - font-size: 12px; - letter-spacing: 0.5px; -} - -div.page div.navigation a { - color: #444; - font-weight: bold; -} - -div.page h2 { - margin: 0 0 15px 0; - color: #105751; - text-shadow: 0 1px 2px #ccc; -} - -div.page div.body { - padding: 10px; -} - -div.page div.footer { - background: #eee; - color: #888; - padding: 5px 10px; - font-size: 12px; -} - -div.page div.followstatus { - border: 1px solid #ccc; - background: #E3EBEA; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - padding: 3px; - font-size: 13px; -} - -div.page ul.messages { - list-style: none; - margin: 0; - padding: 0; -} - -div.page ul.messages li { - margin: 10px 0; - padding: 5px; - background: #F0FAF9; - border: 1px solid #DBF3F1; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - min-height: 48px; -} - -div.page ul.messages p { - margin: 0; -} - -div.page ul.messages li img { - float: left; - padding: 0 10px 0 0; -} - -div.page ul.messages li small { - font-size: 0.9em; - color: #888; -} - -div.page div.twitbox { - margin: 10px 0; - padding: 5px; - background: #F0FAF9; - border: 1px solid #94E2DA; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -div.page div.twitbox h3 { - margin: 0; - font-size: 1em; - color: #2C7E76; -} - -div.page div.twitbox p { - margin: 0; -} - -div.page div.twitbox input[type="text"] { - width: 585px; -} - -div.page div.twitbox input[type="submit"] { - width: 70px; - margin-left: 5px; -} - -ul.flashes { - list-style: none; - margin: 10px 10px 0 10px; - padding: 0; -} - -ul.flashes li { - background: #B9F3ED; - border: 1px solid #81CEC6; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - padding: 4px; - font-size: 13px; -} - -div.error { - margin: 10px 0; - background: #FAE4E4; - border: 1px solid #DD6F6F; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - padding: 4px; - font-size: 13px; -} diff --git a/examples/minitwit/templates/layout.html b/examples/minitwit/templates/layout.html deleted file mode 100644 index 668e3895..00000000 --- a/examples/minitwit/templates/layout.html +++ /dev/null @@ -1,32 +0,0 @@ - -{% block title %}Welcome{% endblock %} | MiniTwit - -

-

MiniTwit

- - {% with flashes = get_flashed_messages() %} - {% if flashes %} -
    - {% for message in flashes %} -
  • {{ message }} - {% endfor %} -
- {% endif %} - {% endwith %} -
- {% block body %}{% endblock %} -
- -
diff --git a/examples/minitwit/templates/login.html b/examples/minitwit/templates/login.html deleted file mode 100644 index ae776714..00000000 --- a/examples/minitwit/templates/login.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "layout.html" %} -{% block title %}Sign In{% endblock %} -{% block body %} -

Sign In

- {% if error %}
Error: {{ error }}
{% endif %} -
-
-
Username: -
-
Password: -
-
-
-
-{% endblock %} - diff --git a/examples/minitwit/templates/register.html b/examples/minitwit/templates/register.html deleted file mode 100644 index ccb345d5..00000000 --- a/examples/minitwit/templates/register.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "layout.html" %} -{% block title %}Sign Up{% endblock %} -{% block body %} -

Sign Up

- {% if error %}
Error: {{ error }}
{% endif %} -
-
-
Username: -
-
E-Mail: -
-
Password: -
-
Password (repeat): -
-
-
-
-{% endblock %} diff --git a/examples/minitwit/templates/timeline.html b/examples/minitwit/templates/timeline.html deleted file mode 100644 index ea7d751b..00000000 --- a/examples/minitwit/templates/timeline.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "layout.html" %} -{% block title %} - {% if request.endpoint == 'public_timeline' %} - Public Timeline - {% elif request.endpoint == 'user_timeline' %} - {{ profile_user.username }}'s Timeline - {% else %} - My Timeline - {% endif %} -{% endblock %} -{% block body %} -

{{ self.title() }}

- {% if g.user %} - {% if request.endpoint == 'user_timeline' %} -
- {% if g.user.user_id == profile_user.user_id %} - This is you! - {% elif followed %} - You are currently following this user. - Unfollow user. - {% else %} - You are not yet following this user. - . - {% endif %} -
- {% elif request.endpoint == 'timeline' %} -
-

What's on your mind {{ g.user.username }}?

-
-

-

-
- {% endif %} - {% endif %} -
    - {% for message in messages %} -
  • - {{ message.username }} - {{ message.text }} - — {{ message.pub_date|datetimeformat }} - {% else %} -

  • There's no message so far. - {% endfor %} -
-{% endblock %} diff --git a/flask.py b/flask.py deleted file mode 100644 index 1f0fb7e6..00000000 --- a/flask.py +++ /dev/null @@ -1,801 +0,0 @@ -# -*- coding: utf-8 -*- -""" - flask - ~~~~~ - - A microframework based on Werkzeug. It's extensively documented - and follows best practice patterns. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from __future__ import with_statement -import os -import sys - -from jinja2 import Environment, PackageLoader, FileSystemLoader -from werkzeug import Request as RequestBase, Response as ResponseBase, \ - LocalStack, LocalProxy, create_environ, SharedDataMiddleware, \ - ImmutableDict, cached_property -from werkzeug.routing import Map, Rule -from werkzeug.exceptions import HTTPException -from werkzeug.contrib.securecookie import SecureCookie - -# try to load the best simplejson implementation available. If JSON -# is not installed, we add a failing class. -json_available = True -try: - import simplejson as json -except ImportError: - try: - import json - except ImportError: - json_available = False - -# utilities we import from Werkzeug and Jinja2 that are unused -# in the module but are exported as public interface. -from werkzeug import abort, redirect -from jinja2 import Markup, escape - -# use pkg_resource if that works, otherwise fall back to cwd. The -# current working directory is generally not reliable with the notable -# exception of google appengine. -try: - import pkg_resources - pkg_resources.resource_stream -except (ImportError, AttributeError): - pkg_resources = None - - -class Request(RequestBase): - """The request object used by default in flask. Remembers the - matched endpoint and view arguments. - - It is what ends up as :class:`~flask.request`. If you want to replace - the request object used you can subclass this and set - :attr:`~flask.Flask.request_class` to your subclass. - """ - - endpoint = view_args = None - - @cached_property - def json(self): - """If the mimetype is `application/json` this will contain the - parsed JSON data. - """ - if __debug__: - _assert_have_json() - if self.mimetype == 'application/json': - return json.loads(self.data) - - -class Response(ResponseBase): - """The response object that is used by default in flask. Works like the - response object from Werkzeug but is set to have a HTML mimetype by - default. Quite often you don't have to create this object yourself because - :meth:`~flask.Flask.make_response` will take care of that for you. - - If you want to replace the response object used you can subclass this and - set :attr:`~flask.Flask.request_class` to your subclass. - """ - default_mimetype = 'text/html' - - -class _RequestGlobals(object): - pass - - -class _NullSession(SecureCookie): - """Class used to generate nicer error messages if sessions are not - available. Will still allow read-only access to the empty session - but fail on setting. - """ - - def _fail(self, *args, **kwargs): - raise RuntimeError('the session is unavailable because no secret ' - 'key was set. Set the secret_key on the ' - 'application to something unique and secret') - __setitem__ = __delitem__ = clear = pop = popitem = \ - update = setdefault = _fail - del _fail - - -class _RequestContext(object): - """The request context contains all request relevant information. It is - created at the beginning of the request and pushed to the - `_request_ctx_stack` and removed at the end of it. It will create the - URL adapter and request object for the WSGI environment provided. - """ - - def __init__(self, app, environ): - self.app = app - self.url_adapter = app.url_map.bind_to_environ(environ) - self.request = app.request_class(environ) - self.session = app.open_session(self.request) - if self.session is None: - self.session = _NullSession() - self.g = _RequestGlobals() - self.flashes = None - - def __enter__(self): - _request_ctx_stack.push(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() - - -def url_for(endpoint, **values): - """Generates a URL to the given endpoint with the method provided. - - :param endpoint: the endpoint of the URL (name of the function) - :param values: the variable arguments of the URL rule - """ - return _request_ctx_stack.top.url_adapter.build(endpoint, values) - - -def get_template_attribute(template_name, attribute): - """Loads a macro (or variable) a template exports. This can be used to - invoke a macro from within Python code. If you for example have a - template named `_foo.html` with the following contents: - - .. sourcecode:: html+jinja - - {% macro hello(name) %}Hello {{ name }}!{% endmacro %} - - You can access this from Python code like this:: - - hello = get_template_attribute('_foo.html', 'hello') - return hello('World') - - .. versionadded:: 0.2 - - :param template_name: the name of the template - :param attribute: the name of the variable of macro to acccess - """ - return getattr(current_app.jinja_env.get_template(template_name).module, - attribute) - - -def flash(message): - """Flashes a message to the next request. In order to remove the - flashed message from the session and to display it to the user, - the template has to call :func:`get_flashed_messages`. - - :param message: the message to be flashed. - """ - session.setdefault('_flashes', []).append(message) - - -def get_flashed_messages(): - """Pulls all flashed messages from the session and returns them. - Further calls in the same request to the function will return - the same messages. - """ - flashes = _request_ctx_stack.top.flashes - if flashes is None: - _request_ctx_stack.top.flashes = flashes = session.pop('_flashes', []) - return flashes - - -def jsonify(*args, **kwargs): - """Creates a :class:`~flask.Response` with the JSON representation of - the given arguments with an `application/json` mimetype. The arguments - to this function are the same as to the :class:`dict` constructor. - - Example usage:: - - @app.route('/_get_current_user') - def get_current_user(): - return jsonify(username=g.user.username, - email=g.user.email, - id=g.user.id) - - This will send a JSON response like this to the browser:: - - { - "username": "admin", - "email": "admin@localhost", - "id": 42 - } - - This requires Python 2.6 or an installed version of simplejson. - - .. versionadded:: 0.2 - """ - if __debug__: - _assert_have_json() - return current_app.response_class(json.dumps(dict(*args, **kwargs), - indent=None if request.is_xhr else 2), mimetype='application/json') - - -def render_template(template_name, **context): - """Renders a template from the template folder with the given - context. - - :param template_name: the name of the template to be rendered - :param context: the variables that should be available in the - context of the template. - """ - current_app.update_template_context(context) - return current_app.jinja_env.get_template(template_name).render(context) - - -def render_template_string(source, **context): - """Renders a template from the given template source string - with the given context. - - :param template_name: the sourcecode of the template to be - rendered - :param context: the variables that should be available in the - context of the template. - """ - current_app.update_template_context(context) - return current_app.jinja_env.from_string(source).render(context) - - -def _default_template_ctx_processor(): - """Default template context processor. Injects `request`, - `session` and `g`. - """ - reqctx = _request_ctx_stack.top - return dict( - request=reqctx.request, - session=reqctx.session, - g=reqctx.g - ) - - -def _assert_have_json(): - """Helper function that fails if JSON is unavailable.""" - if not json_available: - raise RuntimeError('simplejson not installed') - - -def _get_package_path(name): - """Returns the path to a package or cwd if that cannot be found.""" - try: - return os.path.abspath(os.path.dirname(sys.modules[name].__file__)) - except (KeyError, AttributeError): - return os.getcwd() - - -# figure out if simplejson escapes slashes. This behaviour was changed -# from one version to another without reason. -if not json_available or '\\/' not in json.dumps('/'): - - def _tojson_filter(*args, **kwargs): - if __debug__: - _assert_have_json() - return json.dumps(*args, **kwargs).replace('/', '\\/') -else: - _tojson_filter = json.dumps - - -class Flask(object): - """The flask object implements a WSGI application and acts as the central - object. It is passed the name of the module or package of the - application. Once it is created it will act as a central registry for - the view functions, the URL rules, template configuration and much more. - - The name of the package is used to resolve resources from inside the - package or the folder the module is contained in depending on if the - package parameter resolves to an actual python package (a folder with - an `__init__.py` file inside) or a standard module (just a `.py` file). - - For more information about resource loading, see :func:`open_resource`. - - Usually you create a :class:`Flask` instance in your main module or - in the `__init__.py` file of your package like this:: - - from flask import Flask - app = Flask(__name__) - """ - - #: the class that is used for request objects. See :class:`~flask.request` - #: for more information. - request_class = Request - - #: the class that is used for response objects. See - #: :class:`~flask.Response` for more information. - response_class = Response - - #: path for the static files. If you don't want to use static files - #: you can set this value to `None` in which case no URL rule is added - #: and the development server will no longer serve any static files. - static_path = '/static' - - #: if a secret key is set, cryptographic components can use this to - #: sign cookies and other things. Set this to a complex random value - #: when you want to use the secure cookie for instance. - secret_key = None - - #: The secure cookie uses this for the name of the session cookie - session_cookie_name = 'session' - - #: options that are passed directly to the Jinja2 environment - jinja_options = ImmutableDict( - autoescape=True, - extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] - ) - - def __init__(self, package_name): - #: the debug flag. Set this to `True` to enable debugging of - #: the application. In debug mode the debugger will kick in - #: when an unhandled exception ocurrs and the integrated server - #: will automatically reload the application if changes in the - #: code are detected. - self.debug = False - - #: the name of the package or module. Do not change this once - #: it was set by the constructor. - self.package_name = package_name - - #: where is the app root located? - self.root_path = _get_package_path(self.package_name) - - #: a dictionary of all view functions registered. The keys will - #: be function names which are also used to generate URLs and - #: the values are the function objects themselves. - #: to register a view function, use the :meth:`route` decorator. - self.view_functions = {} - - #: a dictionary of all registered error handlers. The key is - #: be the error code as integer, the value the function that - #: should handle that error. - #: To register a error handler, use the :meth:`errorhandler` - #: decorator. - self.error_handlers = {} - - #: a list of functions that should be called at the beginning - #: of the request before request dispatching kicks in. This - #: can for example be used to open database connections or - #: getting hold of the currently logged in user. - #: To register a function here, use the :meth:`before_request` - #: decorator. - self.before_request_funcs = [] - - #: a list of functions that are called at the end of the - #: request. The function is passed the current response - #: object and modify it in place or replace it. - #: To register a function here use the :meth:`after_request` - #: decorator. - self.after_request_funcs = [] - - #: a list of functions that are called without arguments - #: to populate the template context. Each returns a dictionary - #: that the template context is updated with. - #: To register a function here, use the :meth:`context_processor` - #: decorator. - self.template_context_processors = [_default_template_ctx_processor] - - #: the :class:`~werkzeug.routing.Map` for this instance. You can use - #: this to change the routing converters after the class was created - #: but before any routes are connected. Example:: - #: - #: from werkzeug import BaseConverter - #: - #: class ListConverter(BaseConverter): - #: def to_python(self, value): - #: return value.split(',') - #: def to_url(self, values): - #: return ','.join(BaseConverter.to_url(value) - #: for value in values) - #: - #: app = Flask(__name__) - #: app.url_map.converters['list'] = ListConverter - self.url_map = Map() - - if self.static_path is not None: - self.add_url_rule(self.static_path + '/', - build_only=True, endpoint='static') - if pkg_resources is not None: - target = (self.package_name, 'static') - else: - target = os.path.join(self.root_path, 'static') - self.wsgi_app = SharedDataMiddleware(self.wsgi_app, { - self.static_path: target - }) - - #: the Jinja2 environment. It is created from the - #: :attr:`jinja_options` and the loader that is returned - #: by the :meth:`create_jinja_loader` function. - self.jinja_env = Environment(loader=self.create_jinja_loader(), - **self.jinja_options) - self.jinja_env.globals.update( - url_for=url_for, - get_flashed_messages=get_flashed_messages - ) - self.jinja_env.filters['tojson'] = _tojson_filter - - def create_jinja_loader(self): - """Creates the Jinja loader. By default just a package loader for - the configured package is returned that looks up templates in the - `templates` folder. To add other loaders it's possible to - override this method. - """ - if pkg_resources is None: - return FileSystemLoader(os.path.join(self.root_path, 'templates')) - return PackageLoader(self.package_name) - - def update_template_context(self, context): - """Update the template context with some commonly used variables. - This injects request, session and g into the template context. - - :param context: the context as a dictionary that is updated in place - to add extra variables. - """ - for func in self.template_context_processors: - context.update(func()) - - def run(self, host='127.0.0.1', port=5000, **options): - """Runs the application on a local development server. If the - :attr:`debug` flag is set the server will automatically reload - for code changes and show a debugger in case an exception happened. - - :param host: the hostname to listen on. set this to ``'0.0.0.0'`` - to have the server available externally as well. - :param port: the port of the webserver - :param options: the options to be forwarded to the underlying - Werkzeug server. See :func:`werkzeug.run_simple` - for more information. - """ - from werkzeug import run_simple - if 'debug' in options: - self.debug = options.pop('debug') - options.setdefault('use_reloader', self.debug) - options.setdefault('use_debugger', self.debug) - return run_simple(host, port, self, **options) - - def test_client(self): - """Creates a test client for this application. For information - about unit testing head over to :ref:`testing`. - """ - from werkzeug import Client - return Client(self, self.response_class, use_cookies=True) - - def open_resource(self, resource): - """Opens a resource from the application's resource folder. To see - how this works, consider the following folder structure:: - - /myapplication.py - /schemal.sql - /static - /style.css - /template - /layout.html - /index.html - - If you want to open the `schema.sql` file you would do the - following:: - - with app.open_resource('schema.sql') as f: - contents = f.read() - do_something_with(contents) - - :param resource: the name of the resource. To access resources within - subfolders use forward slashes as separator. - """ - if pkg_resources is None: - return open(os.path.join(self.root_path, resource), 'rb') - return pkg_resources.resource_stream(self.package_name, resource) - - def open_session(self, request): - """Creates or opens a new session. Default implementation stores all - session data in a signed cookie. This requires that the - :attr:`secret_key` is set. - - :param request: an instance of :attr:`request_class`. - """ - key = self.secret_key - if key is not None: - return SecureCookie.load_cookie(request, self.session_cookie_name, - secret_key=key) - - def save_session(self, session, response): - """Saves the session if it needs updates. For the default - implementation, check :meth:`open_session`. - - :param session: the session to be saved (a - :class:`~werkzeug.contrib.securecookie.SecureCookie` - object) - :param response: an instance of :attr:`response_class` - """ - session.save_cookie(response, self.session_cookie_name) - - def add_url_rule(self, rule, endpoint, view_func=None, **options): - """Connects a URL rule. Works exactly like the :meth:`route` - decorator. If a view_func is provided it will be registered with the - endpoint. - - Basically this example:: - - @app.route('/') - def index(): - pass - - Is equivalent to the following:: - - def index(): - pass - app.add_url_rule('/', 'index', index) - - If the view_func is not provided you will need to connect the endpoint - to a view function like so:: - - app.view_functions['index'] = index - - .. versionchanged:: 0.2 - `view_func` parameter added - - :param rule: the URL rule as string - :param endpoint: the endpoint for the registered URL rule. Flask - itself assumes the name of the view function as - endpoint - :param view_func: the function to call when serving a request to the - provided endpoint - :param options: the options to be forwarded to the underlying - :class:`~werkzeug.routing.Rule` object - """ - options['endpoint'] = endpoint - options.setdefault('methods', ('GET',)) - self.url_map.add(Rule(rule, **options)) - if view_func is not None: - self.view_functions[endpoint] = view_func - - def route(self, rule, **options): - """A decorator that is used to register a view function for a - given URL rule. Example:: - - @app.route('/') - def index(): - return 'Hello World' - - Variables 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 possible: - - =========== =========================================== - `int` accepts integers - `float` like `int` but for floating point values - `path` like the default but also accepts slashes - =========== =========================================== - - Here 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 request - 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. - - The :meth:`route` decorator accepts a couple of other arguments - as well: - - :param rule: the URL rule as string - :param methods: a list of methods this rule should be limited - to (``GET``, ``POST`` etc.). By default a rule - just listens for ``GET`` (and implicitly ``HEAD``). - :param subdomain: specifies the rule for the subdoain in case - subdomain matching is in use. - :param strict_slashes: can be used to disable the strict slashes - setting for this rule. See above. - :param options: other options to be forwarded to the underlying - :class:`~werkzeug.routing.Rule` object. - """ - def decorator(f): - self.add_url_rule(rule, f.__name__, f, **options) - return f - return decorator - - def errorhandler(self, code): - """A decorator that is used to register a function give a given - error code. Example:: - - @app.errorhandler(404) - def page_not_found(): - return 'This page does not exist', 404 - - You can also register a function as error handler without using - the :meth:`errorhandler` decorator. The following example is - equivalent to the one above:: - - def page_not_found(): - return 'This page does not exist', 404 - app.error_handlers[404] = page_not_found - - :param code: the code as integer for the handler - """ - def decorator(f): - self.error_handlers[code] = f - return f - return decorator - - def before_request(self, f): - """Registers a function to run before each request.""" - self.before_request_funcs.append(f) - return f - - def after_request(self, f): - """Register a function to be run after each request.""" - self.after_request_funcs.append(f) - return f - - def context_processor(self, f): - """Registers a template context processor function.""" - self.template_context_processors.append(f) - return f - - def match_request(self): - """Matches the current request against the URL map and also - stores the endpoint and view arguments on the request object - is successful, otherwise the exception is stored. - """ - rv = _request_ctx_stack.top.url_adapter.match() - request.endpoint, request.view_args = rv - return rv - - def dispatch_request(self): - """Does the request dispatching. Matches the URL and returns the - return value of the view or error handler. This does not have to - be a response object. In order to convert the return value to a - proper response object, call :func:`make_response`. - """ - try: - endpoint, values = self.match_request() - return self.view_functions[endpoint](**values) - except HTTPException, e: - handler = self.error_handlers.get(e.code) - if handler is None: - return e - return handler(e) - except Exception, e: - handler = self.error_handlers.get(500) - if self.debug or handler is None: - raise - return handler(e) - - def make_response(self, rv): - """Converts the return value from a view function to a real - response object that is an instance of :attr:`response_class`. - - The following types are allowd for `rv`: - - ======================= =========================================== - :attr:`response_class` the object is returned unchanged - :class:`str` a response object is created with the - string as body - :class:`unicode` a response object is created with the - string encoded to utf-8 as body - :class:`tuple` the response object is created with the - contents of the tuple as arguments - a WSGI function the function is called as WSGI application - and buffered as response object - ======================= =========================================== - - :param rv: the return value from the view function - """ - if isinstance(rv, self.response_class): - return rv - if isinstance(rv, basestring): - return self.response_class(rv) - if isinstance(rv, tuple): - return self.response_class(*rv) - return self.response_class.force_type(rv, request.environ) - - def preprocess_request(self): - """Called before the actual request dispatching and will - call every as :meth:`before_request` decorated function. - If any of these function returns a value it's handled as - if it was the return value from the view and further - request handling is stopped. - """ - for func in self.before_request_funcs: - rv = func() - if rv is not None: - return rv - - def process_response(self, response): - """Can be overridden in order to modify the response object - before it's sent to the WSGI server. By default this will - call all the :meth:`after_request` decorated functions. - - :param response: a :attr:`response_class` object. - :return: a new response object or the same, has to be an - instance of :attr:`response_class`. - """ - session = _request_ctx_stack.top.session - if not isinstance(session, _NullSession): - self.save_session(session, response) - for handler in self.after_request_funcs: - response = handler(response) - return response - - def wsgi_app(self, environ, start_response): - """The actual WSGI application. This is not implemented in - `__call__` so that middlewares can be applied without losing a - reference to the class. So instead of doing this:: - - app = MyMiddleware(app) - - It's a better idea to do this instead:: - - app.wsgi_app = MyMiddleware(app.wsgi_app) - - Then you still have the original application object around and - can continue to call methods on it. - - :param environ: a WSGI environment - :param start_response: a callable accepting a status code, - a list of headers and an optional - exception context to start the response - """ - with self.request_context(environ): - rv = self.preprocess_request() - if rv is None: - rv = self.dispatch_request() - response = self.make_response(rv) - response = self.process_response(response) - return response(environ, start_response) - - def request_context(self, environ): - """Creates a request context from the given environment and binds - it to the current context. This must be used in combination with - the `with` statement because the request is only bound to the - current context for the duration of the `with` block. - - Example usage:: - - with app.request_context(environ): - do_something_with(request) - - :params environ: a WSGI environment - """ - return _RequestContext(self, environ) - - def test_request_context(self, *args, **kwargs): - """Creates a WSGI environment from the given values (see - :func:`werkzeug.create_environ` for more information, this - function accepts the same arguments). - """ - return self.request_context(create_environ(*args, **kwargs)) - - def __call__(self, environ, start_response): - """Shortcut for :attr:`wsgi_app`.""" - return self.wsgi_app(environ, start_response) - - -# context locals -_request_ctx_stack = LocalStack() -current_app = LocalProxy(lambda: _request_ctx_stack.top.app) -request = LocalProxy(lambda: _request_ctx_stack.top.request) -session = LocalProxy(lambda: _request_ctx_stack.top.session) -g = LocalProxy(lambda: _request_ctx_stack.top.g) diff --git a/website/flask_website.py b/flask_website.py similarity index 100% rename from website/flask_website.py rename to flask_website.py diff --git a/setup.py b/setup.py deleted file mode 100644 index ae68c49e..00000000 --- a/setup.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Flask ------ - -Flask is a microframework for Python based on Werkzeug, Jinja 2 and good -intentions. And before you ask: It's BSD licensed! - -Flask is Fun -```````````` - -:: - - from flask import Flask - app = Flask(__name__) - - @app.route("/") - def hello(): - return "Hello World!" - - if __name__ == "__main__": - app.run() - -And Easy to Setup -````````````````` - -:: - - $ easy_install Flask - $ python hello.py - * Running on http://localhost:5000/ - -Links -````` - -* `website `_ -* `documentation `_ -* `development version - `_ - -""" -from setuptools import setup - - -setup( - name='Flask', - version='0.2', - url='http://github.com/mitsuhiko/flask/', - license='BSD', - author='Armin Ronacher', - author_email='armin.ronacher@active-4.com', - description='A microframework based on Werkzeug, Jinja2 ' - 'and good intentions', - long_description=__doc__, - py_modules=['flask'], - zip_safe=False, - platforms='any', - install_requires=[ - 'Werkzeug>=0.6.1', - 'Jinja2>=2.4' - ], - classifiers=[ - 'Development Status :: 3 - Alpha', - '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' - ] -) diff --git a/website/static/logo.png b/static/logo.png similarity index 100% rename from website/static/logo.png rename to static/logo.png diff --git a/website/static/mailinglist.js b/static/mailinglist.js similarity index 100% rename from website/static/mailinglist.js rename to static/mailinglist.js diff --git a/website/static/mailinglist.png b/static/mailinglist.png similarity index 100% rename from website/static/mailinglist.png rename to static/mailinglist.png diff --git a/website/static/mask.png b/static/mask.png similarity index 100% rename from website/static/mask.png rename to static/mask.png diff --git a/website/static/ship.png b/static/ship.png similarity index 100% rename from website/static/ship.png rename to static/ship.png diff --git a/website/static/style.css b/static/style.css similarity index 100% rename from website/static/style.css rename to static/style.css diff --git a/website/sync-librelist.py b/sync-librelist.py similarity index 100% rename from website/sync-librelist.py rename to sync-librelist.py diff --git a/website/templates/404.html b/templates/404.html similarity index 100% rename from website/templates/404.html rename to templates/404.html diff --git a/website/templates/index.html b/templates/index.html similarity index 100% rename from website/templates/index.html rename to templates/index.html diff --git a/website/templates/layout.html b/templates/layout.html similarity index 100% rename from website/templates/layout.html rename to templates/layout.html diff --git a/website/templates/mailinglist/archive.html b/templates/mailinglist/archive.html similarity index 100% rename from website/templates/mailinglist/archive.html rename to templates/mailinglist/archive.html diff --git a/website/templates/mailinglist/index.html b/templates/mailinglist/index.html similarity index 100% rename from website/templates/mailinglist/index.html rename to templates/mailinglist/index.html diff --git a/website/templates/mailinglist/layout.html b/templates/mailinglist/layout.html similarity index 100% rename from website/templates/mailinglist/layout.html rename to templates/mailinglist/layout.html diff --git a/website/templates/mailinglist/show_thread.html b/templates/mailinglist/show_thread.html similarity index 100% rename from website/templates/mailinglist/show_thread.html rename to templates/mailinglist/show_thread.html diff --git a/tests/flask_tests.py b/tests/flask_tests.py deleted file mode 100644 index 5f07fbe8..00000000 --- a/tests/flask_tests.py +++ /dev/null @@ -1,316 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Flask Tests - ~~~~~~~~~~~ - - Tests Flask itself. The majority of Flask is already tested - as part of Werkzeug. - - :copyright: (c) 2010 by Armin Ronacher. - :license: BSD, see LICENSE for more details. -""" -from __future__ import with_statement -import os -import sys -import flask -import unittest -import tempfile - - -example_path = os.path.join(os.path.dirname(__file__), '..', 'examples') -sys.path.append(os.path.join(example_path, 'flaskr')) -sys.path.append(os.path.join(example_path, 'minitwit')) - - -class ContextTestCase(unittest.TestCase): - - def test_context_binding(self): - app = flask.Flask(__name__) - @app.route('/') - def index(): - return 'Hello %s!' % flask.request.args['name'] - @app.route('/meh') - def meh(): - return flask.request.url - - with app.test_request_context('/?name=World'): - assert index() == 'Hello World!' - with app.test_request_context('/meh'): - assert meh() == 'http://localhost/meh' - - -class BasicFunctionalityTestCase(unittest.TestCase): - - def test_request_dispatching(self): - app = flask.Flask(__name__) - @app.route('/') - def index(): - return flask.request.method - @app.route('/more', methods=['GET', 'POST']) - def more(): - return flask.request.method - - c = app.test_client() - assert c.get('/').data == 'GET' - rv = c.post('/') - assert rv.status_code == 405 - assert sorted(rv.allow) == ['GET', 'HEAD'] - rv = c.head('/') - assert rv.status_code == 200 - assert not rv.data # head truncates - assert c.post('/more').data == 'POST' - assert c.get('/more').data == 'GET' - rv = c.delete('/more') - assert rv.status_code == 405 - assert sorted(rv.allow) == ['GET', 'HEAD', 'POST'] - - def test_url_mapping(self): - app = flask.Flask(__name__) - def index(): - return flask.request.method - def more(): - return flask.request.method - - app.add_url_rule('/', 'index', index) - app.add_url_rule('/more', 'more', more, methods=['GET', 'POST']) - - c = app.test_client() - assert c.get('/').data == 'GET' - rv = c.post('/') - assert rv.status_code == 405 - assert sorted(rv.allow) == ['GET', 'HEAD'] - rv = c.head('/') - assert rv.status_code == 200 - assert not rv.data # head truncates - assert c.post('/more').data == 'POST' - assert c.get('/more').data == 'GET' - rv = c.delete('/more') - assert rv.status_code == 405 - assert sorted(rv.allow) == ['GET', 'HEAD', 'POST'] - - def test_session(self): - app = flask.Flask(__name__) - app.secret_key = 'testkey' - @app.route('/set', methods=['POST']) - def set(): - flask.session['value'] = flask.request.form['value'] - return 'value set' - @app.route('/get') - def get(): - return flask.session['value'] - - c = app.test_client() - assert c.post('/set', data={'value': '42'}).data == 'value set' - assert c.get('/get').data == '42' - - def test_missing_session(self): - app = flask.Flask(__name__) - def expect_exception(f, *args, **kwargs): - try: - f(*args, **kwargs) - except RuntimeError, e: - assert e.args and 'session is unavailable' in e.args[0] - else: - assert False, 'expected exception' - with app.test_request_context(): - assert flask.session.get('missing_key') is None - expect_exception(flask.session.__setitem__, 'foo', 42) - expect_exception(flask.session.pop, 'foo') - - def test_flashes(self): - app = flask.Flask(__name__) - app.secret_key = 'testkey' - - with app.test_request_context(): - assert not flask.session.modified - flask.flash('Zap') - flask.session.modified = False - flask.flash('Zip') - assert flask.session.modified - assert list(flask.get_flashed_messages()) == ['Zap', 'Zip'] - - def test_request_processing(self): - app = flask.Flask(__name__) - evts = [] - @app.before_request - def before_request(): - evts.append('before') - @app.after_request - def after_request(response): - response.data += '|after' - evts.append('after') - return response - @app.route('/') - def index(): - assert 'before' in evts - assert 'after' not in evts - return 'request' - assert 'after' not in evts - rv = app.test_client().get('/').data - assert 'after' in evts - assert rv == 'request|after' - - def test_error_handling(self): - app = flask.Flask(__name__) - @app.errorhandler(404) - def not_found(e): - return 'not found', 404 - @app.errorhandler(500) - def internal_server_error(e): - return 'internal server error', 500 - @app.route('/') - def index(): - flask.abort(404) - @app.route('/error') - def error(): - 1/0 - c = app.test_client() - rv = c.get('/') - assert rv.status_code == 404 - assert rv.data == 'not found' - rv = c.get('/error') - assert rv.status_code == 500 - assert 'internal server error' in rv.data - - def test_response_creation(self): - app = flask.Flask(__name__) - @app.route('/unicode') - def from_unicode(): - return u'Hällo Wörld' - @app.route('/string') - def from_string(): - return u'Hällo Wörld'.encode('utf-8') - @app.route('/args') - def from_tuple(): - return 'Meh', 400, {'X-Foo': 'Testing'}, 'text/plain' - c = app.test_client() - assert c.get('/unicode').data == u'Hällo Wörld'.encode('utf-8') - assert c.get('/string').data == u'Hällo Wörld'.encode('utf-8') - rv = c.get('/args') - assert rv.data == 'Meh' - assert rv.headers['X-Foo'] == 'Testing' - assert rv.status_code == 400 - assert rv.mimetype == 'text/plain' - - def test_url_generation(self): - app = flask.Flask(__name__) - @app.route('/hello/', methods=['POST']) - def hello(): - pass - with app.test_request_context(): - assert flask.url_for('hello', name='test x') == '/hello/test%20x' - - def test_custom_converters(self): - from werkzeug.routing import BaseConverter - class ListConverter(BaseConverter): - def to_python(self, value): - return value.split(',') - def to_url(self, value): - return ','.join(super(ListConverter, self).to_url(x) for x in value) - app = flask.Flask(__name__) - app.url_map.converters['list'] = ListConverter - @app.route('/') - def index(args): - return '|'.join(args) - c = app.test_client() - assert c.get('/1,2,3').data == '1|2|3' - - def test_static_files(self): - app = flask.Flask(__name__) - rv = app.test_client().get('/static/index.html') - assert rv.status_code == 200 - assert rv.data.strip() == '

Hello World!

' - with app.test_request_context(): - assert flask.url_for('static', filename='index.html') \ - == '/static/index.html' - - -class JSONTestCase(unittest.TestCase): - - def test_jsonify(self): - d = dict(a=23, b=42, c=[1, 2, 3]) - app = flask.Flask(__name__) - @app.route('/kw') - def return_kwargs(): - return flask.jsonify(**d) - @app.route('/dict') - def return_dict(): - return flask.jsonify(d) - c = app.test_client() - for url in '/kw', '/dict': - rv = c.get(url) - assert rv.mimetype == 'application/json' - assert flask.json.loads(rv.data) == d - - def test_json_attr(self): - app = flask.Flask(__name__) - @app.route('/add', methods=['POST']) - def add(): - return unicode(flask.request.json['a'] + flask.request.json['b']) - c = app.test_client() - rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}), - content_type='application/json') - assert rv.data == '3' - - def test_template_escaping(self): - app = flask.Flask(__name__) - with app.test_request_context(): - rv = flask.render_template_string('{{ ""|tojson|safe }}') - assert rv == '"<\\/script>"' - rv = flask.render_template_string('{{ "<\0/script>"|tojson|safe }}') - assert rv == '"<\\u0000\\/script>"' - - -class TemplatingTestCase(unittest.TestCase): - - def test_context_processing(self): - app = flask.Flask(__name__) - @app.context_processor - def context_processor(): - return {'injected_value': 42} - @app.route('/') - def index(): - return flask.render_template('context_template.html', value=23) - rv = app.test_client().get('/') - assert rv.data == '

23|42' - - def test_escaping(self): - text = '

Hello World!' - app = flask.Flask(__name__) - @app.route('/') - def index(): - return flask.render_template('escaping_template.html', text=text, - html=flask.Markup(text)) - lines = app.test_client().get('/').data.splitlines() - assert lines == [ - '<p>Hello World!', - '

Hello World!', - '

Hello World!', - '

Hello World!', - '<p>Hello World!', - '

Hello World!' - ] - - def test_macros(self): - app = flask.Flask(__name__) - with app.test_request_context(): - macro = flask.get_template_attribute('_macro.html', 'hello') - assert macro('World') == 'Hello World!' - - -def suite(): - from minitwit_tests import MiniTwitTestCase - from flaskr_tests import FlaskrTestCase - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ContextTestCase)) - suite.addTest(unittest.makeSuite(BasicFunctionalityTestCase)) - suite.addTest(unittest.makeSuite(TemplatingTestCase)) - if flask.json_available: - suite.addTest(unittest.makeSuite(JSONTestCase)) - suite.addTest(unittest.makeSuite(MiniTwitTestCase)) - suite.addTest(unittest.makeSuite(FlaskrTestCase)) - return suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/tests/static/index.html b/tests/static/index.html deleted file mode 100644 index de8b69b6..00000000 --- a/tests/static/index.html +++ /dev/null @@ -1 +0,0 @@ -

Hello World!

diff --git a/tests/templates/_macro.html b/tests/templates/_macro.html deleted file mode 100644 index 3460ae2e..00000000 --- a/tests/templates/_macro.html +++ /dev/null @@ -1 +0,0 @@ -{% macro hello(name) %}Hello {{ name }}!{% endmacro %} diff --git a/tests/templates/context_template.html b/tests/templates/context_template.html deleted file mode 100644 index fadf3e5d..00000000 --- a/tests/templates/context_template.html +++ /dev/null @@ -1 +0,0 @@ -

{{ value }}|{{ injected_value }} diff --git a/tests/templates/escaping_template.html b/tests/templates/escaping_template.html deleted file mode 100644 index dc47644d..00000000 --- a/tests/templates/escaping_template.html +++ /dev/null @@ -1,6 +0,0 @@ -{{ text }} -{{ html }} -{% autoescape false %}{{ text }} -{{ html }}{% endautoescape %} -{% autoescape true %}{{ text }} -{{ html }}{% endautoescape %}