├── .gitignore ├── .gitmodules ├── .travis-devel-requirements.txt ├── .travis-lowest-requirements.txt ├── .travis-release-requirements.txt ├── .travis.yml ├── AUTHORS ├── CHANGES ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README ├── artwork ├── LICENSE └── logo-full.svg ├── docs ├── .gitignore ├── Makefile ├── _static │ ├── debugger.png │ ├── flask.png │ ├── flaskr.png │ ├── logo-full.png │ ├── no.png │ ├── touch-icon.png │ └── yes.png ├── _templates │ ├── sidebarintro.html │ └── sidebarlogo.html ├── advanced_foreword.rst ├── api.rst ├── appcontext.rst ├── becomingbig.rst ├── blueprints.rst ├── changelog.rst ├── conf.py ├── config.rst ├── contents.rst.inc ├── deploying │ ├── cgi.rst │ ├── fastcgi.rst │ ├── index.rst │ ├── mod_wsgi.rst │ ├── uwsgi.rst │ └── wsgi-standalone.rst ├── design.rst ├── en │ ├── Makefile │ ├── _static │ │ ├── debugger.png │ │ ├── flask.png │ │ ├── flaskr.png │ │ ├── logo-full.png │ │ ├── no.png │ │ ├── touch-icon.png │ │ └── yes.png │ ├── _templates │ │ ├── sidebarintro.html │ │ └── sidebarlogo.html │ ├── advanced_foreword.rst │ ├── api.rst │ ├── appcontext.rst │ ├── becomingbig.rst │ ├── blueprints.rst │ ├── changelog.rst │ ├── conf.py │ ├── config.rst │ ├── contents.rst.inc │ ├── deploying │ │ ├── cgi.rst │ │ ├── fastcgi.rst │ │ ├── index.rst │ │ ├── mod_wsgi.rst │ │ ├── uwsgi.rst │ │ └── wsgi-standalone.rst │ ├── design.rst │ ├── errorhandling.rst │ ├── extensiondev.rst │ ├── extensions.rst │ ├── flaskdocext.py │ ├── flaskext.py │ ├── flaskstyle.sty │ ├── foreword.rst │ ├── htmlfaq.rst │ ├── index.rst │ ├── installation.rst │ ├── latexindex.rst │ ├── license.rst │ ├── logo.pdf │ ├── make.bat │ ├── patterns │ │ ├── appdispatch.rst │ │ ├── appfactories.rst │ │ ├── caching.rst │ │ ├── deferredcallbacks.rst │ │ ├── distribute.rst │ │ ├── errorpages.rst │ │ ├── fabric.rst │ │ ├── favicon.rst │ │ ├── fileuploads.rst │ │ ├── flashing.rst │ │ ├── index.rst │ │ ├── jquery.rst │ │ ├── lazyloading.rst │ │ ├── methodoverrides.rst │ │ ├── mongokit.rst │ │ ├── packages.rst │ │ ├── requestchecksum.rst │ │ ├── sqlalchemy.rst │ │ ├── sqlite3.rst │ │ ├── streaming.rst │ │ ├── templateinheritance.rst │ │ ├── urlprocessors.rst │ │ ├── viewdecorators.rst │ │ └── wtforms.rst │ ├── quickstart.rst │ ├── reqcontext.rst │ ├── security.rst │ ├── shell.rst │ ├── signals.rst │ ├── styleguide.rst │ ├── templating.rst │ ├── testing.rst │ ├── tutorial │ │ ├── css.rst │ │ ├── dbcon.rst │ │ ├── dbinit.rst │ │ ├── folders.rst │ │ ├── index.rst │ │ ├── introduction.rst │ │ ├── schema.rst │ │ ├── setup.rst │ │ ├── templates.rst │ │ ├── testing.rst │ │ └── views.rst │ ├── unicode.rst │ ├── upgrading.rst │ └── views.rst ├── errorhandling.rst ├── extensiondev.rst ├── extensions.rst ├── flaskdocext.py ├── flaskext.py ├── flaskstyle.sty ├── foreword.rst ├── htmlfaq.rst ├── index.rst ├── installation.rst ├── ko │ ├── Makefile │ ├── _static │ │ ├── debugger.png │ │ ├── flask.png │ │ ├── flaskr.png │ │ ├── logo-full.png │ │ ├── no.png │ │ ├── touch-icon.png │ │ └── yes.png │ ├── _templates │ │ ├── sidebarintro.html │ │ └── sidebarlogo.html │ ├── advanced_foreword.rst │ ├── api.rst │ ├── appcontext.rst │ ├── becomingbig.rst │ ├── blueprints.rst │ ├── changelog.rst │ ├── conf.py │ ├── config.rst │ ├── contents.rst.inc │ ├── deploying │ │ ├── cgi.rst │ │ ├── fastcgi.rst │ │ ├── index.rst │ │ ├── mod_wsgi.rst │ │ ├── uwsgi.rst │ │ └── wsgi-standalone.rst │ ├── design.rst │ ├── errorhandling.rst │ ├── extensiondev.rst │ ├── extensions.rst │ ├── flaskdocext.py │ ├── flaskext.py │ ├── flaskstyle.sty │ ├── foreword.rst │ ├── htmlfaq.rst │ ├── index.rst │ ├── installation.rst │ ├── latexindex.rst │ ├── license.rst │ ├── logo.pdf │ ├── make.bat │ ├── patterns │ │ ├── appdispatch.rst │ │ ├── appfactories.rst │ │ ├── caching.rst │ │ ├── deferredcallbacks.rst │ │ ├── distribute.rst │ │ ├── errorpages.rst │ │ ├── fabric.rst │ │ ├── favicon.rst │ │ ├── fileuploads.rst │ │ ├── flashing.rst │ │ ├── index.rst │ │ ├── jquery.rst │ │ ├── lazyloading.rst │ │ ├── methodoverrides.rst │ │ ├── mongokit.rst │ │ ├── packages.rst │ │ ├── requestchecksum.rst │ │ ├── sqlalchemy.rst │ │ ├── sqlite3.rst │ │ ├── streaming.rst │ │ ├── templateinheritance.rst │ │ ├── urlprocessors.rst │ │ ├── viewdecorators.rst │ │ └── wtforms.rst │ ├── quickstart.rst │ ├── reqcontext.rst │ ├── security.rst │ ├── shell.rst │ ├── signals.rst │ ├── styleguide.rst │ ├── templating.rst │ ├── testing.rst │ ├── tutorial │ │ ├── css.rst │ │ ├── dbcon.rst │ │ ├── dbinit.rst │ │ ├── folders.rst │ │ ├── index.rst │ │ ├── introduction.rst │ │ ├── schema.rst │ │ ├── setup.rst │ │ ├── templates.rst │ │ ├── testing.rst │ │ └── views.rst │ ├── unicode.rst │ ├── upgrading.rst │ └── views.rst ├── latexindex.rst ├── license.rst ├── logo.pdf ├── make.bat ├── patterns │ ├── apierrors.rst │ ├── appdispatch.rst │ ├── appfactories.rst │ ├── caching.rst │ ├── celery.rst │ ├── deferredcallbacks.rst │ ├── distribute.rst │ ├── errorpages.rst │ ├── fabric.rst │ ├── favicon.rst │ ├── fileuploads.rst │ ├── flashing.rst │ ├── index.rst │ ├── jquery.rst │ ├── lazyloading.rst │ ├── methodoverrides.rst │ ├── mongokit.rst │ ├── packages.rst │ ├── requestchecksum.rst │ ├── sqlalchemy.rst │ ├── sqlite3.rst │ ├── streaming.rst │ ├── templateinheritance.rst │ ├── urlprocessors.rst │ ├── viewdecorators.rst │ └── wtforms.rst ├── python3.rst ├── quickstart.rst ├── reqcontext.rst ├── security.rst ├── shell.rst ├── signals.rst ├── styleguide.rst ├── templating.rst ├── testing.rst ├── tutorial │ ├── css.rst │ ├── dbcon.rst │ ├── dbinit.rst │ ├── folders.rst │ ├── index.rst │ ├── introduction.rst │ ├── schema.rst │ ├── setup.rst │ ├── templates.rst │ ├── testing.rst │ └── views.rst ├── unicode.rst ├── upgrading.rst └── views.rst ├── examples ├── blueprintexample │ ├── blueprintexample.py │ ├── blueprintexample_test.py │ └── simple_page │ │ ├── __init__.py │ │ ├── simple_page.py │ │ └── templates │ │ └── pages │ │ ├── hello.html │ │ ├── index.html │ │ ├── layout.html │ │ └── world.html ├── flaskr │ ├── README │ ├── flaskr.py │ ├── flaskr_tests.py │ ├── schema.sql │ ├── static │ │ └── style.css │ └── templates │ │ ├── layout.html │ │ ├── login.html │ │ └── show_entries.html ├── jqueryexample │ ├── jqueryexample.py │ └── templates │ │ ├── index.html │ │ └── layout.html ├── minitwit │ ├── README │ ├── minitwit.py │ ├── minitwit_tests.py │ ├── schema.sql │ ├── static │ │ └── style.css │ └── templates │ │ ├── layout.html │ │ ├── login.html │ │ ├── register.html │ │ └── timeline.html └── persona │ ├── persona.py │ ├── static │ ├── persona.js │ ├── spinner.png │ └── style.css │ └── templates │ ├── index.html │ └── layout.html ├── flask ├── __init__.py ├── _compat.py ├── app.py ├── blueprints.py ├── config.py ├── ctx.py ├── debughelpers.py ├── ext │ └── __init__.py ├── exthook.py ├── globals.py ├── helpers.py ├── json.py ├── logging.py ├── module.py ├── sessions.py ├── signals.py ├── templating.py ├── testing.py ├── testsuite │ ├── __init__.py │ ├── appctx.py │ ├── basic.py │ ├── blueprints.py │ ├── config.py │ ├── deprecations.py │ ├── examples.py │ ├── ext.py │ ├── helpers.py │ ├── regression.py │ ├── reqctx.py │ ├── signals.py │ ├── static │ │ └── index.html │ ├── subclassing.py │ ├── templates │ │ ├── _macro.html │ │ ├── context_template.html │ │ ├── escaping_template.html │ │ ├── mail.txt │ │ ├── nested │ │ │ └── nested.txt │ │ ├── simple_template.html │ │ ├── template_filter.html │ │ └── template_test.html │ ├── templating.py │ ├── test_apps │ │ ├── blueprintapp │ │ │ ├── __init__.py │ │ │ └── apps │ │ │ │ ├── __init__.py │ │ │ │ ├── admin │ │ │ │ ├── __init__.py │ │ │ │ ├── static │ │ │ │ │ ├── css │ │ │ │ │ │ └── test.css │ │ │ │ │ └── test.txt │ │ │ │ └── templates │ │ │ │ │ └── admin │ │ │ │ │ └── index.html │ │ │ │ └── frontend │ │ │ │ ├── __init__.py │ │ │ │ └── templates │ │ │ │ └── frontend │ │ │ │ └── index.html │ │ ├── config_module_app.py │ │ ├── config_package_app │ │ │ └── __init__.py │ │ ├── flask_broken │ │ │ ├── __init__.py │ │ │ └── b.py │ │ ├── flask_newext_package │ │ │ ├── __init__.py │ │ │ └── submodule.py │ │ ├── flask_newext_simple.py │ │ ├── flaskext │ │ │ ├── __init__.py │ │ │ ├── oldext_package │ │ │ │ ├── __init__.py │ │ │ │ └── submodule.py │ │ │ └── oldext_simple.py │ │ ├── importerror.py │ │ ├── lib │ │ │ └── python2.5 │ │ │ │ └── site-packages │ │ │ │ ├── SiteEgg.egg │ │ │ │ ├── site_app.py │ │ │ │ └── site_package │ │ │ │ └── __init__.py │ │ ├── main_app.py │ │ ├── moduleapp │ │ │ ├── __init__.py │ │ │ └── apps │ │ │ │ ├── __init__.py │ │ │ │ ├── admin │ │ │ │ ├── __init__.py │ │ │ │ ├── static │ │ │ │ │ ├── css │ │ │ │ │ │ └── test.css │ │ │ │ │ └── test.txt │ │ │ │ └── templates │ │ │ │ │ └── index.html │ │ │ │ └── frontend │ │ │ │ ├── __init__.py │ │ │ │ └── templates │ │ │ │ └── index.html │ │ ├── path │ │ │ └── installed_package │ │ │ │ └── __init__.py │ │ └── subdomaintestmodule │ │ │ ├── __init__.py │ │ │ └── static │ │ │ └── hello.txt │ ├── testing.py │ └── views.py ├── views.py └── wrappers.py ├── run-tests.py ├── scripts ├── flask-07-upgrade.py ├── flaskext_compat.py ├── flaskext_test.py ├── make-release.py └── testproj │ ├── templates │ └── index.html │ └── test.py ├── setup.cfg ├── setup.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.pyo 4 | env 5 | env* 6 | dist 7 | *.egg 8 | *.egg-info 9 | _mailinglist 10 | .tox 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/_themes"] 2 | path = docs/_themes 3 | url = git://github.com/mitsuhiko/flask-sphinx-themes.git 4 | -------------------------------------------------------------------------------- /.travis-devel-requirements.txt: -------------------------------------------------------------------------------- 1 | git+git://github.com/mitsuhiko/werkzeug.git#egg=Werkzeug 2 | git+git://github.com/mitsuhiko/jinja2.git#egg=Jinja2 3 | git+git://github.com/mitsuhiko/itsdangerous.git#egg=itsdangerous 4 | 5 | # extra dependencies 6 | hg+http://bitbucket.org/jek/blinker#egg=blinker 7 | -------------------------------------------------------------------------------- /.travis-lowest-requirements.txt: -------------------------------------------------------------------------------- 1 | Werkzeug==0.7 2 | Jinja2==2.4 3 | itsdangerous==0.21 4 | 5 | # extra dependencies 6 | blinker==1.0 7 | -------------------------------------------------------------------------------- /.travis-release-requirements.txt: -------------------------------------------------------------------------------- 1 | # extra dependencies 2 | blinker 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "2.6" 5 | - "2.7" 6 | - "pypy" 7 | - "3.3" 8 | 9 | env: 10 | - REQUIREMENTS=lowest 11 | - REQUIREMENTS=release 12 | - REQUIREMENTS=devel 13 | 14 | matrix: 15 | exclude: 16 | # Python 3 support currently does not work with lowest requirements 17 | - python: "3.3" 18 | env: REQUIREMENTS=lowest 19 | 20 | install: 21 | - pip install -r .travis-$REQUIREMENTS-requirements.txt 22 | - pip install --editable . 23 | 24 | script: make test 25 | 26 | branches: 27 | except: 28 | - website 29 | 30 | notifications: 31 | email: false 32 | irc: 33 | channels: 34 | - "chat.freenode.net#pocoo" 35 | on_success: change 36 | on_failure: always 37 | use_notice: true 38 | skip_join: true 39 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Flask is written and maintained by Armin Ronacher and 2 | various contributors: 3 | 4 | Development Lead 5 | ```````````````` 6 | 7 | - Armin Ronacher 8 | 9 | Patches and Suggestions 10 | ``````````````````````` 11 | 12 | - Adam Zapletal 13 | - Ali Afshar 14 | - Chris Edgemon 15 | - Chris Grindstaff 16 | - Christopher Grebs 17 | - Daniel Neuhäuser 18 | - Florent Xicluna 19 | - Georg Brandl 20 | - Justin Quick 21 | - Kenneth Reitz 22 | - Marian Sigler 23 | - Matt Campell 24 | - Matthew Frazier 25 | - Michael van Tellingen 26 | - Ron DuPlain 27 | - Sebastien Estienne 28 | - Simon Sapin 29 | - Stephane Wirtel 30 | - Thomas Schranz 31 | - Zhao Xiaohong 32 | - Edmond Burnett 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 by Armin Ronacher and contributors. See AUTHORS 2 | for more details. 3 | 4 | Some rights reserved. 5 | 6 | Redistribution and use in source and binary forms of the software as well 7 | as documentation, with or without modification, are permitted provided 8 | that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided 16 | with the distribution. 17 | 18 | * The names of the contributors may not be used to endorse or 19 | promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND 23 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 24 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 | DAMAGE. 34 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile CHANGES LICENSE AUTHORS run-tests.py 2 | recursive-include artwork * 3 | recursive-include tests * 4 | recursive-include examples * 5 | recursive-include docs * 6 | recursive-exclude docs *.pyc 7 | recursive-exclude docs *.pyo 8 | recursive-exclude tests *.pyc 9 | recursive-exclude tests *.pyo 10 | recursive-exclude examples *.pyc 11 | recursive-exclude examples *.pyo 12 | recursive-include flask/testsuite/static * 13 | recursive-include flask/testsuite/templates * 14 | recursive-include flask/testsuite/test_apps * 15 | prune docs/_build 16 | prune docs/_themes/.git 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc ext-test test tox-test test-with-mem upload-docs docs audit 2 | 3 | all: clean-pyc test 4 | 5 | test: 6 | python run-tests.py 7 | 8 | tox-test: 9 | tox 10 | 11 | test-with-mem: 12 | RUN_FLASK_MEMORY_TESTS=1 python run-tests.py 13 | 14 | audit: 15 | python setup.py audit 16 | 17 | release: 18 | python scripts/make-release.py 19 | 20 | ext-test: 21 | python tests/flaskext_test.py --browse 22 | 23 | clean-pyc: 24 | find . -name '*.pyc' -exec rm -f {} + 25 | find . -name '*.pyo' -exec rm -f {} + 26 | find . -name '*~' -exec rm -f {} + 27 | 28 | upload-docs: 29 | $(MAKE) -C docs html dirhtml latex epub 30 | $(MAKE) -C docs/_build/latex all-pdf 31 | cd docs/_build/; mv html flask-docs; zip -r flask-docs.zip flask-docs; mv flask-docs html 32 | rsync -a docs/_build/dirhtml/ pocoo.org:/var/www/flask.pocoo.org/docs/ 33 | rsync -a docs/_build/latex/Flask.pdf pocoo.org:/var/www/flask.pocoo.org/docs/flask-docs.pdf 34 | rsync -a docs/_build/flask-docs.zip pocoo.org:/var/www/flask.pocoo.org/docs/flask-docs.zip 35 | rsync -a docs/_build/epub/Flask.epub pocoo.org:/var/www/flask.pocoo.org/docs/flask-docs.epub 36 | 37 | # ebook-convert docs: http://manual.calibre-ebook.com/cli/ebook-convert.html 38 | ebook: 39 | @echo 'Using .epub from `make upload-docs` to create .mobi.' 40 | @echo 'Command `ebook-covert` is provided by calibre package.' 41 | @echo 'Requires X-forwarding for Qt features used in conversion (ssh -X).' 42 | @echo 'Do not mind "Invalid value for ..." CSS errors if .mobi renders.' 43 | ssh -X pocoo.org ebook-convert /var/www/flask.pocoo.org/docs/flask-docs.epub /var/www/flask.pocoo.org/docs/flask-docs.mobi --cover http://flask.pocoo.org/docs/_images/logo-full.png --authors 'Armin Ronacher' 44 | 45 | docs: 46 | $(MAKE) -C docs html 47 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Flask // 4 | 5 | web development, one drop at a time 6 | 7 | 8 | ~ What is Flask? 9 | 10 | Flask is a microframework for Python based on Werkzeug 11 | and Jinja2. It's intended for getting started very quickly 12 | and was developed with best intentions in mind. 13 | 14 | ~ Is it ready? 15 | 16 | It's still not 1.0 but it's shaping up nicely and is 17 | already widely used. Consider the API to slightly 18 | improve over time but we don't plan on breaking it. 19 | 20 | ~ What do I need? 21 | 22 | Jinja 2.4 and Werkzeug 0.7 or later. 23 | `pip` or `easy_install` will install them for you if you do 24 | `pip install Flask`. I encourage you to use a virtualenv. 25 | Check the docs for complete installation and usage 26 | instructions. 27 | 28 | ~ Where are the docs? 29 | 30 | Go to http://flask.pocoo.org/docs/ for a prebuilt version 31 | of the current documentation. Otherwise build them yourself 32 | from the sphinx sources in the docs folder. 33 | 34 | ~ Where are the tests? 35 | 36 | Good that you're asking. The tests are in the 37 | flask/testsuite package. To run the tests use the 38 | `run-tests.py` file: 39 | 40 | $ python run-tests.py 41 | 42 | If it's not enough output for you, you can use the 43 | `--verbose` flag: 44 | 45 | $ python run-tests.py --verbose 46 | 47 | If you just want one particular testcase to run you can 48 | provide it on the command line: 49 | 50 | $ python run-tests.py test_to_run 51 | 52 | ~ Where can I get help? 53 | 54 | Either use the #pocoo IRC channel on irc.freenode.net or 55 | ask on the mailinglist: http://flask.pocoo.org/mailinglist/ 56 | 57 | See http://flask.pocoo.org/community/ for more resources. 58 | 59 | 60 | -------------------------------------------------------------------------------- /artwork/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 by Armin Ronacher. 2 | 3 | Some rights reserved. 4 | 5 | This logo or a modified version may be used by anyone to refer to the 6 | Flask project, but does not indicate endorsement by the project. 7 | 8 | Redistribution and use in source (the SVG file) and binary forms (rendered 9 | PNG files etc.) of the image, with or without modification, are permitted 10 | provided that the following conditions are met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice and this list of conditions. 14 | 15 | * The names of the contributors to the Flask software (see AUTHORS) may 16 | not be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | Note: we would appreciate that you make the image a link to 20 | http://flask.pocoo.org/ if you use it on a web page. 21 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | -------------------------------------------------------------------------------- /docs/_static/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/debugger.png -------------------------------------------------------------------------------- /docs/_static/flask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/flask.png -------------------------------------------------------------------------------- /docs/_static/flaskr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/flaskr.png -------------------------------------------------------------------------------- /docs/_static/logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/logo-full.png -------------------------------------------------------------------------------- /docs/_static/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/no.png -------------------------------------------------------------------------------- /docs/_static/touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/touch-icon.png -------------------------------------------------------------------------------- /docs/_static/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/_static/yes.png -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

About Flask

2 |

3 | Flask는 파이썬기반의 마이크로 웹개발 프레임워크입니다. 여러분은 현재 개발중인 버전의 문서를 보고 있습니다. 4 |

5 |

Other Formats

6 |

7 | 여러분은 다른 포맷의 문서로 다운로드 받을 수 있습니다: 8 |

9 | 15 |

Useful Links

16 | 22 | -------------------------------------------------------------------------------- /docs/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /docs/advanced_foreword.rst: -------------------------------------------------------------------------------- 1 | .. _advanced_foreword: 2 | 3 | 경험있는 프로그래머를 위한 머릿글 4 | ==================================== 5 | 6 | Flask에서 쓰레드 로컬 7 | ---------------------- 8 | 9 | Flask에 적용된 설계 원칙 중 하나는 단순한 업무는 단순해야한다는 것이다. 그런 종류의 업무들은 많은 코드를 요구하지 않아야 하지만, 여러분을 제약해서도 안된다. 그런 이유로 Flask는 몇몇 사람들을 놀라게 하거나, 정통적인 방식이 아니라고 생각할 수도 있는 몇개의 설계 원칙을 갖고 있다. 예를 들면, Flask는 내부적으로 쓰레드로컬방식을 사용해, 쓰레드-안전한 상태를 유지하기 위해 하나의 요청에서 함수들이 돌아가며 객체를 주고받을 필요가 없도록 했다. 이런 접근은 편리하지만, 의존 주입을 하거나 요청에 고정된 값을 사용하는 코드를 재사용하려할 때 유효한 요청 문맥을 요구한다. Flask 프로젝트는 쓰레드로컬에 대해 투명하고, 숨기지 않고, 심지어 사용되는 코드와 문서에서 드러내고 있다. 10 | 11 | 12 | 웹개발에서 주의점 13 | -------------------------------- 14 | 15 | 16 | 웹 어플리케이션을 개발할때에는 항상 보안에 대해 신경써야한다. 17 | 18 | 여러분이 웹 개발을 할때, 개발된 어플리케이션의 사용자들은 여러분의 서버에 사용자의 정보가 등록되고 남겨지는 것을 허용할 것이다. 사용자는 데이타에 있어서 여러분을 신뢰한다는 것이다. 만약 여러분이 직접 작성한 어플리케이션의 유일한 사용자라 할지라도, 자신의 데이타가 안전하기를 원할 것이다. 19 | 20 | 불행히도, 웹 어플리케이션의 보안이 타협되는 여러 가지 경우가 있다. 프라스크는 현대의 웹 어플리케이션의 가장 일반적인 보안 문제인 XSS로 부터 여러분을 보호한다. 굳이 여러분이 안전하지 않게 작성된 HTML을 안전하게 변환하지 않더라도, Flask와 그 하부의 Jinja2 템플릿 엔진이 여러분을 보호해준다. 그러나 보안문제를 유발하는 더 많은 경우가 있다. 21 | 22 | 이 문서는 보안에 있어 주의를 요구하는 웹 개발의 측면을 여러분에게 당부하고 있다. 이런 보안 관점의 몇몇은 일부 사람이 생각하는것 보다 훨씬 복잡하고, 우리 모두는 때때로 취약점이 이용될것이라는 가능성을 뛰어난 공격자가 우리의 어플리케이션의 취약점을 찾아낼때까지 낮게 점치곤한다. 그리고 여러분의 어플리케이션이 공격자가 칩입할 만큼 중요하지 않다고 생각하지 마라. 공격의 종류에 따라, 자동화된 bot이 여러분의 데이타베이스에 스팸을 채우기 위해 탐색하거나, 악성코드를 링크하는 방식과 같은 기회들이 있다. 23 | 24 | Flask는 여러분이 반드시 주의하며 개발해야하고, 요구사항에 맞춰 개발할때 취약점을 조심해야 하는 측면은 어느 다른 프레임워크와도 같다. 25 | 26 | 27 | Python3의 상태 28 | ---------------------- 29 | 30 | 요즘 파이썬 공동체는 파이썬 프로그래밍 언어의 새로운 버전을 지원하기 위한 라이브러리의 개선 과정중이다. 상황은 대단히 개선되고 있지만, 우리들이 파이썬3로 넘어가는데 걸림돌이 되는 몇가지 이슈가 있다. 이 문제들은 부분적으로 오래동안 검토되지 않은 언어의 변화에 의해 야기됐다. 부분적으로는 우리들이 저수준API가 파이썬3에서 유니코드의 차이점에 맞춰 어떤식으로 바뀌어야 하는지 해결해내지 못했다는 점도 있다. 31 | 32 | Werkzeug과 Flask는 그 변경에 대한 해결책을 찾는 순간 파이썬3로 포팅되고, 파이썬3으로 개발된 버전의 업그레이드에 대한 유용한 팁을 제공할 것이다. 그때까지, 여러분은 개발하는 동안 파이썬2.6이나 2.7을 파이썬3 경고를 활성화한 상태로 사용할 것을 권고한다. 여러분이 근래에 파이썬3로 업그레이드를 계획중이라면 `How to write forwards compatible 33 | Python code `_.를 읽는것을 적극 추천한다. 34 | 35 | 계속해서 :ref:`installation` 과 :ref:`quickstart` 살펴볼 수 있다. 36 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../CHANGES 2 | -------------------------------------------------------------------------------- /docs/contents.rst.inc: -------------------------------------------------------------------------------- 1 | 사용자 가이드 2 | ------------ 3 | 4 | 이 문서의 사용자 가이드 파트에서는, Flask에 관한 일부 배경 정보들로 시작해서 지시사항을 따라하는 Flask 웹 개발을위한 단계별 지침에 초점을 맞추고 있습니다.. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | foreword 10 | advanced_foreword 11 | installation 12 | quickstart 13 | tutorial/index 14 | templating 15 | testing 16 | errorhandling 17 | config 18 | signals 19 | views 20 | appcontext 21 | reqcontext 22 | blueprints 23 | extensions 24 | shell 25 | patterns/index 26 | deploying/index 27 | becomingbig 28 | 29 | API 레퍼런스 30 | ------------- 31 | 32 | 33 | 만약 여러분이 특정 함수, 클래스나 메소드에 대한 정보를 찾고 있다면, 문서의 이 부분은 당신에게 도움이 될 것 입니다. 34 | 35 | .. toctree:: 36 | :maxdepth: 2 37 | 38 | api 39 | 40 | 추가적인 참고사항 41 | ---------------- 42 | 43 | Flask의 디자인 노트, 법률 정보 변경 로그에 대한 관심있는 내용은 이곳에 있습니다. 44 | 45 | .. toctree:: 46 | :maxdepth: 2 47 | 48 | design 49 | htmlfaq 50 | security 51 | unicode 52 | extensiondev 53 | styleguide 54 | upgrading 55 | changelog 56 | license 57 | -------------------------------------------------------------------------------- /docs/deploying/cgi.rst: -------------------------------------------------------------------------------- 1 | CGI 2 | === 3 | 4 | 다른 모든 배포 방법을 적용할 수 없다면, CGI는 확실히 가능할 것이다. 5 | CGI는 거의 모든 주요 서버에 의해 제공되지만 보통 차선의 성능을 가진다. 6 | 7 | 또한 CGI와 같은 환경에서 실행할 수 있는 구글의 `App Engine`_ 에서 플라스크 어플리케이션을 사용할 수 있는 방법이기도 하다. 8 | 9 | .. admonition:: 주의 10 | 11 | 어플리케이션 파일에서 있을 수 있는 ``app.run()`` 호출이 ``if __name__ == '__main__':`` 블럭안에 있는지 12 | 아니면 다른 파일로 분리되어 있는지 미리 확인해야 한다. 이것은 만약 우리가 어플리케이션을 CGI/앱엔진으로 배포한다면 13 | 원하지 않게 로컬 WSGI 서버를 항상 실행하기 때문에 호출되지 않음을 확인해야 한다. 14 | 15 | `.cgi` 파일 만들기 16 | ---------------------- 17 | 18 | 먼저 CGI 어플리케이션 파일을 만드는 것이 필요하다. 그것을 `yourapplication.cgi`:: 이라고 부르자. 19 | 20 | #!/usr/bin/python 21 | from wsgiref.handlers import CGIHandler 22 | from yourapplication import app 23 | 24 | CGIHandler().run(app) 25 | 26 | 서버 설정 27 | ------------ 28 | 29 | 보통 서버를 설정하는 두가지 방법이 있다. 30 | `.cgi` 를 `cgi-bin` 으로 복사하거나(`mod_rewrite` 나 URL을 재작성하는 유사한 것을 사용) 31 | 서버 지점을 파일에 직접 작성한다. 32 | 33 | 아파치의 경우, 아래와 같이 설정 파일 안에 입력할 수 있다: 34 | 35 | .. sourcecode:: apache 36 | 37 | ScriptAlias /app /path/to/the/application.cgi 38 | 39 | 그러나 공유된 웹호스팅에서는 아파치 설정에 접근할 수 없을 지도 모른다. 40 | 이런 경우, 여러분의 어플리케이션이 실행되기를 원하는 공개 디렉토리에 있는 `.htaccess` 파일에 41 | 입력할 수 있으나, 이 경우엔는 `ScriptAlias` 지시어는 적용되지 않을 것이다: 42 | 43 | .. sourcecode:: apache 44 | 45 | RewriteEngine On 46 | RewriteCond %{REQUEST_FILENAME} !-f # Don't interfere with static files 47 | RewriteRule ^(.*)$ /path/to/the/application.cgi/$1 [L] 48 | 49 | 더 많은 정보를 위해 사용하는 웹서버의 문서를 참조하라. 50 | 51 | .. _App Engine: http://code.google.com/appengine/ 52 | -------------------------------------------------------------------------------- /docs/deploying/index.rst: -------------------------------------------------------------------------------- 1 | .. _deployment: 2 | 3 | 배포 옵션 4 | ================== 5 | 6 | 여러분이 어떤 것을 이용할 수 있는지에 따라서, 플라스크 어플리케이션을 실행할 수 있는 다양한 방법이 있다. 7 | 개발 중에는 내장 서버를 사용할 수 있지만, 운영울 위해서는 모든 배포 옵션을 사용해야 한다. 8 | (운영 중에는 내장 개발 서버를 사용하지 마라.) 사용할 수 있는 몇가지 옵션이 있다. 9 | 10 | 만약 다른 WSGI 서버가 있다면, WSGI 어플리케이션을 사용하는 방법에 대한 서버 문서를 참조하라. 11 | 단지 :class:`Flask` 어플리케이션 객체가 실제 WSGI 어플리케이션임을 기억하라. 12 | 13 | 빠르게 배포하고 실행하기 위한 옵션을 보려면, 퀵스타트의 :ref:`quickstart_deployment` 를 참조하라. 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | mod_wsgi 19 | wsgi-standalone 20 | uwsgi 21 | fastcgi 22 | cgi 23 | -------------------------------------------------------------------------------- /docs/deploying/uwsgi.rst: -------------------------------------------------------------------------------- 1 | .. _deploying-uwsgi: 2 | 3 | uWSGI 4 | ===== 5 | 6 | uWSGI는 `nginx`_, `lighttpd`_, `cherokee`_ 와 같은 서버에서 사용할 수 있는 배포 옵션이다; 7 | 다른 옵션을 보려면 :ref:`deploying-fastcgi` 와 :ref:`deploying-wsgi-standalone` 를 확인하라. 8 | uWSGI 프로토토콜로 WSGI 어플리케이션을 사용하기 위해서는 먼저 uWSGI 서버가 필요하다. uWSGI는프로토콜이면서 어플리케이션 서버이다; 9 | 어플리케이션서버는 uWSGI, FastCGI, HTTP 프로토콜을 서비스할 수 있다. 10 | 11 | 가장 인기있는 uWSGI 서버는 `uwsgi`_이며, 12 | 설명을 위해 사용할 것이다. 아래와 같이 설치되어 있는지 확인하라. 13 | 14 | .. admonition:: 주의 15 | 16 | 어플리케이션 파일에서 있을 수 있는 ``app.run()`` 호출이 ``if __name__ == '__main__':`` 블럭안에 있는지 17 | 아니면 다른 파일로 분리되어 있는지 미리 확인해야 한다. 이것은 만약 우리가 어플리케이션을 uWSGI로 배포한다면 18 | 원하지 않게 로컬 WSGI 서버를 항상 실행하기 때문에 호출되지 않음을 확인해야 한다. 19 | 20 | uwsgi로 app 시작하기 21 | -------------------- 22 | 23 | `uwsgi`는 파이썬 모듈에 있는 WSGI callables에서 운영하기 위해 설계되어 있다. 24 | 25 | myapp.py에 flask application이 있다면 아래와 같이 사용하라: 26 | 27 | .. sourcecode:: text 28 | 29 | $ uwsgi -s /tmp/uwsgi.sock --module myapp --callable app 30 | 31 | 또는 아래와 같은 방법도 사용할 수 있다: 32 | 33 | .. sourcecode:: text 34 | 35 | $ uwsgi -s /tmp/uwsgi.sock -w myapp:app 36 | 37 | nginx 설정하기 38 | -------------- 39 | 40 | nginx를 위한 기본적인 flask uWSGI 설정은 아래와 같다:: 41 | 42 | location = /yourapplication { rewrite ^ /yourapplication/; } 43 | location /yourapplication { try_files $uri @yourapplication; } 44 | location @yourapplication { 45 | include uwsgi_params; 46 | uwsgi_param SCRIPT_NAME /yourapplication; 47 | uwsgi_modifier1 30; 48 | uwsgi_pass unix:/tmp/uwsgi.sock; 49 | } 50 | 51 | 이 설정은 어플리케이션을 `/yourapplication`에 바인드한다. 52 | URL 루트에 어플리케이션을 두길 원한다면, WSGI `SCRIPT_NAME`를 알려줄 필요가 없거나 53 | uwsgi modifier를 설정할 필요가 없기 때문에 조금 더 간단하다:: 54 | 55 | This configuration binds the application to `/yourapplication`. If you want 56 | to have it in the URL root it's a bit simpler because you don't have to tell 57 | it the WSGI `SCRIPT_NAME` or set the uwsgi modifier to make use of it:: 58 | 59 | location / { try_files $uri @yourapplication; } 60 | location @yourapplication { 61 | include uwsgi_params; 62 | uwsgi_pass unix:/tmp/uwsgi.sock; 63 | } 64 | 65 | .. _nginx: http://nginx.org/ 66 | .. _lighttpd: http://www.lighttpd.net/ 67 | .. _cherokee: http://www.cherokee-project.com/ 68 | .. _uwsgi: http://projects.unbit.it/uwsgi/ 69 | -------------------------------------------------------------------------------- /docs/en/_static/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/debugger.png -------------------------------------------------------------------------------- /docs/en/_static/flask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/flask.png -------------------------------------------------------------------------------- /docs/en/_static/flaskr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/flaskr.png -------------------------------------------------------------------------------- /docs/en/_static/logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/logo-full.png -------------------------------------------------------------------------------- /docs/en/_static/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/no.png -------------------------------------------------------------------------------- /docs/en/_static/touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/touch-icon.png -------------------------------------------------------------------------------- /docs/en/_static/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/_static/yes.png -------------------------------------------------------------------------------- /docs/en/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

About Flask

2 |

3 | Flask is a micro webdevelopment framework for Python. You are currently 4 | looking at the documentation of the development version. 5 |

6 |

Other Formats

7 |

8 | You can download the documentation in other formats as well: 9 |

10 | 16 |

Useful Links

17 | 23 | -------------------------------------------------------------------------------- /docs/en/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /docs/en/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGES 2 | -------------------------------------------------------------------------------- /docs/en/contents.rst.inc: -------------------------------------------------------------------------------- 1 | User's Guide 2 | ------------ 3 | 4 | This part of the documentation, which is mostly prose, begins with some 5 | background information about Flask, then focuses on step-by-step 6 | instructions for web development with Flask. 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | foreword 12 | advanced_foreword 13 | installation 14 | quickstart 15 | tutorial/index 16 | templating 17 | testing 18 | errorhandling 19 | config 20 | signals 21 | views 22 | appcontext 23 | reqcontext 24 | blueprints 25 | extensions 26 | shell 27 | patterns/index 28 | deploying/index 29 | becomingbig 30 | 31 | API Reference 32 | ------------- 33 | 34 | If you are looking for information on a specific function, class or 35 | method, this part of the documentation is for you. 36 | 37 | .. toctree:: 38 | :maxdepth: 2 39 | 40 | api 41 | 42 | Additional Notes 43 | ---------------- 44 | 45 | Design notes, legal information and changelog are here for the interested. 46 | 47 | .. toctree:: 48 | :maxdepth: 2 49 | 50 | design 51 | htmlfaq 52 | security 53 | unicode 54 | extensiondev 55 | styleguide 56 | python3 57 | upgrading 58 | changelog 59 | license 60 | -------------------------------------------------------------------------------- /docs/en/deploying/cgi.rst: -------------------------------------------------------------------------------- 1 | CGI 2 | === 3 | 4 | If all other deployment methods do not work, CGI will work for sure. 5 | CGI is supported by all major servers but usually has a sub-optimal 6 | performance. 7 | 8 | This is also the way you can use a Flask application on Google's `App 9 | Engine`_, where execution happens in a CGI-like environment. 10 | 11 | .. admonition:: Watch Out 12 | 13 | Please make sure in advance that any ``app.run()`` calls you might 14 | have in your application file are inside an ``if __name__ == 15 | '__main__':`` block or moved to a separate file. Just make sure it's 16 | not called because this will always start a local WSGI server which 17 | we do not want if we deploy that application to CGI / app engine. 18 | 19 | With CGI, you will also have to make sure that your code does not contain 20 | any ``print`` statements, or that ``sys.stdout`` is overridden by something 21 | that doesn't write into the HTTP response. 22 | 23 | Creating a `.cgi` file 24 | ---------------------- 25 | 26 | First you need to create the CGI application file. Let's call it 27 | `yourapplication.cgi`:: 28 | 29 | #!/usr/bin/python 30 | from wsgiref.handlers import CGIHandler 31 | from yourapplication import app 32 | 33 | CGIHandler().run(app) 34 | 35 | Server Setup 36 | ------------ 37 | 38 | Usually there are two ways to configure the server. Either just copy the 39 | `.cgi` into a `cgi-bin` (and use `mod_rewrite` or something similar to 40 | rewrite the URL) or let the server point to the file directly. 41 | 42 | In Apache for example you can put something like this into the config: 43 | 44 | .. sourcecode:: apache 45 | 46 | ScriptAlias /app /path/to/the/application.cgi 47 | 48 | On shared webhosting, though, you might not have access to your Apache config. 49 | In this case, a file called `.htaccess`, sitting in the public directory you want 50 | your app to be available, works too but the `ScriptAlias` directive won't 51 | work in that case: 52 | 53 | .. sourcecode:: apache 54 | 55 | RewriteEngine On 56 | RewriteCond %{REQUEST_FILENAME} !-f # Don't interfere with static files 57 | RewriteRule ^(.*)$ /path/to/the/application.cgi/$1 [L] 58 | 59 | For more information consult the documentation of your webserver. 60 | 61 | .. _App Engine: http://code.google.com/appengine/ 62 | -------------------------------------------------------------------------------- /docs/en/deploying/index.rst: -------------------------------------------------------------------------------- 1 | .. _deployment: 2 | 3 | Deployment Options 4 | ================== 5 | 6 | Depending on what you have available there are multiple ways to run 7 | Flask applications. You can use the builtin server during development, 8 | but you should use a full deployment option for production applications. 9 | (Do not use the builtin development server in production.) Several 10 | options are available and documented here. 11 | 12 | If you have a different WSGI server look up the server documentation 13 | about how to use a WSGI app with it. Just remember that your 14 | :class:`Flask` application object is the actual WSGI application. 15 | 16 | For hosted options to get up and running quickly, see 17 | :ref:`quickstart_deployment` in the Quickstart. 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | 22 | mod_wsgi 23 | wsgi-standalone 24 | uwsgi 25 | fastcgi 26 | cgi 27 | -------------------------------------------------------------------------------- /docs/en/deploying/uwsgi.rst: -------------------------------------------------------------------------------- 1 | .. _deploying-uwsgi: 2 | 3 | uWSGI 4 | ===== 5 | 6 | uWSGI is a deployment option on servers like `nginx`_, `lighttpd`_, and 7 | `cherokee`_; see :ref:`deploying-fastcgi` and :ref:`deploying-wsgi-standalone` 8 | for other options. To use your WSGI application with uWSGI protocol you will 9 | need a uWSGI server first. uWSGI is both a protocol and an application server; 10 | the application server can serve uWSGI, FastCGI, and HTTP protocols. 11 | 12 | The most popular uWSGI server is `uwsgi`_, which we will use for this 13 | guide. Make sure to have it installed to follow along. 14 | 15 | .. admonition:: Watch Out 16 | 17 | Please make sure in advance that any ``app.run()`` calls you might 18 | have in your application file are inside an ``if __name__ == 19 | '__main__':`` block or moved to a separate file. Just make sure it's 20 | not called because this will always start a local WSGI server which 21 | we do not want if we deploy that application to uWSGI. 22 | 23 | Starting your app with uwsgi 24 | ---------------------------- 25 | 26 | `uwsgi` is designed to operate on WSGI callables found in python modules. 27 | 28 | Given a flask application in myapp.py, use the following command: 29 | 30 | .. sourcecode:: text 31 | 32 | $ uwsgi -s /tmp/uwsgi.sock --module myapp --callable app 33 | 34 | Or, if you prefer: 35 | 36 | .. sourcecode:: text 37 | 38 | $ uwsgi -s /tmp/uwsgi.sock -w myapp:app 39 | 40 | Configuring nginx 41 | ----------------- 42 | 43 | A basic flask uWSGI configuration for nginx looks like this:: 44 | 45 | location = /yourapplication { rewrite ^ /yourapplication/; } 46 | location /yourapplication { try_files $uri @yourapplication; } 47 | location @yourapplication { 48 | include uwsgi_params; 49 | uwsgi_param SCRIPT_NAME /yourapplication; 50 | uwsgi_modifier1 30; 51 | uwsgi_pass unix:/tmp/uwsgi.sock; 52 | } 53 | 54 | This configuration binds the application to `/yourapplication`. If you want 55 | to have it in the URL root it's a bit simpler because you don't have to tell 56 | it the WSGI `SCRIPT_NAME` or set the uwsgi modifier to make use of it:: 57 | 58 | location / { try_files $uri @yourapplication; } 59 | location @yourapplication { 60 | include uwsgi_params; 61 | uwsgi_pass unix:/tmp/uwsgi.sock; 62 | } 63 | 64 | .. _nginx: http://nginx.org/ 65 | .. _lighttpd: http://www.lighttpd.net/ 66 | .. _cherokee: http://www.cherokee-project.com/ 67 | .. _uwsgi: http://projects.unbit.it/uwsgi/ 68 | -------------------------------------------------------------------------------- /docs/en/extensions.rst: -------------------------------------------------------------------------------- 1 | Flask Extensions 2 | ================ 3 | 4 | Flask extensions extend the functionality of Flask in various different 5 | ways. For instance they add support for databases and other common tasks. 6 | 7 | Finding Extensions 8 | ------------------ 9 | 10 | Flask extensions are listed on the `Flask Extension Registry`_ and can be 11 | downloaded with ``easy_install`` or ``pip``. If you add a Flask extension 12 | as dependency to your ``requirements.rst`` or ``setup.py`` file they are 13 | usually installed with a simple command or when your application installs. 14 | 15 | Using Extensions 16 | ---------------- 17 | 18 | Extensions typically have documentation that goes along that shows how to 19 | use it. There are no general rules in how extensions are supposed to 20 | behave but they are imported from common locations. If you have an 21 | extension called ``Flask-Foo`` or ``Foo-Flask`` it will be always 22 | importable from ``flask.ext.foo``:: 23 | 24 | from flask.ext import foo 25 | 26 | Flask Before 0.8 27 | ---------------- 28 | 29 | If you are using Flask 0.7 or earlier the :data:`flask.ext` package will not 30 | exist, instead you have to import from ``flaskext.foo`` or ``flask_foo`` 31 | depending on how the extension is distributed. If you want to develop an 32 | application that supports Flask 0.7 or earlier you should still import 33 | from the :data:`flask.ext` package. We provide you with a compatibility 34 | module that provides this package for older versions of Flask. You can 35 | download it from github: `flaskext_compat.py`_ 36 | 37 | And here is how you can use it:: 38 | 39 | import flaskext_compat 40 | flaskext_compat.activate() 41 | 42 | from flask.ext import foo 43 | 44 | Once the ``flaskext_compat`` module is activated the :data:`flask.ext` will 45 | exist and you can start importing from there. 46 | 47 | .. _Flask Extension Registry: http://flask.pocoo.org/extensions/ 48 | .. _flaskext_compat.py: https://github.com/mitsuhiko/flask/raw/master/scripts/flaskext_compat.py 49 | -------------------------------------------------------------------------------- /docs/en/flaskdocext.py: -------------------------------------------------------------------------------- 1 | import re 2 | import inspect 3 | 4 | 5 | _internal_mark_re = re.compile(r'^\s*:internal:\s*$(?m)') 6 | 7 | 8 | def skip_member(app, what, name, obj, skip, options): 9 | docstring = inspect.getdoc(obj) 10 | if skip: 11 | return True 12 | return _internal_mark_re.search(docstring or '') is not None 13 | 14 | 15 | def setup(app): 16 | app.connect('autodoc-skip-member', skip_member) 17 | -------------------------------------------------------------------------------- /docs/en/index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Welcome to Flask 4 | ================ 5 | 6 | .. image:: _static/logo-full.png 7 | :alt: Flask: web development, one drop at a time 8 | :class: floatingflask 9 | 10 | Welcome to Flask's documentation. This documentation is divided into 11 | different parts. I recommend that you get started with 12 | :ref:`installation` and then head over to the :ref:`quickstart`. 13 | Besides the quickstart, there is also a more detailed :ref:`tutorial` that 14 | shows how to create a complete (albeit small) application with Flask. If 15 | you'd rather dive into the internals of Flask, check out 16 | the :ref:`api` documentation. Common patterns are described in the 17 | :ref:`patterns` section. 18 | 19 | Flask depends on two external libraries: the `Jinja2`_ template 20 | engine and the `Werkzeug`_ WSGI toolkit. These libraries are not documented 21 | here. If you want to dive into their documentation, check out the 22 | following links: 23 | 24 | - `Jinja2 Documentation `_ 25 | - `Werkzeug Documentation `_ 26 | 27 | .. _Jinja2: http://jinja.pocoo.org/2/ 28 | .. _Werkzeug: http://werkzeug.pocoo.org/ 29 | 30 | .. include:: contents.rst.inc 31 | -------------------------------------------------------------------------------- /docs/en/latexindex.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Flask Documentation 4 | =================== 5 | 6 | .. include:: contents.rst.inc 7 | -------------------------------------------------------------------------------- /docs/en/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | Flask is licensed under a three clause BSD License. It basically means: 5 | do whatever you want with it as long as the copyright in Flask sticks 6 | around, the conditions are not modified and the disclaimer is present. 7 | Furthermore you must not use the names of the authors to promote derivatives 8 | of the software without written consent. 9 | 10 | The full license text can be found below (:ref:`flask-license`). For the 11 | documentation and artwork different licenses apply. 12 | 13 | .. _authors: 14 | 15 | Authors 16 | ------- 17 | 18 | .. include:: ../AUTHORS 19 | 20 | General License Definitions 21 | --------------------------- 22 | 23 | The following section contains the full license texts for Flask and the 24 | documentation. 25 | 26 | - "AUTHORS" hereby refers to all the authors listed in the 27 | :ref:`authors` section. 28 | 29 | - The ":ref:`flask-license`" applies to all the sourcecode shipped as 30 | part of Flask (Flask itself as well as the examples and the unittests) 31 | as well as documentation. 32 | 33 | - The ":ref:`artwork-license`" applies to the project's Horn-Logo. 34 | 35 | .. _flask-license: 36 | 37 | Flask License 38 | ------------- 39 | 40 | .. include:: ../LICENSE 41 | 42 | 43 | .. _artwork-license: 44 | 45 | Flask Artwork License 46 | --------------------- 47 | 48 | .. include:: ../artwork/LICENSE 49 | -------------------------------------------------------------------------------- /docs/en/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/en/logo.pdf -------------------------------------------------------------------------------- /docs/en/patterns/caching.rst: -------------------------------------------------------------------------------- 1 | .. _caching-pattern: 2 | 3 | Caching 4 | ======= 5 | 6 | When your application runs slow, throw some caches in. Well, at least 7 | it's the easiest way to speed up things. What does a cache do? Say you 8 | have a function that takes some time to complete but the results would 9 | still be good enough if they were 5 minutes old. So then the idea is that 10 | you actually put the result of that calculation into a cache for some 11 | time. 12 | 13 | Flask itself does not provide caching for you, but Werkzeug, one of the 14 | libraries it is based on, has some very basic cache support. It supports 15 | multiple cache backends, normally you want to use a memcached server. 16 | 17 | Setting up a Cache 18 | ------------------ 19 | 20 | You create a cache object once and keep it around, similar to how 21 | :class:`~flask.Flask` objects are created. If you are using the 22 | development server you can create a 23 | :class:`~werkzeug.contrib.cache.SimpleCache` object, that one is a simple 24 | cache that keeps the item stored in the memory of the Python interpreter:: 25 | 26 | from werkzeug.contrib.cache import SimpleCache 27 | cache = SimpleCache() 28 | 29 | If you want to use memcached, make sure to have one of the memcache modules 30 | supported (you get them from `PyPI `_) and a 31 | memcached server running somewhere. This is how you connect to such an 32 | memcached server then:: 33 | 34 | from werkzeug.contrib.cache import MemcachedCache 35 | cache = MemcachedCache(['127.0.0.1:11211']) 36 | 37 | If you are using App Engine, you can connect to the App Engine memcache 38 | server easily:: 39 | 40 | from werkzeug.contrib.cache import GAEMemcachedCache 41 | cache = GAEMemcachedCache() 42 | 43 | Using a Cache 44 | ------------- 45 | 46 | Now how can one use such a cache? There are two very important 47 | operations: :meth:`~werkzeug.contrib.cache.BaseCache.get` and 48 | :meth:`~werkzeug.contrib.cache.BaseCache.set`. This is how to use them: 49 | 50 | To get an item from the cache call 51 | :meth:`~werkzeug.contrib.cache.BaseCache.get` with a string as key name. 52 | If something is in the cache, it is returned. Otherwise that function 53 | will return `None`:: 54 | 55 | rv = cache.get('my-item') 56 | 57 | To add items to the cache, use the :meth:`~werkzeug.contrib.cache.BaseCache.set` 58 | method instead. The first argument is the key and the second the value 59 | that should be set. Also a timeout can be provided after which the cache 60 | will automatically remove item. 61 | 62 | Here a full example how this looks like normally:: 63 | 64 | def get_my_item(): 65 | rv = cache.get('my-item') 66 | if rv is None: 67 | rv = calculate_value() 68 | cache.set('my-item', rv, timeout=5 * 60) 69 | return rv 70 | -------------------------------------------------------------------------------- /docs/en/patterns/deferredcallbacks.rst: -------------------------------------------------------------------------------- 1 | .. _deferred-callbacks: 2 | 3 | Deferred Request Callbacks 4 | ========================== 5 | 6 | One of the design principles of Flask is that response objects are created 7 | and passed down a chain of potential callbacks that can modify them or 8 | replace them. When the request handling starts, there is no response 9 | object yet. It is created as necessary either by a view function or by 10 | some other component in the system. 11 | 12 | But what happens if you want to modify the response at a point where the 13 | response does not exist yet? A common example for that would be a 14 | before-request function that wants to set a cookie on the response object. 15 | 16 | One way is to avoid the situation. Very often that is possible. For 17 | instance you can try to move that logic into an after-request callback 18 | instead. Sometimes however moving that code there is just not a very 19 | pleasant experience or makes code look very awkward. 20 | 21 | As an alternative possibility you can attach a bunch of callback functions 22 | to the :data:`~flask.g` object and call them at the end of the request. 23 | This way you can defer code execution from anywhere in the application. 24 | 25 | 26 | The Decorator 27 | ------------- 28 | 29 | The following decorator is the key. It registers a function on a list on 30 | the :data:`~flask.g` object:: 31 | 32 | from flask import g 33 | 34 | def after_this_request(f): 35 | if not hasattr(g, 'after_request_callbacks'): 36 | g.after_request_callbacks = [] 37 | g.after_request_callbacks.append(f) 38 | return f 39 | 40 | 41 | Calling the Deferred 42 | -------------------- 43 | 44 | Now you can use the `after_this_request` decorator to mark a function to 45 | be called at the end of the request. But we still need to call them. For 46 | this the following function needs to be registered as 47 | :meth:`~flask.Flask.after_request` callback:: 48 | 49 | @app.after_request 50 | def call_after_request_callbacks(response): 51 | for callback in getattr(g, 'after_request_callbacks', ()): 52 | callback(response) 53 | return response 54 | 55 | 56 | A Practical Example 57 | ------------------- 58 | 59 | Now we can easily at any point in time register a function to be called at 60 | the end of this particular request. For example you can remember the 61 | current language of the user in a cookie in the before-request function:: 62 | 63 | from flask import request 64 | 65 | @app.before_request 66 | def detect_user_language(): 67 | language = request.cookies.get('user_lang') 68 | if language is None: 69 | language = guess_language_from_request() 70 | @after_this_request 71 | def remember_language(response): 72 | response.set_cookie('user_lang', language) 73 | g.language = language 74 | -------------------------------------------------------------------------------- /docs/en/patterns/favicon.rst: -------------------------------------------------------------------------------- 1 | Adding a favicon 2 | ================ 3 | 4 | A "favicon" is an icon used by browsers for tabs and bookmarks. This helps 5 | to distinguish your website and to give it a unique brand. 6 | 7 | A common question is how to add a favicon to a flask application. First, of 8 | course, you need an icon. It should be 16 × 16 pixels and in the ICO file 9 | format. This is not a requirement but a de-facto standard supported by all 10 | relevant browsers. Put the icon in your static directory as 11 | :file:`favicon.ico`. 12 | 13 | Now, to get browsers to find your icon, the correct way is to add a link 14 | tag in your HTML. So, for example: 15 | 16 | .. sourcecode:: html+jinja 17 | 18 | 19 | 20 | That's all you need for most browsers, however some really old ones do not 21 | support this standard. The old de-facto standard is to serve this file, 22 | with this name, at the website root. If your application is not mounted at 23 | the root path of the domain you either need to configure the webserver to 24 | serve the icon at the root or if you can't do that you're out of luck. If 25 | however your application is the root you can simply route a redirect:: 26 | 27 | app.add_url_rule('/favicon.ico', 28 | redirect_to=url_for('static', filename='favicon.ico')) 29 | 30 | If you want to save the extra redirect request you can also write a view 31 | using :func:`~flask.send_from_directory`:: 32 | 33 | import os 34 | from flask import send_from_directory 35 | 36 | @app.route('/favicon.ico') 37 | def favicon(): 38 | return send_from_directory(os.path.join(app.root_path, 'static'), 39 | 'favicon.ico', mimetype='image/vnd.microsoft.icon') 40 | 41 | We can leave out the explicit mimetype and it will be guessed, but we may 42 | as well specify it to avoid the extra guessing, as it will always be the 43 | same. 44 | 45 | The above will serve the icon via your application and if possible it's 46 | better to configure your dedicated web server to serve it; refer to the 47 | webserver's documentation. 48 | 49 | See also 50 | -------- 51 | 52 | * The `Favicon `_ article on 53 | Wikipedia 54 | -------------------------------------------------------------------------------- /docs/en/patterns/index.rst: -------------------------------------------------------------------------------- 1 | .. _patterns: 2 | 3 | Patterns for Flask 4 | ================== 5 | 6 | Certain things are common enough that the chances are high you will find 7 | them in most web applications. For example quite a lot of applications 8 | are using relational databases and user authentication. In that case, 9 | chances are they will open a database connection at the beginning of the 10 | request and get the information of the currently logged in user. At the 11 | end of the request, the database connection is closed again. 12 | 13 | There are more user contributed snippets and patterns in the `Flask 14 | Snippet Archives `_. 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | packages 20 | appfactories 21 | appdispatch 22 | apierrors 23 | urlprocessors 24 | distribute 25 | fabric 26 | sqlite3 27 | sqlalchemy 28 | fileuploads 29 | caching 30 | viewdecorators 31 | wtforms 32 | templateinheritance 33 | flashing 34 | jquery 35 | errorpages 36 | lazyloading 37 | mongokit 38 | favicon 39 | streaming 40 | deferredcallbacks 41 | methodoverrides 42 | requestchecksum 43 | celery 44 | -------------------------------------------------------------------------------- /docs/en/patterns/methodoverrides.rst: -------------------------------------------------------------------------------- 1 | Adding HTTP Method Overrides 2 | ============================ 3 | 4 | Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP 5 | methods (such as PATCH). In that case it's possible to “proxy” HTTP 6 | methods through another HTTP method in total violation of the protocol. 7 | 8 | The way this works is by letting the client do an HTTP POST request and 9 | set the ``X-HTTP-Method-Override`` header and set the value to the 10 | intended HTTP method (such as ``PATCH``). 11 | 12 | This can easily be accomplished with an HTTP middleware:: 13 | 14 | class HTTPMethodOverrideMiddleware(object): 15 | allowed_methods = frozenset([ 16 | 'GET', 17 | 'HEAD', 18 | 'POST', 19 | 'DELETE', 20 | 'PUT', 21 | 'PATCH', 22 | 'OPTIONS' 23 | ]) 24 | bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE']) 25 | 26 | def __init__(self, app): 27 | self.app = app 28 | 29 | def __call__(self, environ, start_response): 30 | method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper() 31 | if method in self.allowed_methods: 32 | method = method.encode('ascii', 'replace') 33 | environ['REQUEST_METHOD'] = method 34 | if method in self.bodyless_methods: 35 | environ['CONTENT_LENGTH'] = '0' 36 | return self.app(environ, start_response) 37 | 38 | To use this with Flask this is all that is necessary:: 39 | 40 | from flask import Flask 41 | 42 | app = Flask(__name__) 43 | app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app) 44 | -------------------------------------------------------------------------------- /docs/en/patterns/requestchecksum.rst: -------------------------------------------------------------------------------- 1 | Request Content Checksums 2 | ========================= 3 | 4 | Various pieces of code can consume the request data and preprocess it. 5 | For instance JSON data ends up on the request object already read and 6 | processed, form data ends up there as well but goes through a different 7 | code path. This seems inconvenient when you want to calculate the 8 | checksum of the incoming request data. This is necessary sometimes for 9 | some APIs. 10 | 11 | Fortunately this is however very simple to change by wrapping the input 12 | stream. 13 | 14 | The following example calculates the SHA1 checksum of the incoming data as 15 | it gets read and stores it in the WSGI environment:: 16 | 17 | import hashlib 18 | 19 | class ChecksumCalcStream(object): 20 | 21 | def __init__(self, stream): 22 | self._stream = stream 23 | self._hash = hashlib.sha1() 24 | 25 | def read(self, bytes): 26 | rv = self._stream.read(bytes) 27 | self._hash.update(rv) 28 | return rv 29 | 30 | def readline(self, size_hint): 31 | rv = self._stream.readline(size_hint) 32 | self._hash.update(rv) 33 | return rv 34 | 35 | def generate_checksum(request): 36 | env = request.environ 37 | stream = ChecksumCalcStream(env['wsgi.input']) 38 | env['wsgi.input'] = stream 39 | return stream._hash 40 | 41 | To use this, all you need to do is to hook the calculating stream in 42 | before the request starts consuming data. (Eg: be careful accessing 43 | ``request.form`` or anything of that nature. ``before_request_handlers`` 44 | for instance should be careful not to access it). 45 | 46 | Example usage:: 47 | 48 | @app.route('/special-api', methods=['POST']) 49 | def special_api(): 50 | hash = generate_checksum(request) 51 | # Accessing this parses the input stream 52 | files = request.files 53 | # At this point the hash is fully constructed. 54 | checksum = hash.hexdigest() 55 | return 'Hash was: %s' % checksum 56 | -------------------------------------------------------------------------------- /docs/en/patterns/templateinheritance.rst: -------------------------------------------------------------------------------- 1 | .. _template-inheritance: 2 | 3 | Template Inheritance 4 | ==================== 5 | 6 | The most powerful part of Jinja is template inheritance. Template inheritance 7 | allows you to build a base "skeleton" template that contains all the common 8 | elements of your site and defines **blocks** that child templates can override. 9 | 10 | Sounds complicated but is very basic. It's easiest to understand it by starting 11 | with an example. 12 | 13 | 14 | Base Template 15 | ------------- 16 | 17 | This template, which we'll call ``layout.html``, defines a simple HTML skeleton 18 | document that you might use for a simple two-column page. It's the job of 19 | "child" templates to fill the empty blocks with content: 20 | 21 | .. sourcecode:: html+jinja 22 | 23 | 24 | 25 | 26 | {% block head %} 27 | 28 | {% block title %}{% endblock %} - My Webpage 29 | {% endblock %} 30 | 31 | 32 |
{% block content %}{% endblock %}
33 | 38 | 39 | 40 | 41 | In this example, the ``{% block %}`` tags define four blocks that child templates 42 | can fill in. All the `block` tag does is tell the template engine that a 43 | child template may override those portions of the template. 44 | 45 | Child Template 46 | -------------- 47 | 48 | A child template might look like this: 49 | 50 | .. sourcecode:: html+jinja 51 | 52 | {% extends "layout.html" %} 53 | {% block title %}Index{% endblock %} 54 | {% block head %} 55 | {{ super() }} 56 | 59 | {% endblock %} 60 | {% block content %} 61 |

Index

62 |

63 | Welcome on my awesome homepage. 64 | {% endblock %} 65 | 66 | The ``{% extends %}`` tag is the key here. It tells the template engine that 67 | this template "extends" another template. When the template system evaluates 68 | this template, first it locates the parent. The extends tag must be the 69 | first tag in the template. To render the contents of a block defined in 70 | the parent template, use ``{{ super() }}``. 71 | -------------------------------------------------------------------------------- /docs/en/tutorial/css.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-css: 2 | 3 | Step 7: Adding Style 4 | ==================== 5 | 6 | Now that everything else works, it's time to add some style to the 7 | application. Just create a stylesheet called `style.css` in the `static` 8 | folder we created before: 9 | 10 | .. sourcecode:: css 11 | 12 | body { font-family: sans-serif; background: #eee; } 13 | a, h1, h2 { color: #377ba8; } 14 | h1, h2 { font-family: 'Georgia', serif; margin: 0; } 15 | h1 { border-bottom: 2px solid #eee; } 16 | h2 { font-size: 1.2em; } 17 | 18 | .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; 19 | padding: 0.8em; background: white; } 20 | .entries { list-style: none; margin: 0; padding: 0; } 21 | .entries li { margin: 0.8em 1.2em; } 22 | .entries li h2 { margin-left: -1em; } 23 | .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } 24 | .add-entry dl { font-weight: bold; } 25 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 26 | margin-bottom: 1em; background: #fafafa; } 27 | .flash { background: #cee5F5; padding: 0.5em; 28 | border: 1px solid #aacbe2; } 29 | .error { background: #f0d6d6; padding: 0.5em; } 30 | 31 | Continue with :ref:`tutorial-testing`. 32 | -------------------------------------------------------------------------------- /docs/en/tutorial/dbinit.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-dbinit: 2 | 3 | Step 3: Creating The Database 4 | ============================= 5 | 6 | Flaskr is a database powered application as outlined earlier, and more 7 | precisely, an application powered by a relational database system. Such 8 | systems need a schema that tells them how to store that information. So 9 | before starting the server for the first time it's important to create 10 | that schema. 11 | 12 | Such a schema can be created by piping the `schema.sql` file into the 13 | `sqlite3` command as follows:: 14 | 15 | sqlite3 /tmp/flaskr.db < schema.sql 16 | 17 | The downside of this is that it requires the sqlite3 command to be 18 | installed which is not necessarily the case on every system. Also one has 19 | to provide the path to the database there which leaves some place for 20 | errors. It's a good idea to add a function that initializes the database 21 | for you to the application. 22 | 23 | If you want to do that, you first have to import the 24 | :func:`contextlib.closing` function from the contextlib package. 25 | Accordingly, add the following lines to your existing imports in `flaskr.py`:: 26 | 27 | from contextlib import closing 28 | 29 | Next we can create a function called `init_db` that initializes the 30 | database. For this we can use the `connect_db` function we defined 31 | earlier. Just add that function below the `connect_db` function in 32 | `flaskr.py`:: 33 | 34 | def init_db(): 35 | with closing(connect_db()) as db: 36 | with app.open_resource('schema.sql', mode='r') as f: 37 | db.cursor().executescript(f.read()) 38 | db.commit() 39 | 40 | The :func:`~contextlib.closing` helper function allows us to keep a 41 | connection open for the duration of the `with` block. The 42 | :func:`~flask.Flask.open_resource` method of the application object 43 | supports that functionality out of the box, so it can be used in the 44 | `with` block directly. This function opens a file from the resource 45 | location (your `flaskr` folder) and allows you to read from it. We are 46 | using this here to execute a script on the database connection. 47 | 48 | When we connect to a database we get a connection object (here called 49 | `db`) that can give us a cursor. On that cursor there is a method to 50 | execute a complete script. Finally we only have to commit the changes. 51 | SQLite 3 and other transactional databases will not commit unless you 52 | explicitly tell it to. 53 | 54 | Now it is possible to create a database by starting up a Python shell and 55 | importing and calling that function:: 56 | 57 | >>> from flaskr import init_db 58 | >>> init_db() 59 | 60 | .. admonition:: Troubleshooting 61 | 62 | If you get an exception later that a table cannot be found check that 63 | you did call the `init_db` function and that your table names are 64 | correct (singular vs. plural for example). 65 | 66 | Continue with :ref:`tutorial-dbcon` 67 | -------------------------------------------------------------------------------- /docs/en/tutorial/folders.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-folders: 2 | 3 | Step 0: Creating The Folders 4 | ============================ 5 | 6 | Before we get started, let's create the folders needed for this 7 | application:: 8 | 9 | /flaskr 10 | /static 11 | /templates 12 | 13 | The `flaskr` folder is not a python package, but just something where we 14 | drop our files. Directly into this folder we will then put our database 15 | schema as well as main module in the following steps. The files inside 16 | the `static` folder are available to users of the application via `HTTP`. 17 | This is the place where css and javascript files go. Inside the 18 | `templates` folder Flask will look for `Jinja2`_ templates. The 19 | templates you create later in the tutorial will go in this directory. 20 | 21 | Continue with :ref:`tutorial-schema`. 22 | 23 | .. _Jinja2: http://jinja.pocoo.org/2/ 24 | -------------------------------------------------------------------------------- /docs/en/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial: 2 | 3 | Tutorial 4 | ======== 5 | 6 | You want to develop an application with Python and Flask? Here you have 7 | the chance to learn that by example. In this tutorial we will create a 8 | simple microblog application. It only supports one user that can create 9 | text-only entries and there are no feeds or comments, but it still 10 | features everything you need to get started. We will use Flask and SQLite 11 | as database which comes out of the box with Python, so there is nothing 12 | else you need. 13 | 14 | If you want the full sourcecode in advance or for comparison, check out 15 | the `example source`_. 16 | 17 | .. _example source: 18 | http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ 19 | 20 | .. toctree:: 21 | :maxdepth: 2 22 | 23 | introduction 24 | folders 25 | schema 26 | setup 27 | dbinit 28 | dbcon 29 | views 30 | templates 31 | css 32 | testing 33 | -------------------------------------------------------------------------------- /docs/en/tutorial/introduction.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-introduction: 2 | 3 | Introducing Flaskr 4 | ================== 5 | 6 | We will call our blogging application flaskr here, feel free to choose a 7 | less web-2.0-ish name ;) Basically we want it to do the following things: 8 | 9 | 1. let the user sign in and out with credentials specified in the 10 | configuration. Only one user is supported. 11 | 2. when the user is logged in they can add new entries to the page 12 | consisting of a text-only title and some HTML for the text. This HTML 13 | is not sanitized because we trust the user here. 14 | 3. the page shows all entries so far in reverse order (newest on top) and 15 | the user can add new ones from there if logged in. 16 | 17 | We will be using SQLite3 directly for that application because it's good 18 | enough for an application of that size. For larger applications however 19 | it makes a lot of sense to use `SQLAlchemy`_ that handles database 20 | connections in a more intelligent way, allows you to target different 21 | relational databases at once and more. You might also want to consider 22 | one of the popular NoSQL databases if your data is more suited for those. 23 | 24 | Here a screenshot from the final application: 25 | 26 | .. image:: ../_static/flaskr.png 27 | :align: center 28 | :class: screenshot 29 | :alt: screenshot of the final application 30 | 31 | Continue with :ref:`tutorial-folders`. 32 | 33 | .. _SQLAlchemy: http://www.sqlalchemy.org/ 34 | -------------------------------------------------------------------------------- /docs/en/tutorial/schema.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-schema: 2 | 3 | Step 1: Database Schema 4 | ======================= 5 | 6 | First we want to create the database schema. For this application only a 7 | single table is needed and we only want to support SQLite so that is quite 8 | easy. Just put the following contents into a file named `schema.sql` in 9 | the just created `flaskr` folder: 10 | 11 | .. sourcecode:: sql 12 | 13 | drop table if exists entries; 14 | create table entries ( 15 | id integer primary key autoincrement, 16 | title text not null, 17 | text text not null 18 | ); 19 | 20 | This schema consists of a single table called `entries` and each row in 21 | this table has an `id`, a `title` and a `text`. The `id` is an 22 | automatically incrementing integer and a primary key, the other two are 23 | strings that must not be null. 24 | 25 | Continue with :ref:`tutorial-setup`. 26 | -------------------------------------------------------------------------------- /docs/en/tutorial/testing.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-testing: 2 | 3 | Bonus: Testing the Application 4 | ============================== 5 | 6 | Now that you have finished the application and everything works as 7 | expected, it's probably not a bad idea to add automated tests to simplify 8 | modifications in the future. The application above is used as a basic 9 | example of how to perform unittesting in the :ref:`testing` section of the 10 | documentation. Go there to see how easy it is to test Flask applications. 11 | -------------------------------------------------------------------------------- /docs/extensions.rst: -------------------------------------------------------------------------------- 1 | Flask 확장기능 2 | ================ 3 | Flask 확장기능(extensions)은 서로 다른 다양한 방법으로 Flask 의 기능을 추가 시킬 수 있게 해준다. 4 | 예를 들어 확장기능을 이용하여 데이터베이스 그리고 다른 일반적인 태스크들을 지원할 수 있다. 5 | 6 | 7 | 확장기능 찾아내기 8 | ------------------ 9 | 10 | 플라스크 확장기능들의 목록은 `Flask Extension Registry`_ 에서 살펴볼 수 있다. 11 | 그리고 ``easy_install`` 혹은 ``pip`` 를 통해 다운로드 할 수 있다. 12 | 만약 여러분이 Flask 확장기능을 추가하면, ``requirements.rst`` 혹은 ``setup.py`` 에 명시된 13 | 파일 의존관계로부터 간단한 명령어의 실행이나 응용 프로그램 설치와 함께 설치될 수 있다. 14 | 15 | 16 | 확장기능 사용하기 17 | ---------------- 18 | 19 | 확장기능은 일반적으로 해당 기능을 사용하는 방법을 보여주는 문서를 가지고 있다. 20 | 이 확장기능의 작동 방식에 대한 일반적인 규칙은 없지만, 확장기능은 공통된 위치에서 21 | 가져오게 된다. 만약 여러분이 ``Flask-Foo`` 혹은 ``Foo-Flask`` 라는 확장기능을 22 | 호출 하였다면, 그것은 항상 ``flask.ext.foo`` 을 통해서 가져오게 될 것이다 :: 23 | 24 | from flask.ext import foo 25 | 26 | 27 | Flask 0.8 이전버전의 경우 28 | ---------------- 29 | 30 | 31 | 만약 여러분의 Flask가 0.7 버전 혹은 그 이전의 것이라면 :data:`flask.ext` 패키지가 32 | 존재하지 않는다. 대신에 여러분은 ``flaskext.foo`` 혹은 ``flask_foo`` 등의 형식으로 33 | 확장기능이 배포되는 방식에 따라 불러와야만 한다. 만약 여러분이 여전히 Flask 0.7 혹은 이전 34 | 이전 버전을 지원하는 어플리케이션을 개발하기 원한다면, 여러분은 여전히 :data:`flask.ext` 35 | 패키지를 불러와야만 한다. 우리는 Flask 의 이전 버전의 Flask를 위한 호환성 모듈을 제공하고 있다. 36 | 여러분은 github을 통해서 : `flaskext_compat.py`_ 를 다운로드 받을 수 있다. 37 | 38 | 그리고 여기에서 호환성 모듈의 사용 방법을 볼 수 있다:: 39 | 40 | 41 | import flaskext_compat 42 | flaskext_compat.activate() 43 | 44 | from flask.ext import foo 45 | 46 | 47 | 48 | ``flaskext_compat`` 모듈이 활성화 되면 :data:`flask.ext` 가 존재하게 되고 49 | 여러분은 이것을 통해 여기서부터 불러오기를 시작 할 수 있다. 50 | 51 | 52 | .. _Flask Extension Registry: http://flask.pocoo.org/extensions/ 53 | .. _flaskext_compat.py: https://github.com/mitsuhiko/flask/raw/master/scripts/flaskext_compat.py 54 | -------------------------------------------------------------------------------- /docs/flaskdocext.py: -------------------------------------------------------------------------------- 1 | import re 2 | import inspect 3 | 4 | 5 | _internal_mark_re = re.compile(r'^\s*:internal:\s*$(?m)') 6 | 7 | 8 | def skip_member(app, what, name, obj, skip, options): 9 | docstring = inspect.getdoc(obj) 10 | if skip: 11 | return True 12 | return _internal_mark_re.search(docstring or '') is not None 13 | 14 | 15 | def setup(app): 16 | app.connect('autodoc-skip-member', skip_member) 17 | -------------------------------------------------------------------------------- /docs/foreword.rst: -------------------------------------------------------------------------------- 1 | 머리말 2 | ======== 3 | 4 | Flask를 시작하기 전에 먼저 이글을 읽어주시기 바랍니다. 이 글이 여러분의 프로젝트에서 이것을 사용하여야 하거나 사용하지 말아야 할때에 해당 목적과 의도에 대한 일부 질문들에 대한 답변이 될 수 있기를 희망합니다. 5 | 6 | 7 | "마이크로(Micro)"는 무엇을 뜻하는가? 8 | ----------------------- 9 | 10 | “마이크로”는 여러분의 웹 어플리케이션이 하나의 파이썬 파일으로 개발되야한다는 걸 말하는게 아니다.(그렇게 해석될 수 도 있겠지만…) 또한, 기능적으로 부족하다는걸 의미하지도 않는다. 마이크로 프레임워크(Microframework)에서의 “마이크로”는 핵심기능만 간결하게 유지하지만, 확장가능한 것을 목적으로 한다. Flask는 여러분을 위해 데이타베이스를 선택해주지 않는다. Flask에서 제공하는 템플릿 엔진을 변경하는것은 쉽다. 그밖에 모든것은 여러분에게 달려있고, 그래서 Flask는 여러분이 필요한 모든것일 수 있고, 필요없는것은 하나도 없을것이다. 11 | 12 | 13 | 설정과 관례 14 | ----------------------------- 15 | 16 | Flask로 시작할때, 여러분은 잘 정의된 기본값이 있는 많은 설정값들과 몇가지 관례를 볼 수 있다. 템플릿과 정적파일은 어플리케이션의 파이썬 소스 디렉토리의 하위 디렉토리에 templates과 statics에 저장된다. 이 방식은 변경할 수 있지만, 처음부터 반드시 그럴 필요는 없다. 17 | 18 | 19 | Flask를 이용하여 성장시키기 20 | -------------------------- 21 | 22 | 여러분이 Flask를 가지고 개발할때, 운영을 위해 여러분의 프로젝트와 통합할 여러 종류의 확장을 찾게된다. Flask 핵심 개발팀은 많은 확장을 검토했고 그것들이 앞으로의 배포판과 어긋나지 않는다는것을 보증한다. 23 | 24 | 여러분의 코드의 규모가 점점 커지면서, 여러분의 프로젝트에 설계에 적합한 선택을 할 기회가 온다 Flask는 계속적으로 파이썬이 제공하는 최고의 모듈에 간결한 연결층을 제공할 것이다. 여러분은 SQLAlchemy이나 다른 디비툴 또는 알맞게 비관계형 데이타 저장소로 고급 패턴을 만들수도 있고 파이썬 웹 인터페이스인 WSGI를 위한 프레임웍에 관계없이 사용할 수 있는 툴을 이용할 수 있다. 25 | 26 | Flask는 프레임웍의 기능을 변경하기 위한 많은 훅(hook)을 포함한다. 그것보다 더 많이 변경하고 싶다면 Flask class 자체를 상속하면 된다. 여러분이 subclassing에 관심이 있다면 :ref:`becomingbig` 챕터를 확인한다. 디자인 패턴이 궁금하다면 :ref:`design` 에 대한 섹션으로 넘어가라. 27 | 28 | 29 | 계속하기 :ref:`installation`, :ref:`quickstart`, 혹은 :ref:`advanced_foreword`. 30 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Flask의 세계에 오신것을 환영합니다. 4 | ================ 5 | 6 | .. image:: _static/logo-full.png 7 | :alt: Flask: web development, one drop at a time 8 | :class: floatingflask 9 | 10 | Flask 문서에 오신것을 환영합니다. 이 문서는 다양한 파트로 나누어져 있습니다. 11 | 저자는 :ref:`installation` 와 :ref:`quickstart` 를 먼저 보실것을 추천합니다. 12 | :ref:`quickstart` 뿐만아니라, 어떻게 Flask 어플리케이션을 만들 수 있는지 좀 더 상세하게 다루는 :ref:`tutorial` 또한 볼 수 있습니다. 13 | 14 | 만약 여러분이 오히려 Flask의 내부로 직접 뛰어 들고 싶은 경우라면, 15 | :ref:`api` 문서를 확인하십시오. 일반적으로 사용되는 패턴들은 16 | :ref:`patterns` 섹션을 확인하면 됩니다.. 17 | 18 | Flask는 두개의 외부 라이브러리에 의존합니다.: 바로 `Jinja2`_ 템플릿엔진과 `Werkzeug`_ WSGI 툴킷입니다. 이 라이브러리들은 이 문서에서 다루지않습니다. 19 | 만약 여러분이 이 라이브러리들에 대해서 깊이 알고 싶다면 다음의 링크를 확인하십시오. 20 | 21 | 22 | - `Jinja2 Documentation `_ 23 | - `Werkzeug Documentation `_ 24 | 25 | .. _Jinja2: http://jinja.pocoo.org/2/ 26 | .. _Werkzeug: http://werkzeug.pocoo.org/ 27 | 28 | .. include:: contents.rst.inc 29 | -------------------------------------------------------------------------------- /docs/ko/_static/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/debugger.png -------------------------------------------------------------------------------- /docs/ko/_static/flask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/flask.png -------------------------------------------------------------------------------- /docs/ko/_static/flaskr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/flaskr.png -------------------------------------------------------------------------------- /docs/ko/_static/logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/logo-full.png -------------------------------------------------------------------------------- /docs/ko/_static/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/no.png -------------------------------------------------------------------------------- /docs/ko/_static/touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/touch-icon.png -------------------------------------------------------------------------------- /docs/ko/_static/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/_static/yes.png -------------------------------------------------------------------------------- /docs/ko/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

About Flask

2 |

3 | Flask는 파이썬기반의 마이크로 웹개발 프레임워크입니다. 여러분은 현재 개발중인 버전의 문서를 보고 있습니다. 4 |

5 |

Other Formats

6 |

7 | 여러분은 다른 포맷의 문서로 다운로드 받을 수 있습니다: 8 |

9 | 15 |

Useful Links

16 | 22 | -------------------------------------------------------------------------------- /docs/ko/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /docs/ko/advanced_foreword.rst: -------------------------------------------------------------------------------- 1 | .. _advanced_foreword: 2 | 3 | 경험있는 프로그래머를 위한 머릿글 4 | ==================================== 5 | 6 | Flask에서 쓰레드 로컬 7 | ---------------------- 8 | 9 | Flask에 적용된 설계 원칙 중 하나는 단순한 업무는 단순해야한다는 것이다. 그런 종류의 업무들은 많은 코드를 요구하지 않아야 하지만, 여러분을 제약해서도 안된다. 그런 이유로 Flask는 몇몇 사람들을 놀라게 하거나, 정통적인 방식이 아니라고 생각할 수도 있는 몇개의 설계 원칙을 갖고 있다. 예를 들면, Flask는 내부적으로 쓰레드로컬방식을 사용하므로, 쓰레드-안전한 상태를 유지하기 위해 하나의 요청에서 처리되는 함수와 함수로 객체를 넘길 수 없다. 이런 접근은 편리하지만, 의존 주입에 대한 유효한 요청 문맥을 요구한다. 다시 말하면 요청에 고정된 값을 사용하는 코드를 재사용하려할 때, Flask 프로젝트는 쓰레드로컬에 대해 투명하고, 숨기지 않고, 심지어 사용되는 코드와 문서에서 드러내고 있다. 10 | 11 | 12 | 웹개발에서 주의점 13 | -------------------------------- 14 | 15 | 16 | 웹 어플리케이션을 개발할때에는 항상 보안에 대해 신경써야한다. 17 | 18 | 여러분이 웹 개발을 할때, 개발된 어플리케이션의 사용자들은 여러분의 서버에 사용자의 정보가 등록되고 남겨지는 것을 허용할 것이다. 사용자는 데이타에 있어서 여러분을 신뢰한다는 것이다. 만약 여러분이 직접 작성한 어플리케이션의 유일한 사용자라 할지라도, 자신의 데이타가 안전하기를 원할 것이다. 19 | 20 | 불행히도, 웹 어플리케이션의 보안이 타협되는 여러 가지 경우가 있다. 플라스크는 현대의 웹 어플리케이션의 가장 일반적인 보안 문제인 XSS로 부터 여러분을 보호한다. 굳이 여러분이 안전하지 않게 작성된 HTML을 안전하게 변환하지 않더라도, Flask와 그 하부의 Jinja2 템플릿 엔진이 여러분을 보호해준다. 그러나 보안문제를 유발하는 더 많은 경우가 있다. 21 | 22 | 이 문서는 보안에 있어 주의를 요구하는 웹 개발의 측면을 여러분에게 당부하고 있다. 이런 보안 관점의 몇몇은 일부 사람이 생각하는것 보다 훨씬 복잡하고, 우리 모두는 때때로 취약점이 이용될것이라는 가능성을 뛰어난 공격자가 우리의 어플리케이션의 취약점을 찾아낼때까지 낮게 점치곤한다. 그리고 여러분의 어플리케이션이 공격자가 칩입할 만큼 중요하지 않다고 생각하지 마라. 공격의 종류에 따라, 자동화된 bot이 여러분의 데이타베이스에 스팸을 채우기 위해 탐색하거나, 악성코드를 링크하는 방식과 같은 기회들이 있다. 23 | 24 | Flask는 여러분이 반드시 주의를 가지고 개발해야하고, 요구사항을 뽑아낼때 취약점 조사해야하는 측면은 어느 다른 프레임워크와도 같다. 25 | 26 | 27 | Python3의 상태 28 | ---------------------- 29 | 30 | 요즘 파이썬 공동체는 파이썬 프로그래밍 언어의 새로운 버전을 지원하기 위한 라이브러리의 개선 과정중이다. 그 과정은 대단히 개선되고 있지만, 우리들이 파이썬3로 넘가는데 걸림돌이 되는 몇가지 이슈가 있다. 이 문제들은 부분적으로 오래동안 검토되지 않은 언어의 변화에 의해 야기됐다. 또한 부분적으로는 우리들이 저수준API가 파이썬3에서 유니코드의 차이점 때문에 어떤식으로 변화되야한다는 점을 해결하지 못해왔다는 것이다. 31 | 32 | Werkzeug과 Flask는 그 변경에 대한 해결책을 찾는 순간 파이썬3로 포팅되고, 파이썬3으로 기 개발된 버전의 업그레이드에 대한 유용한 팁을 제공할 것이다. 그때까지, 여러분은 개발하는 동안 파이썬2.6이나 2.7을 파이썬3 경고를 활성화한 상태로 사용할 것을 권고한다. 여러분이 근래에 파이썬3로 업그레이드를 계획중이라면 `How to write forwards compatible 33 | Python code `_.를 읽는것을 적극 추천한다. 34 | 35 | 계속해서 :ref:`installation` 과 :ref:`quickstart` 살펴볼 수 있다. 36 | -------------------------------------------------------------------------------- /docs/ko/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../CHANGES 2 | -------------------------------------------------------------------------------- /docs/ko/contents.rst.inc: -------------------------------------------------------------------------------- 1 | 사용자 가이드 2 | ------------ 3 | 4 | 이 문서의 사용자 가이드 파트에서는, Flask에 관한 일부 배경 정보들로 시작해서 지시사항을 따라하는 Flask 웹 개발을위한 단계별 지침에 초점을 맞추고 있습니다.. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | foreword 10 | advanced_foreword 11 | installation 12 | quickstart 13 | tutorial/index 14 | templating 15 | testing 16 | errorhandling 17 | config 18 | signals 19 | views 20 | appcontext 21 | reqcontext 22 | blueprints 23 | extensions 24 | shell 25 | patterns/index 26 | deploying/index 27 | becomingbig 28 | 29 | API 레퍼런스 30 | ------------- 31 | 32 | 33 | 만약 여러분이 특정 함수, 클래스나 메소드에 대한 정보를 찾고 있다면, 문서의 이 부분은 당신에게 도움이 될 것 입니다. 34 | 35 | .. toctree:: 36 | :maxdepth: 2 37 | 38 | api 39 | 40 | 추가적인 참고사항 41 | ---------------- 42 | 43 | Flask의 디자인 노트, 법률 정보 변경 로그에 대한 관심있는 내용은 이곳에 있습니다. 44 | 45 | .. toctree:: 46 | :maxdepth: 2 47 | 48 | design 49 | htmlfaq 50 | security 51 | unicode 52 | extensiondev 53 | styleguide 54 | upgrading 55 | changelog 56 | license 57 | -------------------------------------------------------------------------------- /docs/ko/deploying/cgi.rst: -------------------------------------------------------------------------------- 1 | CGI 2 | === 3 | 4 | 다른 모든 배포 방법을 적용할 수 없다면, CGI는 확실히 가능할 것이다. 5 | CGI는 거의 모든 주요 서버에 의해 제공되지만 보통 차선의 성능을 가진다. 6 | 7 | 또한 CGI와 같은 환경에서 실행할 수 있는 구글의 `App Engine`_ 에서 플라스크 어플리케이션을 사용할 수 있는 방법이기도 하다. 8 | 9 | .. admonition:: 주의 10 | 11 | 어플리케이션 파일에서 있을 수 있는 ``app.run()`` 호출이 ``if __name__ == '__main__':`` 블럭안에 있는지 12 | 아니면 다른 파일로 분리되어 있는지 미리 확인해야 한다. 이것은 만약 우리가 어플리케이션을 CGI/앱엔진으로 배포한다면 13 | 원하지 않게 로컬 WSGI 서버를 항상 실행하기 때문에 호출되지 않음을 확인해야 한다. 14 | 15 | `.cgi` 파일 만들기 16 | ---------------------- 17 | 18 | 먼저 CGI 어플리케이션 파일을 만드는 것이 필요하다. 그것을 `yourapplication.cgi`:: 이라고 부르자. 19 | 20 | #!/usr/bin/python 21 | from wsgiref.handlers import CGIHandler 22 | from yourapplication import app 23 | 24 | CGIHandler().run(app) 25 | 26 | 서버 설정 27 | ------------ 28 | 29 | 보통 서버를 설정하는 두가지 방법이 있다. 30 | `.cgi` 를 `cgi-bin` 으로 복사하거나(`mod_rewrite` 나 URL을 재작성하는 유사한 것을 사용) 31 | 서버 지점을 파일에 직접 작성한다. 32 | 33 | 아파치의 경우, 아래와 같이 설정 파일 안에 입력할 수 있다: 34 | 35 | .. sourcecode:: apache 36 | 37 | ScriptAlias /app /path/to/the/application.cgi 38 | 39 | 그러나 공유된 웹호스팅에서는 아파치 설정에 접근할 수 없을 지도 모른다. 40 | 이런 경우, 여러분의 어플리케이션이 실행되기를 원하는 공개 디렉토리에 있는 `.htaccess` 파일에 41 | 입력할 수 있으나, 이 경우엔는 `ScriptAlias` 지시어는 적용되지 않을 것이다: 42 | 43 | .. sourcecode:: apache 44 | 45 | RewriteEngine On 46 | RewriteCond %{REQUEST_FILENAME} !-f # Don't interfere with static files 47 | RewriteRule ^(.*)$ /path/to/the/application.cgi/$1 [L] 48 | 49 | 더 많은 정보를 위해 사용하는 웹서버의 문서를 참조하라. 50 | 51 | .. _App Engine: http://code.google.com/appengine/ 52 | -------------------------------------------------------------------------------- /docs/ko/deploying/index.rst: -------------------------------------------------------------------------------- 1 | .. _deployment: 2 | 3 | 배포 옵션 4 | ================== 5 | 6 | 여러분이 어떤 것을 이용할 수 있는지에 따라서, 플라스크 어플리케이션을 실행할 수 있는 다양한 방법이 있다. 7 | 개발 중에는 내장 서버를 사용할 수 있지만, 운영울 위해서는 모든 배포 옵션을 사용해야 한다. 8 | (운영 중에는 내장 개발 서버를 사용하지 마라.) 사용할 수 있는 몇가지 옵션이 있다. 9 | 10 | 만약 다른 WSGI 서버가 있다면, WSGI 어플리케이션을 사용하는 방법에 대한 서버 문서를 참조하라. 11 | 단지 :class:`Flask` 어플리케이션 객체가 실제 WSGI 어플리케이션임을 기억하라. 12 | 13 | 빠르게 배포하고 실행하기 위한 옵션을 보려면, 퀵스타트의 :ref:`quickstart_deployment` 를 참조하라. 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | mod_wsgi 19 | wsgi-standalone 20 | uwsgi 21 | fastcgi 22 | cgi 23 | -------------------------------------------------------------------------------- /docs/ko/deploying/uwsgi.rst: -------------------------------------------------------------------------------- 1 | .. _deploying-uwsgi: 2 | 3 | uWSGI 4 | ===== 5 | 6 | uWSGI는 `nginx`_, `lighttpd`_, `cherokee`_ 와 같은 서버에서 사용할 수 있는 배포 옵션이다; 7 | 다른 옵션을 보려면 :ref:`deploying-fastcgi` 와 :ref:`deploying-wsgi-standalone` 를 확인하라. 8 | uWSGI 프로토토콜로 WSGI 어플리케이션을 사용하기 위해서는 먼저 uWSGI 서버가 필요하다. uWSGI는프로토콜이면서 어플리케이션 서버이다; 9 | 어플리케이션서버는 uWSGI, FastCGI, HTTP 프로토콜을 서비스할 수 있다. 10 | 11 | 가장 인기있는 uWSGI 서버는 `uwsgi`_이며, 12 | 설명을 위해 사용할 것이다. 아래와 같이 설치되어 있는지 확인하라. 13 | 14 | .. admonition:: 주의 15 | 16 | 어플리케이션 파일에서 있을 수 있는 ``app.run()`` 호출이 ``if __name__ == '__main__':`` 블럭안에 있는지 17 | 아니면 다른 파일로 분리되어 있는지 미리 확인해야 한다. 이것은 만약 우리가 어플리케이션을 uWSGI로 배포한다면 18 | 원하지 않게 로컬 WSGI 서버를 항상 실행하기 때문에 호출되지 않음을 확인해야 한다. 19 | 20 | uwsgi로 app 시작하기 21 | -------------------- 22 | 23 | `uwsgi`는 파이썬 모듈에 있는 WSGI callables에서 운영하기 위해 설계되어 있다. 24 | 25 | myapp.py에 flask application이 있다면 아래와 같이 사용하라: 26 | 27 | .. sourcecode:: text 28 | 29 | $ uwsgi -s /tmp/uwsgi.sock --module myapp --callable app 30 | 31 | 또는 아래와 같은 방법도 사용할 수 있다: 32 | 33 | .. sourcecode:: text 34 | 35 | $ uwsgi -s /tmp/uwsgi.sock -w myapp:app 36 | 37 | nginx 설정하기 38 | -------------- 39 | 40 | nginx를 위한 기본적인 flask uWSGI 설정은 아래와 같다:: 41 | 42 | location = /yourapplication { rewrite ^ /yourapplication/; } 43 | location /yourapplication { try_files $uri @yourapplication; } 44 | location @yourapplication { 45 | include uwsgi_params; 46 | uwsgi_param SCRIPT_NAME /yourapplication; 47 | uwsgi_modifier1 30; 48 | uwsgi_pass unix:/tmp/uwsgi.sock; 49 | } 50 | 51 | 이 설정은 어플리케이션을 `/yourapplication`에 바인드한다. 52 | URL 루트에 어플리케이션을 두길 원한다면, WSGI `SCRIPT_NAME`를 알려줄 필요가 없거나 53 | uwsgi modifier를 설정할 필요가 없기 때문에 조금 더 간단하다:: 54 | 55 | This configuration binds the application to `/yourapplication`. If you want 56 | to have it in the URL root it's a bit simpler because you don't have to tell 57 | it the WSGI `SCRIPT_NAME` or set the uwsgi modifier to make use of it:: 58 | 59 | location / { try_files $uri @yourapplication; } 60 | location @yourapplication { 61 | include uwsgi_params; 62 | uwsgi_pass unix:/tmp/uwsgi.sock; 63 | } 64 | 65 | .. _nginx: http://nginx.org/ 66 | .. _lighttpd: http://www.lighttpd.net/ 67 | .. _cherokee: http://www.cherokee-project.com/ 68 | .. _uwsgi: http://projects.unbit.it/uwsgi/ 69 | -------------------------------------------------------------------------------- /docs/ko/extensions.rst: -------------------------------------------------------------------------------- 1 | Flask 확장기능 2 | ================ 3 | Flask 확장기능(extensions)은 서로 다른 다양한 방법으로 Flask 의 기능을 추가 시킬 수 있게 해준다. 4 | 예를 들어 확장기능을 이용하여 데이터베이스 그리고 다른 일반적인 태스크들을 지원할 수 있다. 5 | 6 | 7 | 확장기능 찾아내기 8 | ------------------ 9 | 10 | 플라스크 확장기능들의 목록은 `Flask Extension Registry`_ 에서 살펴볼 수 있다. 11 | 그리고 ``easy_install`` 혹은 ``pip`` 를 통해 다운로드 할 수 있다. 12 | 만약 여러분이 Flask 확장기능을 추가하면, ``requirements.rst`` 혹은 ``setup.py`` 에 명시된 13 | 파일 의존관계로부터 간단한 명령어의 실행이나 응용 프로그램 설치와 함께 설치될 수 있다. 14 | 15 | 16 | 확장기능 사용하기 17 | ---------------- 18 | 19 | 확장기능은 일반적으로 해당 기능을 사용하는 방법을 보여주는 문서를 가지고 있다. 20 | 이 확장기능의 작동 방식에 대한 일반적인 규칙은 없지만, 확장기능은 공통된 위치에서 21 | 가져오게 된다. 만약 여러분이 ``Flask-Foo`` 혹은 ``Foo-Flask`` 라는 확장기능을 22 | 호출 하였다면, 그것은 항상 ``flask.ext.foo`` 을 통해서 가져오게 될 것이다 :: 23 | 24 | from flask.ext import foo 25 | 26 | 27 | Flask 0.8 이전버전의 경우 28 | ---------------- 29 | 30 | 31 | 만약 여러분의 Flask가 0.7 버전 혹은 그 이전의 것이라면 :data:`flask.ext` 패키지가 32 | 존재하지 않는다. 대신에 여러분은 ``flaskext.foo`` 혹은 ``flask_foo`` 등의 형식으로 33 | 확장기능이 배포되는 방식에 따라 불러와야만 한다. 만약 여러분이 여전히 Flask 0.7 혹은 이전 34 | 이전 버전을 지원하는 어플리케이션을 개발하기 원한다면, 여러분은 여전히 :data:`flask.ext` 35 | 패키지를 불러와야만 한다. 우리는 Flask 의 이전 버전의 Flask를 위한 호환성 모듈을 제공하고 있다. 36 | 여러분은 github을 통해서 : `flaskext_compat.py`_ 를 다운로드 받을 수 있다. 37 | 38 | 그리고 여기에서 호환성 모듈의 사용 방법을 볼 수 있다:: 39 | 40 | 41 | import flaskext_compat 42 | flaskext_compat.activate() 43 | 44 | from flask.ext import foo 45 | 46 | 47 | 48 | ``flaskext_compat`` 모듈이 활성화 되면 :data:`flask.ext` 가 존재하게 되고 49 | 여러분은 이것을 통해 여기서부터 불러오기를 시작 할 수 있다. 50 | 51 | 52 | .. _Flask Extension Registry: http://flask.pocoo.org/extensions/ 53 | .. _flaskext_compat.py: https://github.com/mitsuhiko/flask/raw/master/scripts/flaskext_compat.py 54 | -------------------------------------------------------------------------------- /docs/ko/flaskdocext.py: -------------------------------------------------------------------------------- 1 | import re 2 | import inspect 3 | 4 | 5 | _internal_mark_re = re.compile(r'^\s*:internal:\s*$(?m)') 6 | 7 | 8 | def skip_member(app, what, name, obj, skip, options): 9 | docstring = inspect.getdoc(obj) 10 | if skip: 11 | return True 12 | return _internal_mark_re.search(docstring or '') is not None 13 | 14 | 15 | def setup(app): 16 | app.connect('autodoc-skip-member', skip_member) 17 | -------------------------------------------------------------------------------- /docs/ko/foreword.rst: -------------------------------------------------------------------------------- 1 | 머리말 2 | ======== 3 | 4 | Flask를 시작하기 전에 먼저 이글을 읽어주시기 바랍니다. 이 글이 여러분의 프로젝트에서 이것을 사용하여야 하거나 사용하지 말아야 할때에 해당 목적과 의도에 대한 일부 질문들에 대한 답변이 될 수 있기를 희망합니다. 5 | 6 | 7 | "마이크로(Micro)"는 무엇을 뜻하는가? 8 | ----------------------- 9 | 10 | “마이크로”는 여러분의 웹 어플리케이션이 하나의 파이썬 파일으로 개발되야한다는 걸 말하는게 아니다.(그렇게 해석될 수 도 있겠지만…) 또한, 기능적으로 부족하다는걸 의미하지도 않는다. 마이크로 프레임워크(Microframework)에서의 “마이크로”는 핵심기능만 간결하게 유지하지만, 확장가능한 것을 목적으로 한다. Flask는 여러분을 위해 데이타베이스를 선택해주지 않는다. Flask에서 제공하는 템플릿 엔진을 변경하는것은 쉽다. 그밖에 모든것은 여러분에게 달려있고, 그래서 Flask는 여러분이 필요한 모든것일 수 있고, 필요없는것은 하나도 없을것이다. 11 | 12 | 13 | 설정과 관례 14 | ----------------------------- 15 | 16 | Flask로 시작할때, 여러분은 잘 정의된 기본값이 있는 많은 설정값들과 몇가지 관례를 볼 수 있다. 템플릿과 정적파일은 어플리케이션의 파이썬 소스 디렉토리의 하위 디렉토리에 templates과 statics에 저장된다. 이 방식은 변경할 수 있지만, 처음부터 반드시 그럴 필요는 없다. 17 | 18 | 19 | Flask를 이용하여 성장시키기 20 | -------------------------- 21 | 22 | 여러분이 Flask를 가지고 개발할때, 운영을 위해 여러분의 프로젝트와 통합할 여러 종류의 확장을 찾게된다. Flask 핵심 개발팀은 많은 확장을 검토했고 그것들이 앞으로의 배포판과 어긋나지 않는다는것을 보증한다. 23 | 24 | 여러분의 코드의 규모가 점점 커지면서, 여러분의 프로젝트에 설계에 적합한 선택을 할 기회가 온다 Flask는 계속적으로 파이썬이 제공하는 최고의 모듈에 간결한 연결층을 제공할 것이다. 여러분은 SQLAlchemy이나 다른 디비툴 또는 알맞게 비관계형 데이타 저장소로 고급 패턴을 만들수도 있고 파이썬 웹 인터페이스인 WSGI를 위한 프레임웍에 관계없이 사용할 수 있는 툴을 이용할 수 있다. 25 | 26 | Flask는 프레임웍의 기능을 변경하기 위한 많은 훅(hook)을 포함한다. 그것보다 더 많이 변경하고 싶다면 Flask class 자체를 상속하면 된다. 여러분이 subclassing에 관심이 있다면 :ref:`becomingbig` 챕터를 확인한다. 디자인 패턴이 궁금하다면 :ref:`design` 에 대한 섹션으로 넘어가라. 27 | 28 | 29 | 계속하기 :ref:`installation`, :ref:`quickstart`, 혹은 :ref:`advanced_foreword`. 30 | -------------------------------------------------------------------------------- /docs/ko/index.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Flask의 세계에 오신것을 환영합니다. 4 | ================ 5 | 6 | .. image:: _static/logo-full.png 7 | :alt: Flask: web development, one drop at a time 8 | :class: floatingflask 9 | 10 | Flask 문서에 오신것을 환영합니다. 이 문서는 다양한 파트로 나누어져 있습니다. 11 | 저자는 :ref:`installation` 와 :ref:`quickstart` 를 먼저 보실것을 추천합니다. 12 | :ref:`quickstart` 뿐만아니라, 어떻게 Flask 어플리케이션을 만들 수 있는지 좀 더 상세하게 다루는 :ref:`tutorial` 또한 볼 수 있습니다. 13 | 14 | 만약 여러분이 오히려 Flask의 내부로 직접 뛰어 들고 싶은 경우라면, 15 | :ref:`api` 문서를 확인하십시오. 일반적으로 사용되는 패턴들은 16 | :ref:`patterns` 섹션을 확인하면 됩니다.. 17 | 18 | Flask는 두개의 외부 라이브러리에 의존합니다.: 바로 `Jinja2`_ 템플릿엔진과 `Werkzeug`_ WSGI 툴킷입니다. 이 라이브러리들은 이 문서에서 다루지않습니다. 19 | 만약 여러분이 이 라이브러리들에 대해서 깊이 알고 싶다면 다음의 링크를 확인하십시오. 20 | 21 | 22 | - `Jinja2 Documentation `_ 23 | - `Werkzeug Documentation `_ 24 | 25 | .. _Jinja2: http://jinja.pocoo.org/2/ 26 | .. _Werkzeug: http://werkzeug.pocoo.org/ 27 | 28 | .. include:: contents.rst.inc 29 | -------------------------------------------------------------------------------- /docs/ko/latexindex.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Flask Documentation 4 | =================== 5 | 6 | .. include:: contents.rst.inc 7 | -------------------------------------------------------------------------------- /docs/ko/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | Flask is licensed under a three clause BSD License. It basically means: 5 | do whatever you want with it as long as the copyright in Flask sticks 6 | around, the conditions are not modified and the disclaimer is present. 7 | Furthermore you must not use the names of the authors to promote derivatives 8 | of the software without written consent. 9 | 10 | The full license text can be found below (:ref:`flask-license`). For the 11 | documentation and artwork different licenses apply. 12 | 13 | .. _authors: 14 | 15 | Authors 16 | ------- 17 | 18 | .. include:: ../../AUTHORS 19 | 20 | General License Definitions 21 | --------------------------- 22 | 23 | The following section contains the full license texts for Flask and the 24 | documentation. 25 | 26 | - "AUTHORS" hereby refers to all the authors listed in the 27 | :ref:`authors` section. 28 | 29 | - The ":ref:`flask-license`" applies to all the sourcecode shipped as 30 | part of Flask (Flask itself as well as the examples and the unittests) 31 | as well as documentation. 32 | 33 | - The ":ref:`artwork-license`" applies to the project's Horn-Logo. 34 | 35 | .. _flask-license: 36 | 37 | Flask License 38 | ------------- 39 | 40 | .. include:: ../../LICENSE 41 | 42 | 43 | .. _artwork-license: 44 | 45 | Flask Artwork License 46 | --------------------- 47 | 48 | .. include:: ../../artwork/LICENSE 49 | -------------------------------------------------------------------------------- /docs/ko/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/ko/logo.pdf -------------------------------------------------------------------------------- /docs/ko/patterns/appfactories.rst: -------------------------------------------------------------------------------- 1 | .. _app-factories: 2 | 3 | 어플리케이션 팩토리 4 | ===================== 5 | 6 | 여러분이 어플리케이션에 이미 패키지들과 청사진들을 사용한다면(:ref:`blueprints`) 7 | 그 경험들을 좀 더 개선할 몇 가지 정말 좋은 방법들이 있다. 8 | 일반적인 패턴은 청사진을 임포트할 때 어플리케이션 객체를 생성하는 것이다. 9 | 하지만 여러분이 이 객체의 생성을 함수로 옮긴다면, 10 | 나중에 이 객체에 대한 복수 개의 인스턴스를 생성할 수 있다. 11 | 12 | 그래서 여러분은 왜 이렇게 하고 싶은 것인가? 13 | 14 | 1. 테스팅. 여러분은 모든 케이스를 테스트하기 위해 여러 설정을 가진 어플리케이션 인스턴스들을 가질수 있다. 15 | 2. 복수 개의 인스턴스. 여러분이 같은 어플리케이션의 여러 다른 버전을 실행하고 싶다고 가정하자. 16 | 물론 여러분은 여러분은 웹서버에 여러 다른 설정을 가진 복수 개의 인스턴스를 가질 수도 있지만, 17 | 여러분이 팩토리를 사용한다면, 여러분은 간편하게 같은 어플리케이션 프로세스에서 동작하는 18 | 복수 개의 인스턴스를 가질 수 있다. 19 | 20 | 그렇다면 어떻게 여러분은 실제로 그것을 구현할 것인가? 21 | 22 | 기본 팩토리 23 | --------------- 24 | 25 | 이 방식은 함수 안에 어플리케이션을 설정하는 방법이다:: 26 | 27 | def create_app(config_filename): 28 | app = Flask(__name__) 29 | app.config.from_pyfile(config_filename) 30 | 31 | from yourapplication.views.admin import admin 32 | from yourapplication.views.frontend import frontend 33 | app.register_blueprint(admin) 34 | app.register_blueprint(frontend) 35 | 36 | return app 37 | 38 | 이 방식의 단점은 여러분은 임포트하는 시점에 청사진 안에 있는 어플리케이션 객체를 사용할 수 없다. 39 | 그러나 여러분은 요청 안에서 어플리케이션 객체를 사용할 수 있다. 40 | 어떻게 여러분이 설정을 갖고 있는 어플리케이션에 접근하는가? :data:`~flask.current_app` 을 사용하면 된다:: 41 | 42 | from flask import current_app, Blueprint, render_template 43 | admin = Blueprint('admin', __name__, url_prefix='/admin') 44 | 45 | @admin.route('/') 46 | def index(): 47 | return render_template(current_app.config['INDEX_TEMPLATE']) 48 | 49 | 여기에서 우리는 설정에 있는 템플릿 이름을 찾아낸다. 50 | 51 | 어플리케이션(Application) 사용하기 52 | ----------------------------------- 53 | 54 | 그렇다면 그런 어플리케이션을 사용하기 위해서 어려분은 먼저 어플리케이션을 생성해야한다. 55 | 아래는 그런 어플리케이션을 실행하는 `run.py` 파일이다:: 56 | 57 | from yourapplication import create_app 58 | app = create_app('/path/to/config.cfg') 59 | app.run() 60 | 61 | 팩토리 개선 62 | -------------------- 63 | 64 | 위에서 팩토리 함수는 지금까지는 그다지 똑똑하지 않았지만, 여러분은 개선할 수 있다. 65 | 다음 변경들은 간단하고 가능성이 있다: 66 | 67 | 1. 여러분이 파일시스템에 설정 파일을 만들지 않도록 유닛테스트를 위해 설정값을 전달하도록 만들어라. 68 | 2. 여러분이 어플리케이션의 속성들을 변경할 곳을 갖기 위해 어플리케이션이 셋업될 때 청사진에서 함수를 호출해라. 69 | (요청 핸들러의 앞/뒤로 가로채는 것 처럼) 70 | 3. 필요하다면 어플리케이션이 생성될 때, WSGI 미들웨어에 추가해라. 71 | -------------------------------------------------------------------------------- /docs/ko/patterns/caching.rst: -------------------------------------------------------------------------------- 1 | .. _caching-pattern: 2 | 3 | 캐싱(Caching) 4 | ============= 5 | 6 | 여러분의 어플리케이션이 느린 경우, 일종의 캐시를 넣어봐라. 그것이 7 | 속도를 높이는 최소한의 가장 쉬운 방법이다. 캐시가 무엇을 하는가? 8 | 여러분이 수행을 마치는데 꽤 시간이 걸리는 함수를 갖고 있지만 결과가 9 | 실시간이 아닌 5분이 지난 결과도 괜찮다고 하자. 그렇다면 여러분은 10 | 그 시간동안 결과를 캐시에 넣어두고 사용해도 좋다는게 여기의 생각이다. 11 | 12 | 플라스크 그 자체는 캐시를 제공하지 않지만, 플라스크의 토대가 되는 13 | 라이브러중 하나인 벡자이크(Werkzeug)는 굉장히 기본적인 캐시를 지원한다. 14 | 보통은 여러분이 memchached 서버로 사용하고 싶은 15 | 다중 캐시 백엔드를 지원한다. 16 | 17 | 캐시 설정하기 18 | ------------- 19 | 20 | 여러분은 :class:`~flask.Flask` 을 생성하는 방법과 유사하게 캐시 객체를 21 | 일단 생성하고 유지한다. 여러분이 개발 서버를 사용하고 있다면 여러분은 22 | :class:`~werkzeug.contrib.cache.SimpleCache` 객체를 생성할 수 있고, 23 | 그 객체는 파이썬 인터프리터의 메모리에 캐시의 항목을 저장하는 간단한 캐시다:: 24 | 25 | from werkzeug.contrib.cache import SimpleCache 26 | cache = SimpleCache() 27 | 28 | 여러분이 memcached를 사용하고 싶다면, 지원되는 memcache 모듈중 하나를 갖고 29 | (`PyPI `_ 에서 얻음) 어디선가 memcached 서버가 30 | 동작하는 것을 보장해라. 그리고 나면 아래의 방식으로 memcached 서버에 31 | 연결하면 된다:: 32 | 33 | from werkzeug.contrib.cache import MemcachedCache 34 | cache = MemcachedCache(['127.0.0.1:11211']) 35 | 36 | 여러분이 App 엔진을 사용한다면, 손쉽게 App 엔진 ememcache 서버에 연결할 37 | 수 있다:: 38 | 39 | from werkzeug.contrib.cache import GAEMemcachedCache 40 | cache = GAEMemcachedCache() 41 | 42 | 캐시 사용하기 43 | ------------- 44 | 45 | 캐시는 어떻게 사용할 수 있을까? 두가지 굉장히 중요한 함수가 있다: 46 | :meth:`~werkzeug.contrib.cache.BaseCache.get` 과 47 | :meth:`~werkzeug.contrib.cache.BaseCache.set` 이다. 아래는 사용 방법이다: 48 | 49 | 캐시에서 항목을 얻기 위해서는 문자열로 된 키 명으로 50 | :meth:`~werkzeug.contrib.cache.BaseCache.get` 를 호출하면 된다. 캐시에 그 키에 51 | 값이 있다면, 그 값이 반환된다. 없다면 `None`이 반환될 것이다:: 52 | 53 | rv = cache.get('my-item') 54 | 55 | 캐시에 항목을 넣기 위해서는, :meth:`~werkzeug.contrib.cache.BaseCache.set` 를 56 | 사용하면 된다. 첫번째 인자는 키이고 두번째는 설정할 값이다. 타임아웃 또한 57 | 항목으로 넣을 수가 있는데 그 시간이 지나면 캐시에서 자동으로 그 항목은 삭제된다. 58 | 59 | 아래는 보통 정상적으로 사용되는 전체 예제이다:: 60 | 61 | def get_my_item(): 62 | rv = cache.get('my-item') 63 | if rv is None: 64 | rv = calculate_value() 65 | cache.set('my-item', rv, timeout=5 * 60) 66 | return rv 67 | -------------------------------------------------------------------------------- /docs/ko/patterns/deferredcallbacks.rst: -------------------------------------------------------------------------------- 1 | .. _deferred-callbacks: 2 | 3 | 지연된(deferred) 요청 콜백 4 | ========================== 5 | 6 | 플라스크의 설계 원칙 중 한가지는 응답 객체가 생성되고 그 객체를 수정하거나 7 | 대체할 수 있는 잠재적인 콜백의 호출 사슬로 그 객체를 전달하는 것이다. 8 | 요청 처리가 시작될 때, 아직은 응답 객체를 존재하지 않는다. 뷰 함수나 9 | 시스템에 있는 어떤 다른 컴포넌트에 의해 필요할 때 생성된다. 10 | 11 | 하지만 응답이 아직 존재하지 않는 시점에서 응답을 수정하려 하면 어떻게 되는가? 12 | 그에 대한 일반적인 예제는 응답 객체에 있는 쿠키를 설정하기를 원하는 13 | before-request 함수에서 발생할 것이다. 14 | 15 | 한가지 방법은 그런 상황을 피하는 것이다. 꽤 자주 이렇게 하는게 가능하다. 16 | 예를 들면 여러분은 그런 로직을 after-request 콜백으로 대신 옮기도록 17 | 시도할 수 있다. 하지만 때때로 거기에 있는 코드를 옮기는 것은 유쾌한 18 | 일이 아니거나 코드가 대단히 부자연스럽게 보이게 된다. 19 | 20 | 다른 가능성으로서 여러분은 :data:`~flask.g` 객체에 여러 콜백 함수를 21 | 추가하고 요청의 끝부분에서 그것을 호출할 수 있다. 이 방식으로 여러분은 22 | 어플리케이션의 어느 위치로도 코드 실행을 지연시킬 수 있다. 23 | 24 | 25 | 데코레이터 26 | ---------- 27 | 28 | 다음에 나올 데코레이터가 핵심이다. 그 데코레이터는 :data:`~flask.g` 객체에 29 | 있는 리스트에 함수를 등록한다:: 30 | 31 | from flask import g 32 | 33 | def after_this_request(f): 34 | if not hasattr(g, 'after_request_callbacks'): 35 | g.after_request_callbacks = [] 36 | g.after_request_callbacks.append(f) 37 | return f 38 | 39 | 40 | 지연된 함수의 호출 41 | ------------------ 42 | 43 | 이제 여러분은 요청의 마지막에서 호출될 함수를 표시하기 위해 `after_this_request` 44 | 데코레이터를 사용할 수 있다. 하지만 우리는 여전히 그 함수를 호출할 수도 있다. 45 | 이렇게 하기 위해 다음 함수가 :meth:`~flask.Flask.after_request` 콜백으로 등록될 46 | 필요가 있다:: 47 | 48 | @app.after_request 49 | def call_after_request_callbacks(response): 50 | for callback in getattr(g, 'after_request_callbacks', ()): 51 | response = callback(response) 52 | return response 53 | 54 | 55 | 실제적인 예제 56 | ------------- 57 | 58 | 이제 우리는 이 특정 요청의 마지막에서 호출될 함수를 적절한 어느 시점에라도 59 | 쉽게 등록할 수 있다. 예를 들면 여러분은 before-request 함수에서 쿠키에 사용자의 60 | 현재 언어를 기억하게 할 수 있다:: 61 | 62 | from flask import request 63 | 64 | @app.before_request 65 | def detect_user_language(): 66 | language = request.cookies.get('user_lang') 67 | if language is None: 68 | language = guess_language_from_request() 69 | @after_this_request 70 | def remember_language(response): 71 | response.set_cookie('user_lang', language) 72 | g.language = language 73 | -------------------------------------------------------------------------------- /docs/ko/patterns/errorpages.rst: -------------------------------------------------------------------------------- 1 | 커스텀 오류 페이지 2 | ================== 3 | 4 | 플라스크에는 앞에서 나온 HTTP 오류 코드를 가지고 요청을 중단하는 5 | :func:`~flask.abort` 함수가 있다. 그것은 또한 정말 꾸미지 않은 기본적인 6 | 설명을 가진 단순한 흑백의 오류 페이지를 제공할 것이다. 7 | 8 | 오류 코드에 따라서 사용자가 실제로 그런 오류를 볼 가능성이 있다. 9 | 10 | 공통 오류 코드 11 | -------------- 12 | 13 | 다음의 오류 코드는 어플리케이션이 정상적으로 동작했음에도 불구하고 사용자에게 14 | 종종 보여지는 것이다: 15 | 16 | *404 Not Found* 17 | 즐겨쓰는 메시지에 "이봐 친구, 그 URL 입력에 실수가 있어" 가 있다. 18 | 인터넷 초보자 조차 그 404를 알고 있는 그렇게 일반적인 것은 다음을 19 | 의미한다 : 젠장, 내가 찾고 있는 것이 거기에 없네. 404 페이지에 20 | 적어도 index 페이지로 돌아갈 수 있는 링크와 같은 유용한 것이 있도록 21 | 하는게 매우 좋은 방식이다. 22 | 23 | *403 Forbidden* 24 | 여러분의 웹사이트에 어떤 접근 제어가 있다면, 허용되지 않는 자원에 대해 25 | 403 코드를 보내야할 것이다. 그렇기 때문에 사용자가 금지된 자원에 대해 26 | 접근하려할 때 사용자가 링크를 잃어버리지 않도록 해야한다. 27 | 28 | *410 Gone* 29 | 여러분은 "404 Not Found" 에게 "410 Gone" 이라는 형제가 있었다는 것을 30 | 알았는가? 일부 사람들만 실제로 그것을 구현했지만, 그 방식은 전에 31 | 존재했지만 현재 삭제된 자원에 대해 404 대신에 401 로 응답하는 것이다. 32 | 여러분이 데이터베이스에서 영구적으로 문서를 지우지 않고 삭제됐다고 33 | 표시만 한다면, 사용자에게 편의를 제공하며 410 코드를 대신 사용하고 34 | 그들이 찾고 있는 것은 영구적으로 삭제됐다는 메시지를 보여줘라. 35 | 36 | *500 Internal Server Error* 37 | 보통 프로그래밍 오류나 서버에 한계 부하를 넘었을 때 이 오류가 발생한다. 38 | 그 경우에 멋진 페이지를 보여주는 것이 굉장히 좋은 방식인데, 왜냐하면 39 | 여러분의 어플리케이션은 머지않아 다시 동작하지 않을 것이기 때문이다 40 | (여기를 또한 살펴봐라: :ref:`application-errors`). 41 | 42 | 43 | 오류 핸들러 44 | ----------- 45 | 46 | 오류 핸들러는 뷰 함수와 같은 일종의 함수이지만, 그것은 오류가 발생하고 47 | 그 오류를 전달했을 때 호출된다. 오류는 대부분 48 | :exc:`~werkzeug.exceptions.HTTPException` 이지만, 어떤 경우에는 다른 49 | 오류일 수도 있다: 내부 서버 오류에 대한 핸들러는 그 요류들이 잡히지 않을지 50 | 모르지만 다른 예외 인스턴스에 넘겨질 것이다. 51 | 52 | 오류 핸들러는 :meth:`~flask.Flask.errorhandler` 데코레이터와 예외에 대한 53 | 오류 코드를 가지고 등록된다. 플라스크는 오류 코드를 설정하지 *않을 것* 54 | 이라는 것을 명심하고, 그렇기 때문에 응답을 반환할 때 HTTP 상태 코드를 55 | 제공하도록 해야한다. 56 | 57 | 여기에 "404 Page Not Found" 예외에 대한 구현 예제가 있다:: 58 | 59 | from flask import render_template 60 | 61 | @app.errorhandler(404) 62 | def page_not_found(e): 63 | return render_template('404.html'), 404 64 | 65 | 예제 템플릿은 다음과 같을 것이다: 66 | 67 | .. sourcecode:: html+jinja 68 | 69 | {% extends "layout.html" %} 70 | {% block title %}Page Not Found{% endblock %} 71 | {% block body %} 72 |

Page Not Found

73 |

What you were looking for is just not there. 74 |

go somewhere nice 75 | {% endblock %} 76 | -------------------------------------------------------------------------------- /docs/ko/patterns/favicon.rst: -------------------------------------------------------------------------------- 1 | 파비콘 추가하기 2 | =============== 3 | 4 | "파비콘(favicon)"은 탭이나 북마크를 위해 브라우저에서 사용되는 아이콘이다. 5 | 이 아이콘은 여러분의 웹사이트를 구분하는데 도움을 주고 그 사이트에 유일한 6 | 표식을 준다. 7 | 8 | 일반적인 질문은 플라스크 어플리케이션에 어떻게 파이콘을 추가하는가 이다. 9 | 물론 제일 먼저 파이콘이 필요하다. 16 × 16 픽셀과 ICO 파일 형태이어야 한다. 10 | 이것은 전제사항은 아니지만 그 형태가 모든 브라우저에서 지원하는 업계 표준이다. 11 | 여러분의 static 디렉토리에 그 아이콘을 :file:`favicon.ico` 파일명으로 넣는다. 12 | 13 | 자, 그 아이콘을 브라우저에서 찾으려면, 여러분의 HTML에 link 태그를 추가하는게 14 | 알맞은 방법이다. 그래서 예를 들면: 15 | 16 | .. sourcecode:: html+jinja 17 | 18 | 19 | 20 | 대부분의 브라우저에서는 위의 한줄이 여러분이 해줄 전부이지만, 몇몇 예전 브라우저는 21 | 이 표준을 지원하지 않는다. 예전 업계 표준은 웹사이트의 루트에 그 파일을 위치시켜 22 | 제공하는 것이다. 여러분의 어플리케이션이 해당 도메인의 루트 경로에 마운트되지 23 | 않았다면 루트에서 그 아이콘이 제공되도록 웹서버 설정이 필요하므로 그렇게 할 수 24 | 없다면 여러분은 운이 없는 것이다. 그러나 어프리케이션이 루트에 있다면 여러분은 25 | 리디렉션으로 간단히 경로를 찾게할 수 있다:: 26 | 27 | app.add_url_rule('/favicon.ico', 28 | redirect_to=url_for('static', filename='favicon.ico')) 29 | 30 | 여러분이 추가적인 리디렉션 요청을 저장하고 싶다면 :func:`~flask.send_from_directory` 31 | 를 사용한 뷰 함수 또한 작성할 수 있다:: 32 | 33 | import os 34 | from flask import send_from_directory 35 | 36 | @app.route('/favicon.ico') 37 | def favicon(): 38 | return send_from_directory(os.path.join(app.root_path, 'static'), 39 | 'favicon.ico', mimetype='image/vnd.microsoft.icon') 40 | 41 | 명시적인 마임타입(mimetype)을 생략할 수 있고 그 타입은 추측될 것이지만, 그것은 42 | 항상 같게 추측될 것이므로 추가적인 추측을 피하기 위해 타입을 지정하는 것이 좋다. 43 | 44 | 위의 예는 어플리케이션을 통해 아이콘을 제공할 것이고 가능하다면 웹서버 문서를 45 | 참고하여 그렇게 할 전담 웹서버를 구성하는 것이 더 좋다. 46 | 47 | 추가로 볼 내용 48 | -------------- 49 | 50 | * 위키피디아(Wikipedia)의 `파비콘 `_ 기사 51 | -------------------------------------------------------------------------------- /docs/ko/patterns/index.rst: -------------------------------------------------------------------------------- 1 | .. _patterns: 2 | 3 | Flask를 위한 패턴들 4 | ====================== 5 | 6 | 어떤 것들은 충분히 일반적이어서 여러분이 대부분의 웹 어플리케이션에서 찾을 가능성이 높다. 예를 들면 많은 어플리케이션들이 관계형 데이타베이스와 사용자 인증을 사용한다. 그 경우에, 그 어플리케이션들은 요청 초반에 데이타베이스 연결을 열고 사용자 테이블에서 현재 로그인된 사용자의 정보를 얻을 것이다. 요청의 마지막에는 그 데이타베이스 연결을 다시 닫는다. 7 | 8 | `플라스크 스니핏 묶음(Flask Snippet Archives) `_ 에 많은 사용자들이 기여한 스니핏과 패턴들이 있다. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | packages 14 | appfactories 15 | appdispatch 16 | urlprocessors 17 | distribute 18 | fabric 19 | sqlite3 20 | sqlalchemy 21 | fileuploads 22 | caching 23 | viewdecorators 24 | wtforms 25 | templateinheritance 26 | flashing 27 | jquery 28 | errorpages 29 | lazyloading 30 | mongokit 31 | favicon 32 | streaming 33 | deferredcallbacks 34 | methodoverrides 35 | requestchecksum 36 | -------------------------------------------------------------------------------- /docs/ko/patterns/methodoverrides.rst: -------------------------------------------------------------------------------- 1 | HTTP 메소드 오버라이드 추가하기 2 | =============================== 3 | 4 | 어떤 HTTP 프록시는 임시적인 HTTP 메소드나 새로운 HTTP 메소드 (PATCH 같은) 5 | 를 지원하지 않는다. 그런 경우에 프로토콜 전체를 위반하는 방식으로 6 | HTTP 메소드를 다른 HTTP 메소드로 "프록시" 하는 것이 가능하다. 7 | 8 | 이렇게 동작하는 방식은 클라이언트가 HTTP POST로 요청하고 9 | ``X-HTTP-Method-Override`` 헤더를 설정하고 그 값으로 의도하는 HTTP 메소드 10 | (``PATCH`` 와 같은)를 설정하면 된다. 11 | 12 | 이것은 HTTP 미들웨어로 쉽게 수행할 수 있다:: 13 | 14 | class HTTPMethodOverrideMiddleware(object): 15 | allowed_methods = frozenset([ 16 | 'GET', 17 | 'HEAD', 18 | 'POST', 19 | 'DELETE', 20 | 'PUT', 21 | 'PATCH', 22 | 'OPTIONS' 23 | ]) 24 | bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE']) 25 | 26 | def __init__(self, app): 27 | self.app = app 28 | 29 | def __call__(self, environ, start_response): 30 | method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper() 31 | if method in self.allowed_methods: 32 | method = method.encode('ascii', 'replace') 33 | environ['REQUEST_METHOD'] = method 34 | if method in self.bodyless_methods: 35 | environ['CONTENT_LENGTH'] = '0' 36 | return self.app(environ, start_response) 37 | 38 | 플라스크로 이것을 하려면 아래와 같이 하면 된다:: 39 | 40 | from flask import Flask 41 | 42 | app = Flask(__name__) 43 | app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app) 44 | -------------------------------------------------------------------------------- /docs/ko/patterns/requestchecksum.rst: -------------------------------------------------------------------------------- 1 | 요청한 내용에 대한 체크섬 2 | ========================= 3 | 4 | 코드의 여러 부분이 요청 데이터로 5 | Various pieces of code can consume the request data and preprocess it. 6 | For instance JSON data ends up on the request object already read and 7 | processed, form data ends up there as well but goes through a different 8 | code path. This seems inconvenient when you want to calculate the 9 | checksum of the incoming request data. This is necessary sometimes for 10 | some APIs. 11 | 12 | Fortunately this is however very simple to change by wrapping the input 13 | stream. 14 | 15 | The following example calculates the SHA1 checksum of the incoming data as 16 | it gets read and stores it in the WSGI environment:: 17 | 18 | import hashlib 19 | 20 | class ChecksumCalcStream(object): 21 | 22 | def __init__(self, stream): 23 | self._stream = stream 24 | self._hash = hashlib.sha1() 25 | 26 | def read(self, bytes): 27 | rv = self._stream.read(bytes) 28 | self._hash.update(rv) 29 | return rv 30 | 31 | def readline(self, size_hint): 32 | rv = self._stream.readline(size_hint) 33 | self._hash.update(rv) 34 | return rv 35 | 36 | def generate_checksum(request): 37 | env = request.environ 38 | stream = ChecksumCalcStream(env['wsgi.input']) 39 | env['wsgi.input'] = stream 40 | return stream._hash 41 | 42 | To use this, all you need to do is to hook the calculating stream in 43 | before the request starts consuming data. (Eg: be careful accessing 44 | ``request.form`` or anything of that nature. ``before_request_handlers`` 45 | for instance should be careful not to access it). 46 | 47 | Example usage:: 48 | 49 | @app.route('/special-api', methods=['POST']) 50 | def special_api(): 51 | hash = generate_checksum(request) 52 | # Accessing this parses the input stream 53 | files = request.files 54 | # At this point the hash is fully constructed. 55 | checksum = hash.hexdigest() 56 | return 'Hash was: %s' % checksum 57 | -------------------------------------------------------------------------------- /docs/ko/patterns/streaming.rst: -------------------------------------------------------------------------------- 1 | 컨텐트 스트리밍하기 2 | ===================== 3 | 4 | 종종 여러분은 클라이언트로 메모리에 유지하고 싶은 양보다 훨씬 더 큰, 5 | 엄청난 양의 데이터를 전송하기를 원한다. 여러분이 그 데이터를 바로 생성하고 6 | 있을 때, 파일시스템으로 갔다오지 않고 어떻게 클라이언트로 그것을 전송하는가? 7 | 8 | 답은 바로 생성기(generators)와 직접 응답이다. 9 | 10 | 기본 사용법 11 | ----------- 12 | 13 | 이것은 많은 CSV 데이터를 즉각 생성하는 기초적인 뷰 함수이다. 데이터를 생성하는 14 | 생성기를 사용하는 내부(inner) 함수를 갖고 그 함수를 호출하면서 응답 객체에 15 | 그 함수를 넘기는것이 그 기법이다:: 16 | 17 | from flask import Response 18 | 19 | @app.route('/large.csv') 20 | def generate_large_csv(): 21 | def generate(): 22 | for row in iter_all_rows(): 23 | yield ','.join(row) + '\n' 24 | return Response(generate(), mimetype='text/csv') 25 | 26 | 각 ``yield`` 표현식은 브라우져에 직접 전송된다. 어떤 WSGI 미들웨어는 27 | 스트리밍을 깰수도 있지만, 프로파일러를 가진 디버그 환경과 여러분이 활성화 28 | 시킨 다른 것들을 조심하도록 유의하라. 29 | 30 | 템플릿에서 스트리밍 31 | ------------------- 32 | 33 | 진자2 템플릿 엔진은 또한 부분 단위로 템플릿을 뿌려주는 것을 지원한다. 이 기능은 34 | 꽤 일반적이지 않기 때문에 플라스크에 직접적으로 노출되지 않지만, 아래처럼 여러분이 35 | 쉽게 직접 구현할 수 있다:: 36 | 37 | from flask import Response 38 | 39 | def stream_template(template_name, **context): 40 | app.update_template_context(context) 41 | t = app.jinja_env.get_template(template_name) 42 | rv = t.stream(context) 43 | rv.enable_buffering(5) 44 | return rv 45 | 46 | @app.route('/my-large-page.html') 47 | def render_large_template(): 48 | rows = iter_all_rows() 49 | return Response(stream_template('the_template.html', rows=rows)) 50 | 51 | 여기서의 기법은 어플리케이션의 진자2 환경에서 템플릿 객체를 얻고 문자열 대신 52 | 스트림 객체를 반환하는 :meth:`~jinja2.Template.render` 대신 53 | :meth:`~jinja2.Template.stream` 를 호출하는 것이다. 플라스크 템플릿 렌더 함수를 54 | 지나치고 템플릿 객체 자체를 사용하고 있기 때문에 55 | :meth:`~flask.Flask.update_template_context` 를 호출하여 렌더 컨텍스트를 갱신하도록 56 | 보장해야한다. 그리고 나서 스트림을 순환하면서 템플릿을 해석한다. 매번 여러분은 yield 57 | 를 호출하기 때문에 서버는 클라이언트로 내용을 밀어내어 보낼 것이고 여러분은 58 | ``rv.enable_buffering(size)`` 을 가지고 템플릿 안에 몇가지 항목을 버퍼링하기를 원할지도 59 | 모른다. ``5`` 가 보통 기본값이다. 60 | 61 | 컨텍스트를 가진 스트리밍 62 | ------------------------ 63 | 64 | .. versionadded:: 0.9 65 | 66 | 여러분이 데이터를 스트리밍할 때, 요청 컨텍스트는 그 함수가 호출된 순간 이미 67 | 종료된다는 것에 주목해라. 플라스크 0.9 는 생성기가 수행하는 동안 요청 컨텍스트를 68 | 유지하게 해주는 조력자를 제공한다:: 69 | 70 | from flask import stream_with_context, request, Response 71 | 72 | @app.route('/stream') 73 | def streamed_response(): 74 | def generate(): 75 | yield 'Hello ' 76 | yield request.args['name'] 77 | yield '!' 78 | return Response(stream_with_context(generate())) 79 | 80 | 81 | :func:`~flask.stream_with_context` 함수 없다면 여러분은 그 시점에 :class:`RuntimeError` 82 | 를 얻을 것이다. 83 | -------------------------------------------------------------------------------- /docs/ko/patterns/templateinheritance.rst: -------------------------------------------------------------------------------- 1 | .. _template-inheritance: 2 | 3 | 템플릿 상속 4 | =========== 5 | 6 | 진자(Jinja)의 가장 강력한 부분은 템플릿 상속 기능이다. 템플릿 상속은 여러분의 사이트에 7 | 대한 모든 일반적인 요소들을 포함한 기본 "스켈레톤(skeleton)" 템플릿을 생성하도록 하고 8 | 자식 템플릿은 기본 템플릿을 오버라이드(override)할 수 있는 **blocks** 을 정의한다. 9 | 10 | 복잡해 보이지만 꽤 간단하다. 예제로 시작하는게 이해하는데 가장 쉽다. 11 | 12 | 13 | 기본 템플릿 14 | ----------- 15 | 16 | 우리가 ``layout.html`` 이라 부를 이 팀플릿은 간단한 두개의 칼럼을 가진 페이지로 17 | 사용할 간단한 HTML 스켈레톤 문서를 정의한다. 내용의 빈 블럭을 채우것이 "자식" 18 | 템플릿의 일이다: 19 | 20 | .. sourcecode:: html+jinja 21 | 22 | 23 | 24 | 25 | {% block head %} 26 | 27 | {% block title %}{% endblock %} - My Webpage 28 | {% endblock %} 29 | 30 | 31 |

{% block content %}{% endblock %}
32 | 37 | 38 | 39 | 이 예제에서, ``{% block %}`` 태그는 자식 템플릿이 채울 수 있는 네개의 블럭을 40 | 정의한다. `block` 태그가 하는 전부는 템플릿 엔진에 자식 템플릿이 템플릿의 `block` 41 | 태그를 오버라이드할 수 도 있다라고 알려준다. 42 | 43 | 자식 템플릿 44 | ----------- 45 | 46 | 자식 템플릿은 아래와 같이 보일 수도 있다: 47 | 48 | .. sourcecode:: html+jinja 49 | 50 | {% extends "layout.html" %} 51 | {% block title %}Index{% endblock %} 52 | {% block head %} 53 | {{ super() }} 54 | 57 | {% endblock %} 58 | {% block content %} 59 |

Index

60 |

61 | Welcome on my awesome homepage. 62 | {% endblock %} 63 | 64 | ``{% extends %}`` 태그가 여기서 핵심이다. 이 태그는 템플릿 엔진에게 이 템플릿이 65 | 다른 템플릿을 "확장(extends)" 한다라고 알려준다. 템플릿 시스템이 이 템플릿을 66 | 검증할 때, 가장 먼저 부모 템플릿을 찾는다. 그 확장 태그가 템플릿에서 가장 먼저 67 | 있어야 한다. 부모 템플릿에 정의된 블럭의 내용을 보여주려면 ``{{ super() }}`` 를 68 | 사용하면 된다. 69 | -------------------------------------------------------------------------------- /docs/ko/shell.rst: -------------------------------------------------------------------------------- 1 | .. _shell: 2 | 3 | 쉘에서 작업하기 4 | ====================== 5 | 6 | .. versionadded:: 0.3 7 | 8 | 많은 사람들이 파이썬을 좋아하는 이유 중 한가지는 바로 대화식 쉘이다. 9 | 그것은 기본적으로 여러분이 실시간으로 파이썬 명령을 싱행하고 결과를 실시간으로 10 | 즉시 받아 볼 수 있다. Flask 자체는 대화식 쉘과 함께 제공되지 않는다. 왜냐하면 11 | Flask는 특정한 선행 작업이 필요하지 않고, 단지 여러분의 어플리케이션에서 불러오기만 하면 12 | 시작할 수 있기 때문이다. 13 | 14 | 15 | 하지만, 쉘에서 좀 더 많은 즐거운 경험을 얻을 수 있는 몇 가지 유용한 헬퍼들이 있다. 16 | 대화식 콘솔 세션에서의 가장 중요한 문제는 여러분이 직접 브라우저에서 처럼 :data:`~flask.g`, :data:`~flask.request` 를 발생 시킬 수 없고, 그 밖의 다른 것들도 가능하지 않다. 하지만 테스트 해야 할 코드가 그것들에게 종속관계에 있다면 여러분은 어떻게 할 것인가? 17 | 18 | 19 | 이 장에는 몇가지 도움이 되는 함수가 있다. 20 | 이 함수들은 대화식 쉘에서의 사용뿐만 아니라, 단위테스트와 같은 그리고 요청 컨텍스트를 21 | 위조해야 하는 상황에서 또한 유용하다는 것을 염두해 두자. 22 | 23 | 24 | 일반적으로 여러분이 :ref:`request-context` 를 먼저 읽기를 권장한다. 25 | 26 | 27 | 요청 컨텍스트 생성하기 28 | -------------------------- 29 | 30 | 쉘에서 적절한 요청 컨텍스트를 생성하는 가장 쉬운 방법은 :class:`~flask.ctx.RequestContext`: 를 우리에게 생성해주는 :attr:`~flask.Flask.test_request_context` 메소드를 사용하는 것이다.: 31 | 32 | >>> ctx = app.test_request_context() 33 | 34 | 일반적으로 여러분은 `with` 구문을 사용하여 이 요청 객체를 활성화 하겠지만, 35 | 쉘에서는 :meth:`~flask.ctx.RequestContext.push` 와 :meth:`~flask.ctx.RequestContext.pop` 를 36 | 직접 다루는 방법이 더 쉽다: 37 | 38 | 39 | >>> ctx.push() 40 | 41 | 여러분이 `pop` 을 호출하는 그 시점까지 request 객체를 사용하여 작업 할 수 있다. 42 | : 43 | 44 | >>> ctx.pop() 45 | 46 | 47 | 48 | 요청하기 전/후에 발사하기(Firing) 49 | --------------------------- 50 | 51 | 단지 요청 컨텍스트를 생성만 하면, 일반적으로 요청전에 실행되는 코드를 실행할 필요가 없다. 52 | 이것은 만약 여러분이 before-request 콜백에서 데이터베이스 연결을 하거나 , 혹은 현재 사용자가 :data:`~flask.g` 객체에 저장하지 않을 경우에 발생할 수 있다.. 53 | 54 | 그러나 이것은 단지 :meth:`~flask.Flask.preprocess_request` 를 호출하여 쉽게 수행 할 수 있다: 55 | 56 | >>> ctx = app.test_request_context() 57 | >>> ctx.push() 58 | >>> app.preprocess_request() 59 | 60 | 다음을 염두 해 두어야 한다. 61 | 이 경우에 :meth:`~flask.Flask.preprocess_request` 함수는 응답(response) 객체를 리턴할 것이고, 이것은 그냥 무시해도 된다. 62 | 63 | 64 | 요청을 종료시키기 위해서, 여러분은 사후 요청 함수 ( :meth:`~flask.Flask.process_response` 에 의해 트리거되는)가 응답 객체에서 사용 전에 약간의 트릭을 사용해야 한다: 65 | 66 | >>> app.process_response(app.response_class()) 67 | 68 | >>> ctx.pop() 69 | 70 | 컨텍스트가 열리게 되면 :meth:`~flask.Flask.teardown_request` 로 등록된 함수가 71 | 자동으로 호출된다. 그래서 이것은 자동으로 요청 컨텍스트 (데이터 베이스 연결과 같은)에 72 | 필요한 자원을 해제 할 수 있는 완벽한 장소이다.. 73 | 74 | 75 | 76 | 쉘 경험을 더욱 향상시키기 77 | -------------------------------------- 78 | 79 | 여러분이 만약 쉘에서의 실험적인 아이디어를 실험하기 좋아한다면, 80 | 본인 스스로 여러분의 대화형 세션으로 불러올 모듈을 만들 수 있다. 81 | 여기에 또한 여러분은 데이터베이스를 초기화 하거나 테이블을 삭제하는등의 좀 더 유용한 도우미 메소드등을 정의 할 수 있다. 82 | 83 | 84 | 단지 모듈에 이렇게 삽입하면 된다 (`shelltools` 처럼 불러온다.) : 85 | 86 | 87 | >>> from shelltools import * 88 | -------------------------------------------------------------------------------- /docs/ko/tutorial/css.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-css: 2 | 3 | 스텝 7: 스타일 추가하기 4 | ==================== 5 | 6 | 이제 모든것들이 작동한다. 이제 약간의 스타일을 어플리케이션에 추가해볼 시간이다. 7 | 전에 생성해 두었던 `static` 폴더에 `style.css` 이라고 불리는 스타일시트를 생성해서 추가해 보자: 8 | 9 | 10 | .. sourcecode:: css 11 | 12 | body { font-family: sans-serif; background: #eee; } 13 | a, h1, h2 { color: #377BA8; } 14 | h1, h2 { font-family: 'Georgia', serif; margin: 0; } 15 | h1 { border-bottom: 2px solid #eee; } 16 | h2 { font-size: 1.2em; } 17 | 18 | .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; 19 | padding: 0.8em; background: white; } 20 | .entries { list-style: none; margin: 0; padding: 0; } 21 | .entries li { margin: 0.8em 1.2em; } 22 | .entries li h2 { margin-left: -1em; } 23 | .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } 24 | .add-entry dl { font-weight: bold; } 25 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 26 | margin-bottom: 1em; background: #fafafa; } 27 | .flash { background: #CEE5F5; padding: 0.5em; 28 | border: 1px solid #AACBE2; } 29 | .error { background: #F0D6D6; padding: 0.5em; } 30 | 31 | 다음 섹션에서 계속 :ref:`tutorial-testing`. 32 | -------------------------------------------------------------------------------- /docs/ko/tutorial/dbcon.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-dbcon: 2 | 3 | 스텝 4: 데이터베이스 커넥션 요청하기 4 | ------------------------------------ 5 | 6 | 이제 우리는 어떻게 데이터베이스 커넥션을 생성할 수 있고 스크립트에서 어떻게 사용되는지 알고 있다. 7 | 하지만 어떻게 하면 좀더 근사하게 커넥션 요청을 할 수 있을까? 8 | 우리는 우리의 모든 함수에서 데이터베이스 커넥션을 필요로 한다. 9 | 그러므로 요청이 오기전에 커넥션을 초기화 하고 사용이 끝난 후 종료시키는 것이 10 | 합리적이다. 11 | 12 | Flask에서는 :meth:`~flask.Flask.before_request` , 13 | :meth:`~flask.Flask.after_request` 그리고 :meth:`~flask.Flask.teardown_request` 14 | 데코레이터(decorators)를 이용할 수 있다.:: 15 | 16 | @app.before_request 17 | def before_request(): 18 | g.db = connect_db() 19 | 20 | @app.teardown_request 21 | def teardown_request(exception): 22 | g.db.close() 23 | 24 | 파라미터가 없는 :meth:`~flask.Flask.before_request` 함수는 리퀘스트가 실행되기 전에 25 | 호출되는 함수이다. :meth:`~flask.Flask.after_request` 함수는 리퀘스트가 실행된 다음에 26 | 호출되는 함수이며 클라이언트에게 전송된 응답(reponse)를 파리미터로 넘겨주어야 한다. 27 | 이 함수들은 반드시 사용된 응답(response)객체 혹은 새로운 응답(respone)객체를 리턴하여야 한다. 28 | 그러나 이 함수들은 예외가 발생할 경우 반드시 실행됨을 보장하지 않는다. 29 | 이 경우 예외상황은 :meth:`~flask.Flask.teardown_request` 으로 전달된다. 30 | 이 함수들은 응답객체가 생성된 후 호출된다. 이 ㅎ마수들은 request객체를 수정할 수 없으며, 31 | 리턴 값들은 무시된다. 만약 리퀘스트가 진행중에 예외사항이 발생 했을 경우 해당 리퀘스트는 32 | 다시 각 함수들에게로 전달되며 그렇지 않을 경우에는 `None` 이 전달된다. 33 | 34 | 35 | 우리는 현재 사용중인 데이터베이스 커넥션을 특별하게 저장한다. 36 | Flask 는 :data:`~flask.g` 라는 특별한 객체를 우리에게 제공한다. 이 객체는 37 | 각 함수들에 대해서 오직 한번의 리퀘스트에 대해서만 유효한 정보를 저장하하고 있다. 38 | 쓰레드환경의 경우 다른 객체에서 위와 같이 사용 할경우 작동이 보장되지 않기 때문에 39 | 결코 사용해서는 안된다. 40 | 41 | 이 특별한 :data:`~flask.g` 객체는 보이지않는 뒷편에서 마법과 같은 어떤일을 수행하여 42 | 쓰레드환경에서도 위와같은 사용이 올바르게 작동하도록 해준다. 43 | 44 | 다음 섹션에서 계속 :ref:`tutorial-views`. 45 | 46 | .. hint:: 어느 곳에 이 소스코드를 위치시켜야 하나요? 47 | 48 | 만얀 당신이 이 튜토리얼을 따라서 여기까지 진행했다면, 아마도 당신은 49 | 이번 스텝과 다음스텝 어디에 코드를 작성해 넣어야 하는지 궁금할 수 있습니다. 50 | 논리적인 위치는 함수들이 함께 그룹핑되는 모듈 레벨의 위치 이고, 51 | 새로 만든 ``before_request`` 와 ``teardown_request`` 함수를 기존의 ``init_db` 52 | 함수 아래에 작성할 수 있다. 53 | (튜토리얼을 따라 한줄씩 작성한다.) 54 | 55 | 만약 현시점에서 각 부분들의 관계를 알고 싶다면, `예제 소스`_ 가 어떻게 56 | 구성되어 있는지 눈여겨 볼 필요가 있다. Flask에서는 하나의 Python 파일에 당신의 57 | 모든 어플리케이션 코드를 다 작성하여 넣는것도 가능하다. 58 | 물론 정말 그렇게 할 필요는 없다. 만약 당신의 어플리케이션이 :ref:`grows larger ` 59 | 점점 커져간다면 이것은 좋은 생각이 아니다. 60 | 61 | .. _예제 소스: 62 | http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ 63 | -------------------------------------------------------------------------------- /docs/ko/tutorial/dbinit.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-dbinit: 2 | 3 | 스텝 3: 데이터베이스 생성하기 4 | ============================= 5 | 6 | Flaskr은 이전에 설명한 대로 데이터베이스를 사용하는 어플리케이션이고 7 | 좀더 정확하게는 관계형 데이터베이스 시스템에 의해 구동되는 어플리케이션이다. 8 | 이러한 시스템은 어떻게 데이터를 저장할지에 대한 정보를 가지고 있는 스키마가 필요하다. 9 | 그래서 처음으로 서버를 실행하기 전에 스키마를 생성하는 것이 중요하다. 10 | 11 | 이러한 스키마는 `schema.sql` 파일을 이용하여 `sqlite3` 명령어를 사용하여 12 | 다음과 같이 만들 수 있다.:: 13 | 14 | sqlite3 /tmp/flaskr.db < schema.sql 15 | 16 | 이방법에서의 단점은 sqlite3 명령어가 필요하다는 점인데, sqlite3 명령어는 모든 17 | 시스템들에서 필수적으로 설치되어 있는 것은 아니기 때문이다. 18 | 한가지 추가적인 문제는 데이터베이스 경로로 제공받은 어떤 경로들은 오류를 발생시킬 수도 있다는 것이다. 19 | 당신의 어플리케이션에 데이터베이스를 초기화 하는 함수를 추가하는 것은 좋은 생각이다. 20 | 21 | 만약 당신이 데이터베이스를 초기화 하는 함수를 추가하기 원한다면 22 | 먼저 contextlib 패키지에 있는 :func:`contextlib.closing` 함수를 import 해야한다. 23 | 만약 Python 2.5를 사용하고 싶다면 먼저 `with` 구문을 추가적으로 사용해야 하다. 24 | (`__future__` 를 반드시 제일 먼저 import 해야 한다.). 25 | 따라서, 다음의 라인들을 기존의 `flaskr.py` 파일에 추가한다. :: 26 | 27 | from __future__ import with_statement 28 | from contextlib import closing 29 | 30 | 다음으로 우리는 데이터베이스를 초기화 시키는 `init_db` 함수를 만들 수 있다. 31 | 이 함수에서 우리는 앞서 정의한 `connect_db` 함수를 사용할 수 있다. 32 | `flaskr.py` 파일의 `connect_db` 함수 아래에 다음의 내용을 추가 하자.:: 33 | 34 | def init_db(): 35 | with closing(connect_db()) as db: 36 | with app.open_resource('schema.sql') as f: 37 | db.cursor().executescript(f.read()) 38 | db.commit() 39 | 40 | 41 | :func:`~contextlib.closing` 함수는 `with` 블럭안에서 연결한 커넥션을 유지하도록 42 | 도와준다. :func:`~flask.Flask.open_resource` 는 어플리케이션 객체의 함수이며 43 | 영역 밖에서도 기능을 지원하며 `with` 블럭에서 직접적으로 사용할 수 있다. 44 | 이 함수를 통해서 리소스 경로(`flaskr` 의 폴더)의 파일을 열고 그 값을 읽을 수 있다. 45 | 우리는 이것을 이용하여 데이터베이스에 연결하는 스크립트를 실행시킬 것이다. 46 | 47 | 우리가 데이터베이스에 연결할 때 우리는 커서를 제공하는 커넥션 객체를 얻는다. 48 | (여기에서는 `db` 라고 부르려고 한다.) 커서에는 전체 스크립트를 실행하는 메소드를 가지고 있다. 49 | 마지막으로, 우리는 변경사항들을 커밋해야 한다. SQLite 3 이다 다른 트랜잭션 데이터베이스들은 50 | 명시적으로 커밋을 하도록 선언하지 않는 이상 진행하지 않는다. 51 | 52 | 이제 Python 쉘에서 다음 함수를 import 하여 실행시키면 데이터베이스 생성이 가능하다.:: 53 | 54 | >>> from flaskr import init_db 55 | >>> init_db() 56 | 57 | .. admonition:: Troubleshooting 58 | 59 | 만약 테이블을 찾을 수 없다는 예외사항이 발생하면 `init_db` 함수를 60 | 호출하였는지 확인하고 테이블 이름이 정확한지 확인하라. 61 | (예를들면 단수형, 복수형과 같은 실수..) 62 | 63 | 다음 섹션에서 계속된다. :ref:`tutorial-dbcon` 64 | -------------------------------------------------------------------------------- /docs/ko/tutorial/folders.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-folders: 2 | 3 | 스텝 0: 폴더를 생성하기 4 | ============================ 5 | 6 | 어플리케이션 개발을 시작하기전에, 어플리케이션에서 사용할 폴더를 만들자 :: 7 | 8 | /flaskr 9 | /static 10 | /templates 11 | 12 | 13 | `flaskr` 폴더는 Python 패키지가 아니다. 단지 우리의 파일들을 저장할 장소이다. 14 | 우리는 이 폴더 안에 데이터베이스 스키마 뿐만 아니라 다른 앞으로 소개될 다른 15 | 스텝에 나오는 주요 모듈들 넣을 곳이다. `static` 폴더 내 파일들은 `HTTP` 를 16 | 통해 어플리케이션 사용자들이 이용할 수 있다. 이 폴더는 css와 javascript 17 | 파일들이 저장되는 곳이다. Flasks는 `templates` 폴더에서 `Jinja2`_ 템플릿을 찾을 것이다 18 | 19 | 20 | 21 | 계속해서 Step 1:데이타베이스 스키마를 보자 :ref:`tutorial-schema`. 22 | 23 | .. _Jinja2: http://jinja.pocoo.org/2/ 24 | -------------------------------------------------------------------------------- /docs/ko/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial: 2 | 3 | 튜토리얼 4 | ======== 5 | 6 | 7 | 파이썬과 Flask로 어플리케이션을 개발하기를 원하는가? 8 | 여기서 예제를 가지고 그것을 배울 기회를 가질 수 있다. 9 | 이 튜토리얼에서는 우리는 간단한 마이크로 블로그 어플리케이션을 개발할 것이다. 10 | 텍스트만 입력가능한 한 명의 사용자만 지원하며 피드백이나 커멘트를 달 수 없다. 11 | 그러나 여러분이 시작하기에 필요한 모든 내용들이 있을 것이다. 12 | 우리는 Flask와 파이썬 범위에서 벗어난 데이타베이스로 SQLite를 사용할 것이다. 13 | 그 밖에 필요한 것들은 없다. 14 | 15 | 만약 여러분이 미리 또는 비교를 위해 모든 소스코드를 원한다면 `example source`_ 를 확인 16 | 하길 바란다. 17 | 18 | 19 | .. _example source: 20 | http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ 21 | 22 | .. toctree:: 23 | :maxdepth: 2 24 | 25 | introduction 26 | folders 27 | schema 28 | setup 29 | dbinit 30 | dbcon 31 | views 32 | templates 33 | css 34 | testing 35 | -------------------------------------------------------------------------------- /docs/ko/tutorial/introduction.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-introduction: 2 | 3 | Flaskr 소개하기 4 | ================== 5 | 6 | 우리는 우리의 블로깅 어플리케이션을 flaskr 이라고 부를 것이다. 7 | 웬지 덜 웹 2.0스러운 이름을 선택해야할 것 같은 느낌에서 자유로워 진것 같다. 8 | 기본적으로 우리는 flaskr을 통해서 다음 사항들을 하기를 원한다: 9 | 10 | 11 | 1.사용자가 지정한 자격증명 설정을 이용하여 로그인/로그아웃을 할 수 있게 한다. 12 | 사용자는 단한명만 지원한다. 13 | 14 | 2.사용자가 로그인하면 사용자는 제목과 내용을 몇몇 HTML과 텍스트로만 입력할 수 있다. 15 | 우리는 사용자를 신뢰하기 때문에 HTML에 대한 위험성 검증은 하지 않는다. 16 | 17 | 3.flaskr 페이지에서는 지금까지 등록된 모든 항목들을 시간의 역순으로 상단에 보여준다 18 | 최근것을 제일 위로)`(최근것을 제일 위로) 로그인한 사용자는 새로 글을 추가 할 수 있다. 19 | 20 | 21 | 이정도 규모의 어플리케이션에서 사용하기에는 SQLite3도 충분한 선택이다. 22 | 그러나 더 큰 규모의 어플리케이션을 위해서는 더 현명한 방법으로 데이타베이스 연결을 23 | 핸들링하고 다른 RDBMS를 사용이 가능한 `SQLAlchemy`_ 를 사용하는 것이 맞다. 24 | 만약 여러분의 데이타가 NoSQL에 더 적합하다면 인기있는 NoSQL 데이타베이스 중 하나를 25 | 고려하기를 원할 수도 있다. 26 | 27 | 아래는 최종 완성된 어플리케이션의 스크린샷이다.: 28 | 29 | .. image:: ../_static/flaskr.png 30 | :align: center 31 | :class: screenshot 32 | :alt: screenshot of the final application 33 | 34 | 계속해서 스텝 0 폴더 생성하기를 보자. :ref:`tutorial-folders`. 35 | 36 | .. _SQLAlchemy: http://www.sqlalchemy.org/ 37 | -------------------------------------------------------------------------------- /docs/ko/tutorial/schema.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-schema: 2 | 3 | 스텝 1: 데이터베이스 스키마 4 | ======================= 5 | 6 | 먼저 우리는 데이터베이스 스키마를 생성해야 한다. 우리의 어플리케이션을 위해서는 7 | 단지 하나의 테이블만 필요하며 사용이 매우 쉬운 SQLite를 지원하기를 원한다. 8 | 다음의 내용을 `schema.sql` 이라는 이름의 파일로 방금 생성한 `flaskr` 폴더에 저장한다. 9 | 10 | 11 | .. sourcecode:: sql 12 | 13 | drop table if exists entries; 14 | create table entries ( 15 | id integer primary key autoincrement, 16 | title string not null, 17 | text string not null 18 | ); 19 | 20 | 이 스키마는 `entries` 라는 이름의 테이블로 구성되어 있으며 이 테이블의 21 | 각 row에는 `id`, `title`, `text` 컬럼으로 구성된다. `id` 는 자동으로 증가되는 22 | 정수이며 프라이머리 키(primary key) 이다. 나머지 두개의 컬럼은 null이 아닌 23 | 문자열(strings) 값을 가져야 한다. 24 | 25 | 26 | 계속해서 Step 2: 어플리케이션 셋업 코드를 보자. :ref:`tutorial-setup`. 27 | -------------------------------------------------------------------------------- /docs/ko/tutorial/setup.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-setup: 2 | 3 | 스텝 2: 어플리케이션 셋업 코드 4 | ============================== 5 | 6 | 이제 우리는 데이터베이스 스키마를 가지고 있고 어플리케이션 모듈을 생성할 수 있다. 7 | 우리가 만들 어플리케이션을 `flaskr` 폴더안에 있는 `flaskr.py` 라고 부르자. 8 | 시작하는 사람들을 위하여 우리는 import가 필요한 모듈 뿐만 아니라 설정 영역도 추가할 것이다. 9 | 소규모 어플리케이션을 위해서는 우리가 여기에서 할 모듈 안에 설정을 직접 추가하는 것이 가능하다. 10 | 그러나 더 깔끔한 해결책은 설정을 `.ini` 또는 `.py` 로 분리하여 생성하여 로드하거나 그 파일로부터 11 | 값들을 import하는 것이다. 12 | 13 | 14 | 아래는 flaskr.py 파일 내용이다: 15 | 16 | 17 | In `flaskr.py`:: 18 | 19 | # all the imports 20 | import sqlite3 21 | from flask import Flask, request, session, g, redirect, url_for, \ 22 | abort, render_template, flash 23 | 24 | # configuration 25 | DATABASE = '/tmp/flaskr.db' 26 | DEBUG = True 27 | SECRET_KEY = 'development key' 28 | USERNAME = 'admin' 29 | PASSWORD = 'default' 30 | 31 | 32 | 다음으로 우리는 우리의 실제 어플리케이션을 생성하고 같은 파일의 설정을 가지고 33 | 어플리케이션을 초기화할 수 있다. `flaskr.py` 내용은 :: 34 | 35 | 36 | # create our little application :) 37 | app = Flask(__name__) 38 | app.config.from_object(__name__) 39 | 40 | :meth:`~flask.Config.from_object` 는 인자로 주어진 객체를 설정값을 읽어 오기 위해 살펴 볼 것이다. 41 | (만약 인자 값이 문자열이면 해당 객체를 임포트 할것이다.) 그리고나서 거기에 정의된 모든 대문자 42 | 변수들을 찾을 것이다. 우리의 경우, 우리가 위에서 몇 줄의 코드로 작성했던 설정이다. 43 | 여러분은 분리된 파일로도 설정값들을 이동시킬 수 있다. 44 | 45 | 일반적으로 설정 파일에서 설정값을 로드하는 것은 좋은 생각이다. 46 | 위에서 사용한 :meth:`~flask.Config.from_object` 대신 :meth:`~flask.Config.from_envvar` 47 | 를 사용하여 설정값을 로드할 수도 있다:: 48 | 49 | app.config.from_envvar('FLASKR_SETTINGS', silent=True) 50 | 51 | 위와 같은 방식으로 환경변수를 호출하여 설정값을 로드할 수도 있다. 52 | :envvar:`FLASKR_SETTINGS` 에 명시된 설정 파일이 로드되면 기본 설정값들은 덮어쓰기가 된다. 53 | silent 스위치는 해당 환경변수가 존재 하지 않아도 Flask가 작동하도록 하는 것이다. 54 | 55 | 클라이언트에서의 세션을 안전하게 보장하기 위해서는 `secret_key` 가 필요하다. 56 | secret_key는 추측이 어렵도록 가능한 복잡하게 선택하여야 한다. 57 | 디버그 플래그는 인터랙ㅌ브 디버거를 활성화 시키거나 비활성화 시키는 일을 한다. 58 | *운영시스템에서는 디버그 모드를 절대로 활성화 시키지 말아야 한다.* 59 | 왜냐하면 디버그 모드에서는 사용자가 서버의 코드를 실행할수가 있기 때문이다. 60 | 61 | 62 | 우리는 또한 명세화된 데이터베이스에 쉽게 접속할 수 있는 방법을 추가할 것이다. 63 | 이방법으로 Python 인터랙티브 쉘이나 스크립트에서 요청에 의해 커넥션을 64 | 얻기위해 사용할 수 있다. 이 방법을 뒤에서 좀더 편리하게 만들어 볼 것이다. 65 | 66 | 67 | :: 68 | 69 | def connect_db(): 70 | return sqlite3.connect(app.config['DATABASE']) 71 | 72 | 마지막으로 우리는 파일의 마지막에 단독 서버로 실행되는 애플리케이션을 위한 73 | 서버 실행 코드를 한줄 추가 하였다.:: 74 | 75 | if __name__ == '__main__': 76 | app.run() 77 | 78 | 여기까지 되어있으면 문제없이 어플리케이션을 시작할 수 있어야 한다. 79 | 다음 명령어로 실행이 가능하다:: 80 | 81 | python flaskr.py 82 | 83 | 서버가 접근가능한 주소로 실행되었다고 알려주는 메시지를 84 | 접할 수 있을 것이다. 85 | 86 | 우리가 아직 아무런 뷰(view)를 만들지 않았기 때문에 브라우저에서는 페이지를 87 | 찾을 수 없다는 404에러를 볼 수 있을 것이다. 이부분에 대해서는 좀 더 후에 88 | 살펴 보도록 할 것이다. 먼저 살펴봐야 할 것은 데이터베이스가 작동되는지 확인하는 것이다. 89 | 90 | 91 | .. admonition:: 외부에서 접근가능한 서버 92 | 93 | 당신의 서버를 외부에 공개하고 싶다면 다음 섹션을 참고 하라 94 | :ref:`externally visible server ` 95 | 96 | Continue with :ref:`tutorial-dbinit`. 97 | -------------------------------------------------------------------------------- /docs/ko/tutorial/testing.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-testing: 2 | 3 | 보너스: 어플리케이션 테스트 하기 4 | ============================== 5 | 6 | 이제 당신은 어플리케이션 개발을 끝마쳤고 모든것들이 예상한대로 작동한다. 7 | 미래에 어플리케이션을 수정하게될 경우를 대비해 테스트를 자동화하는 것은 8 | 나쁜 생각이 아니다. 위에서 소개한 어플리케이션은 유닛테스트를 어떻게 수행하는지에 9 | 대한 기본적인 예제를 가지고 있다. 이 문서의 :ref:`testing` 섹션을 참고하라. 10 | 해당 문서를 살펴보고 어떻게 쉽게 Flask 어플리케이션을 테스트 할 수있는지 알아보자 11 | 12 | -------------------------------------------------------------------------------- /docs/latexindex.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Flask Documentation 4 | =================== 5 | 6 | .. include:: contents.rst.inc 7 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | Flask is licensed under a three clause BSD License. It basically means: 5 | do whatever you want with it as long as the copyright in Flask sticks 6 | around, the conditions are not modified and the disclaimer is present. 7 | Furthermore you must not use the names of the authors to promote derivatives 8 | of the software without written consent. 9 | 10 | The full license text can be found below (:ref:`flask-license`). For the 11 | documentation and artwork different licenses apply. 12 | 13 | .. _authors: 14 | 15 | Authors 16 | ------- 17 | 18 | .. include:: ../../AUTHORS 19 | 20 | General License Definitions 21 | --------------------------- 22 | 23 | The following section contains the full license texts for Flask and the 24 | documentation. 25 | 26 | - "AUTHORS" hereby refers to all the authors listed in the 27 | :ref:`authors` section. 28 | 29 | - The ":ref:`flask-license`" applies to all the sourcecode shipped as 30 | part of Flask (Flask itself as well as the examples and the unittests) 31 | as well as documentation. 32 | 33 | - The ":ref:`artwork-license`" applies to the project's Horn-Logo. 34 | 35 | .. _flask-license: 36 | 37 | Flask License 38 | ------------- 39 | 40 | .. include:: ../../LICENSE 41 | 42 | 43 | .. _artwork-license: 44 | 45 | Flask Artwork License 46 | --------------------- 47 | 48 | .. include:: ../../artwork/LICENSE 49 | -------------------------------------------------------------------------------- /docs/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/docs/logo.pdf -------------------------------------------------------------------------------- /docs/patterns/apierrors.rst: -------------------------------------------------------------------------------- 1 | Implementing API Exceptions 2 | =========================== 3 | 4 | It's very common to implement RESTful APIs on top of Flask. One of the 5 | first thing that developers run into is the realization that the builtin 6 | exceptions are not expressive enough for APIs and that the content type of 7 | ``text/html`` they are emitting is not very useful for API consumers. 8 | 9 | The better solution than using ``abort`` to signal errors for invalid API 10 | usage is to implement your own exception type and install an error handler 11 | for it that produces the errors in the format the user is expecting. 12 | 13 | Simple Exception Class 14 | ---------------------- 15 | 16 | The basic idea is to introduce a new exception that can take a proper 17 | human readable message, a status code for the error and some optional 18 | payload to give more context for the error. 19 | 20 | This is a simple example:: 21 | 22 | from flask import jsonify 23 | 24 | class InvalidUsage(Exception): 25 | status_code = 400 26 | 27 | def __init__(self, message, status_code=None, payload=None): 28 | Exception.__init__(self) 29 | self.message = message 30 | if status_code is not None: 31 | self.status_code = status_code 32 | self.payload = payload 33 | 34 | def to_dict(self): 35 | rv = dict(self.payload or ()) 36 | rv['message'] = self.message 37 | return rv 38 | 39 | A view can now raise that exception with an error message. Additionally 40 | some extra payload can be provided as a dictionary through the `payload` 41 | parameter. 42 | 43 | Registering an Error Handler 44 | ---------------------------- 45 | 46 | At that point views can raise that error, but it would immediately result 47 | in an internal server error. The reason for this is that there is no 48 | handler registered for this error class. That however is easy to add:: 49 | 50 | @app.errorhandler(InvalidAPIUsage) 51 | def handle_invalid_usage(error): 52 | response = jsonify(error.to_dict()) 53 | response.status_code = error.status_code 54 | return response 55 | 56 | Usage in Views 57 | -------------- 58 | 59 | Here is how a view can use that functionality:: 60 | 61 | @app.route('/foo') 62 | def get_foo(): 63 | raise InvalidUsage('This view is gone', status_code=410) 64 | -------------------------------------------------------------------------------- /docs/patterns/appfactories.rst: -------------------------------------------------------------------------------- 1 | .. _app-factories: 2 | 3 | 어플리케이션 팩토리 4 | ===================== 5 | 6 | 여러분이 어플리케이션에 이미 패키지들과 청사진들을 사용한다면(:ref:`blueprints`) 7 | 그 경험들을 좀 더 개선할 몇 가지 정말 좋은 방법들이 있다. 8 | 일반적인 패턴은 청사진을 임포트할 때 어플리케이션 객체를 생성하는 것이다. 9 | 하지만 여러분이 이 객체의 생성을 함수로 옮긴다면, 10 | 나중에 이 객체에 대한 복수 개의 인스턴스를 생성할 수 있다. 11 | 12 | 그래서 여러분은 왜 이렇게 하고 싶은 것인가? 13 | 14 | 1. 테스팅. 여러분은 모든 케이스를 테스트하기 위해 여러 설정을 가진 어플리케이션 인스턴스들을 가질수 있다. 15 | 2. 복수 개의 인스턴스. 여러분이 같은 어플리케이션의 여러 다른 버전을 실행하고 싶다고 가정하자. 16 | 물론 여러분은 여러분은 웹서버에 여러 다른 설정을 가진 복수 개의 인스턴스를 가질 수도 있지만, 17 | 여러분이 팩토리를 사용한다면, 여러분은 간편하게 같은 어플리케이션 프로세스에서 동작하는 18 | 복수 개의 인스턴스를 가질 수 있다. 19 | 20 | 그렇다면 어떻게 여러분은 실제로 그것을 구현할 것인가? 21 | 22 | 기본 팩토리 23 | --------------- 24 | 25 | 이 방식은 함수 안에 어플리케이션을 설정하는 방법이다:: 26 | 27 | def create_app(config_filename): 28 | app = Flask(__name__) 29 | app.config.from_pyfile(config_filename) 30 | 31 | from yourapplication.views.admin import admin 32 | from yourapplication.views.frontend import frontend 33 | app.register_blueprint(admin) 34 | app.register_blueprint(frontend) 35 | 36 | return app 37 | 38 | 이 방식의 단점은 여러분은 임포트하는 시점에 청사진 안에 있는 어플리케이션 객체를 사용할 수 없다. 39 | 그러나 여러분은 요청 안에서 어플리케이션 객체를 사용할 수 있다. 40 | 어떻게 여러분이 설정을 갖고 있는 어플리케이션에 접근하는가? :data:`~flask.current_app` 을 사용하면 된다:: 41 | 42 | from flask import current_app, Blueprint, render_template 43 | admin = Blueprint('admin', __name__, url_prefix='/admin') 44 | 45 | @admin.route('/') 46 | def index(): 47 | return render_template(current_app.config['INDEX_TEMPLATE']) 48 | 49 | 여기에서 우리는 설정에 있는 템플릿 이름을 찾아낸다. 50 | 51 | 어플리케이션(Application) 사용하기 52 | ----------------------------------- 53 | 54 | 그렇다면 그런 어플리케이션을 사용하기 위해서 어려분은 먼저 어플리케이션을 생성해야한다. 55 | 아래는 그런 어플리케이션을 실행하는 `run.py` 파일이다:: 56 | 57 | from yourapplication import create_app 58 | app = create_app('/path/to/config.cfg') 59 | app.run() 60 | 61 | 팩토리 개선 62 | -------------------- 63 | 64 | 위에서 팩토리 함수는 지금까지는 그다지 똑똑하지 않았지만, 여러분은 개선할 수 있다. 65 | 다음 변경들은 간단하고 가능성이 있다: 66 | 67 | 1. 여러분이 파일시스템에 설정 파일을 만들지 않도록 유닛테스트를 위해 설정값을 전달하도록 만들어라. 68 | 2. 여러분이 어플리케이션의 속성들을 변경할 곳을 갖기 위해 어플리케이션이 셋업될 때 청사진에서 함수를 호출해라. 69 | (요청 핸들러의 앞/뒤로 가로채는 것 처럼) 70 | 3. 필요하다면 어플리케이션이 생성될 때, WSGI 미들웨어에 추가해라. 71 | -------------------------------------------------------------------------------- /docs/patterns/caching.rst: -------------------------------------------------------------------------------- 1 | .. _caching-pattern: 2 | 3 | 캐싱(Caching) 4 | ============= 5 | 6 | 여러분의 어플리케이션이 느린 경우, 일종의 캐시를 넣어보라. 그것이 7 | 속도를 높이는 최소한의 가장 쉬운 방법이다. 캐시가 무엇을 하는가? 8 | 여러분이 수행을 마치는데 꽤 시간이 걸리는 함수를 갖고 있지만 결과가 9 | 실시간이 아닌 5분이 지난 결과도 괜찮다고 하자. 그렇다면 여러분은 10 | 그 시간동안 결과를 캐시에 넣어두고 사용해도 좋다는게 여기의 생각이다. 11 | 12 | 플라스크 그 자체는 캐시를 제공하지 않지만, 플라스크의 토대가 되는 13 | 라이브러중 하나인 벡자이크(Werkzeug)는 굉장히 기본적인 캐시를 지원한다. 14 | 보통은 여러분이 memchached 서버로 사용하고 싶은 15 | 다중 캐시 백엔드를 지원한다. 16 | 17 | 캐시 설정하기 18 | ------------- 19 | 20 | 여러분은 :class:`~flask.Flask` 을 생성하는 방법과 유사하게 캐시 객체를 21 | 일단 생성하고 유지한다. 여러분이 개발 서버를 사용하고 있다면 여러분은 22 | :class:`~werkzeug.contrib.cache.SimpleCache` 객체를 생성할 수 있고, 23 | 그 객체는 파이썬 인터프리터의 메모리에 캐시의 항목을 저장하는 간단한 캐시다:: 24 | 25 | from werkzeug.contrib.cache import SimpleCache 26 | cache = SimpleCache() 27 | 28 | 여러분이 memcached를 사용하고 싶다면, 지원되는 memcache 모듈중 하나를 갖고 29 | (`PyPI `_ 에서 얻음) 어디선가 memcached 서버가 30 | 동작하는 것을 보장해라. 그리고 나면 아래의 방식으로 memcached 서버에 31 | 연결하면 된다:: 32 | 33 | from werkzeug.contrib.cache import MemcachedCache 34 | cache = MemcachedCache(['127.0.0.1:11211']) 35 | 36 | 여러분이 App 엔진을 사용한다면, 손쉽게 App 엔진 ememcache 서버에 연결할 37 | 수 있다:: 38 | 39 | from werkzeug.contrib.cache import GAEMemcachedCache 40 | cache = GAEMemcachedCache() 41 | 42 | 캐시 사용하기 43 | ------------- 44 | 45 | 캐시는 어떻게 사용할 수 있을까? 두가지 굉장히 중요한 함수가 있다: 46 | :meth:`~werkzeug.contrib.cache.BaseCache.get` 과 47 | :meth:`~werkzeug.contrib.cache.BaseCache.set` 이다. 아래는 사용 방법이다: 48 | 49 | 캐시에서 항목을 얻기 위해서는 문자열로 된 키 명으로 50 | :meth:`~werkzeug.contrib.cache.BaseCache.get` 를 호출하면 된다. 캐시에 그 키에 51 | 값이 있따면, 그 값이 반환된다. 없다면 `None`이 반환될 것이다:: 52 | 53 | rv = cache.get('my-item') 54 | 55 | 캐시에 항목을 넣기 위해서는, :meth:`~werkzeug.contrib.cache.BaseCache.set` 를 56 | 사용하면 된다. 첫번째 인자는 키이고 두번째는 설정할 값이다. 타임아웃 또한 57 | 항목으로 넣을 수가 있는데 그 시간이 지나면 캐시에서 자동으로 그 항목은 삭제된다. 58 | 59 | 아래는 보통 정상적으로 사용되는 전체 예제이다:: 60 | 61 | def get_my_item(): 62 | rv = cache.get('my-item') 63 | if rv is None: 64 | rv = calculate_value() 65 | cache.set('my-item', rv, timeout=5 * 60) 66 | return rv 67 | -------------------------------------------------------------------------------- /docs/patterns/deferredcallbacks.rst: -------------------------------------------------------------------------------- 1 | .. _deferred-callbacks: 2 | 3 | 지연된(deferred) 요청 콜백 4 | ========================== 5 | 6 | 플라스크의 설계 원칙 중 한가지는 응답 객체가 생성되고 그 객체를 수정하거나 7 | 대체할 수 있는 잠재적인 콜백의 호출 사슬로 그 객체를 전달하는 것이다. 8 | 요청 처리가 시작될 때, 아직은 응답 객체를 존재하지 않는다. 뷰 함수나 9 | 시스템에 있는 어떤 다른 컴포넌트에 의해 필요할 때 생성된다. 10 | 11 | 하지만 응답이 아직 존재하지 않는 시점에서 응답을 수정하려 하면 어떻게 되는가? 12 | 그에 대한 일반적인 예제는 응답 객체에 있는 쿠키를 설정하기를 원하는 13 | before-request 함수에서 발생할 것이다. 14 | 15 | 한가지 방법은 그런 상황을 피하는 것이다. 꽤 자주 이렇게 하는게 가능하다. 16 | 예를 들면 여러분은 그런 로직을 after-request 콜백으로 대신 옮기도록 17 | 시도할 수 있다. 하지만 때때로 거기에 있는 코드를 옮기는 것은 유쾌한 18 | 일이 아니거나 코드가 대단히 부자연스럽게 보이게 된다. 19 | 20 | 다른 가능성으로서 여러분은 :data:`~flask.g` 객체에 여러 콜백 함수를 21 | 추가하고 요청의 끝부분에서 그것을 호출할 수 있다. 이 방식으로 여러분은 22 | 어플리케이션의 어느 위치로도 코드 실행을 지연시킬 수 있다. 23 | 24 | 25 | 데코레이터 26 | ---------- 27 | 28 | 다음에 나올 데코레이터가 핵심이다. 그 데코레이터는 :data:`~flask.g` 객체에 29 | 있는 리스트에 함수를 등록한다:: 30 | 31 | from flask import g 32 | 33 | def after_this_request(f): 34 | if not hasattr(g, 'after_request_callbacks'): 35 | g.after_request_callbacks = [] 36 | g.after_request_callbacks.append(f) 37 | return f 38 | 39 | 40 | 지연된 함수의 호출 41 | ------------------ 42 | 43 | 이제 여러분은 요청의 마지막에서 호출될 함수를 표시하기 위해 `after_this_request` 44 | 데코레이터를 사용할 수 있다. 하지만 우리는 여전히 그 함수를 호출할 수도 있다. 45 | 이렇게 하기 위해 다음 함수가 :meth:`~flask.Flask.after_request` 콜백으로 등록될 46 | 필요가 있다:: 47 | 48 | @app.after_request 49 | def call_after_request_callbacks(response): 50 | for callback in getattr(g, 'after_request_callbacks', ()): 51 | response = callback(response) 52 | return response 53 | 54 | 55 | 실제적인 예제 56 | ------------- 57 | 58 | 이제 우리는 이 특정 요청의 마지막에서 호출될 함수를 적절한 어느 시점에라도 59 | 쉽게 등록할 수 있다. 예를 들면 여러분은 before-request 함수에서 쿠키에 사용자의 60 | 현재 언어를 기억하게 할 수 있다:: 61 | 62 | from flask import request 63 | 64 | @app.before_request 65 | def detect_user_language(): 66 | language = request.cookies.get('user_lang') 67 | if language is None: 68 | language = guess_language_from_request() 69 | @after_this_request 70 | def remember_language(response): 71 | response.set_cookie('user_lang', language) 72 | g.language = language 73 | -------------------------------------------------------------------------------- /docs/patterns/errorpages.rst: -------------------------------------------------------------------------------- 1 | 커스텀 오류 페이지 2 | ================== 3 | 4 | 플라스크에는 앞에서 나온 HTTP 오류 코드를 가지고 요청을 중단하는 5 | :func:`~flask.abort` 함수가 있다. 그것은 또한 정말 꾸미지 않은 기본적인 6 | 설명을 가진 단순한 흑백의 오류 페이지를 제공할 것이다. 7 | 8 | 오류 코드에 따라서 사용자가 실제로 그런 오류를 볼 가능성이 있다. 9 | 10 | 공통 오류 코드 11 | -------------- 12 | 13 | 다음의 오류 코드는 어플리케이션이 정상적으로 동작했음에도 불구하고 사용자에게 14 | 종종 보여지는 것이다: 15 | 16 | *404 Not Found* 17 | 즐겨쓰는 메시지에 "이봐 친구, 그 URL 입력에 실수가 있어" 가 있다. 18 | 인터넷 초보자 조차 그 404를 알고 있는 그렇게 일반적인 것은 다음을 19 | 의미한다 : 젠장, 내가 찾고 있는 것이 거기에 없네. 404 페이지에 20 | 적어도 index 페이지로 돌아갈 수 있는 링크와 같은 유용한 것이 있도록 21 | 하는게 매우 좋은 방식이다. 22 | 23 | *403 Forbidden* 24 | 여러분의 웹사이트에 어떤 접근 제어가 있다면, 허용되지 않는 자원에 대해 25 | 403 코드를 보내야할 것이다. 그렇기 때문에 사용자가 금지된 자원에 대해 26 | 접근하려할 때 사용자가 링크를 잃어버리지 않도록 해야한다. 27 | 28 | *410 Gone* 29 | 여러분은 "404 Not Found" 에게 "410 Gone" 이라는 형제가 있었다는 것을 30 | 알았는가? 일부 사람들만 실제로 그것을 구현했지만, 그 방식은 전에 31 | 존재했지만 현재 삭제된 자원에 대해 404 대신에 401 로 응답하는 것이다. 32 | 여러분이 데이터베이스에서 영구적으로 문서를 지우지 않고 삭제됐다고 33 | 표시만 한다면, 사용자에게 편의를 제공하며 410 코드를 대신 사용하고 34 | 그들이 찾고 있는 것은 영구적으로 삭제됐다는 메시지를 보여줘라. 35 | 36 | *500 Internal Server Error* 37 | 보통 프로그래밍 오류나 서버에 한계 부하를 넘었을 때 이 오류가 발생한다. 38 | 그 경우에 멋진 페이지를 보여주는 것이 굉장히 좋은 방식인데, 왜냐하면 39 | 여러분의 어플리케이션은 머지않아 다시 동작하지 않을 것이기 때문이다 40 | (여기를 또한 살펴봐라: :ref:`application-errors`). 41 | 42 | 43 | 오류 핸들러 44 | ----------- 45 | 46 | 오류 핸들러는 뷰 함수와 같은 일종의 함수이지만, 그것은 오류가 발생하고 47 | 그 오류를 전달했을 때 호출된다. 오류는 대부분 48 | :exc:`~werkzeug.exceptions.HTTPException` 이지만, 어떤 경우에는 다른 49 | 오류일 수도 있다: 내부 서버 오류에 대한 핸들러는 그 요류들이 잡히지 않을지 50 | 모르지만 다른 예외 인스턴스에 넘겨질 것이다. 51 | 52 | 오류 핸들러는 :meth:`~flask.Flask.errorhandler` 데코레이터와 예외에 대한 53 | 오류 코드를 가지고 등록된다. 플라스크는 오류 코드를 설정하지 *않을 것* 54 | 이라는 것을 명심하고, 그렇기 때문에 응답을 반환할 때 HTTP 상태 코드를 55 | 제공하도록 해야한다. 56 | 57 | 여기에 "404 Page Not Found" 예외에 대한 구현 예제가 있다:: 58 | 59 | from flask import render_template 60 | 61 | @app.errorhandler(404) 62 | def page_not_found(e): 63 | return render_template('404.html'), 404 64 | 65 | 예제 템플릿은 다음과 같을 것이다: 66 | 67 | .. sourcecode:: html+jinja 68 | 69 | {% extends "layout.html" %} 70 | {% block title %}Page Not Found{% endblock %} 71 | {% block body %} 72 |

Page Not Found

73 |

What you were looking for is just not there. 74 |

go somewhere nice 75 | {% endblock %} 76 | -------------------------------------------------------------------------------- /docs/patterns/favicon.rst: -------------------------------------------------------------------------------- 1 | 파비콘 추가하기 2 | =============== 3 | 4 | "파비콘(favicon)"은 탭이나 북마크를 위해 브라우저에서 사용되는 아이콘이다. 5 | 이 아이콘은 여러분의 웹사이트를 구분하는데 도움을 주고 그 사이트에 유일한 6 | 표식을 준다. 7 | 8 | 일반적인 질문은 플라스크 어플리케이션에 어떻게 파이콘을 추가하는가 이다. 9 | 물론 제일 먼저 파이콘이 필요하다. 16 × 16 픽셀과 ICO 파일 형태이어야 한다. 10 | 이것은 전제사항은 아니지만 그 형태가 모든 브라우저에서 지원하는 업계 표준이다. 11 | 여러분의 static 디렉토리에 그 아이콘을 :file:`favicon.ico` 파일명으로 넣는다. 12 | 13 | 자, 그 아이콘을 브라우저에서 찾으려면, 여러분의 HTML에 link 태그를 추가하는게 14 | 알맞은 방법이다. 그래서 예를 들면: 15 | 16 | .. sourcecode:: html+jinja 17 | 18 | 19 | 20 | 대부분의 브라우저에서는 위의 한줄이 여러분이 해줄 전부이지만, 몇몇 예전 브라우저는 21 | 이 표준을 지원하지 않는다. 예전 업계 표준은 웹사이트의 루트에 그 파일을 위치시켜 22 | 제공하는 것이다. 여러분의 어플리케이션이 해당 도메인의 루트 경로에 마운트되지 23 | 않았다면 루트에서 그 아이콘이 제공되도록 웹서버 설정이 필요하므로 그렇게 할 수 24 | 없다면 여러분은 운이 없는 것이다. 그러나 어프리케이션이 루트에 있다면 여러분은 25 | 리디렉션으로 간단히 경로를 찾게할 수 있다:: 26 | 27 | app.add_url_rule('/favicon.ico', 28 | redirect_to=url_for('static', filename='favicon.ico')) 29 | 30 | 여러분이 추가적인 리디렉션 요청을 저장하고 싶다면 :func:`~flask.send_from_directory` 31 | 를 사용한 뷰 함수 또한 작성할 수 있다:: 32 | 33 | import os 34 | from flask import send_from_directory 35 | 36 | @app.route('/favicon.ico') 37 | def favicon(): 38 | return send_from_directory(os.path.join(app.root_path, 'static'), 39 | 'favicon.ico', mimetype='image/vnd.microsoft.icon') 40 | 41 | 명시적인 마임타입(mimetype)을 생략할 수 있고 그 타입은 추측될 것이지만, 그것은 42 | 항상 같게 추측될 것이므로 추가적인 추측을 피하기 위해 타입을 지정하는 것이 좋다. 43 | 44 | 위의 예는 어플리케이션을 통해 아이콘을 제공할 것이고 가능하다면 웹서버 문서를 45 | 참고하여 그렇게 할 전담 웹서버를 구성하는 것이 더 좋다. 46 | 47 | 추가로 볼 내용 48 | -------------- 49 | 50 | * 위키피디아(Wikipedia)의 `파비콘 `_ 기사 51 | -------------------------------------------------------------------------------- /docs/patterns/index.rst: -------------------------------------------------------------------------------- 1 | .. _patterns: 2 | 3 | Flask를 위한 패턴들 4 | ====================== 5 | 6 | 어떤 것들은 충분히 일반적이어서 여러분이 대부분의 웹 어플리케이션에서 찾을 가능성이 높다. 예를 들면 많은 어플리케이션들이 관계형 데이타베이스와 사용자 인증을 사용한다. 그 경우에, 그 어플리케이션들은 요청 초반에 데이타베이스 연결을 열고 사용자 테이블에서 현재 로그인된 사용자의 정보를 얻을 것이다. 요청의 마지막에는 그 데이타베이스 연결을 다시 닫는다. 7 | 8 | `플라스크 스니핏 묶음(Flask Snippet Archives) `_ 에 많은 사용자들이 기여한 스니핏과 패턴들이 있다. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | packages 14 | appfactories 15 | appdispatch 16 | urlprocessors 17 | distribute 18 | fabric 19 | sqlite3 20 | sqlalchemy 21 | fileuploads 22 | caching 23 | viewdecorators 24 | wtforms 25 | templateinheritance 26 | flashing 27 | jquery 28 | errorpages 29 | lazyloading 30 | mongokit 31 | favicon 32 | streaming 33 | deferredcallbacks 34 | methodoverrides 35 | requestchecksum 36 | -------------------------------------------------------------------------------- /docs/patterns/methodoverrides.rst: -------------------------------------------------------------------------------- 1 | HTTP 메소드 오버라이드 추가하기 2 | =============================== 3 | 4 | 어떤 HTTP 프록시는 임시적인 HTTP 메소드나 새로운 HTTP 메소드 (PATCH 같은) 5 | 를 지원하지 않는다. 그런 경우에 프로토콜 전체를 위반하는 방식으로 6 | HTTP 메소드를 다른 HTTP 메소드로 "프록시" 하는 것이 가능하다. 7 | 8 | 이렇게 동작하는 방식은 클라이언트가 HTTP POST로 요청하고 9 | ``X-HTTP-Method-Override`` 헤더를 설정하고 그 값으로 의도하는 HTTP 메소드 10 | (``PATCH`` 와 같은)를 설정하면 된다. 11 | 12 | 이것은 HTTP 미들웨어로 쉽게 수행할 수 있다:: 13 | 14 | class HTTPMethodOverrideMiddleware(object): 15 | allowed_methods = frozenset([ 16 | 'GET', 17 | 'HEAD', 18 | 'POST', 19 | 'DELETE', 20 | 'PUT', 21 | 'PATCH', 22 | 'OPTIONS' 23 | ]) 24 | bodyless_methods = frozenset(['GET', 'HEAD', 'OPTIONS', 'DELETE']) 25 | 26 | def __init__(self, app): 27 | self.app = app 28 | 29 | def __call__(self, environ, start_response): 30 | method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper() 31 | if method in self.allowed_methods: 32 | method = method.encode('ascii', 'replace') 33 | environ['REQUEST_METHOD'] = method 34 | if method in self.bodyless_methods: 35 | environ['CONTENT_LENGTH'] = '0' 36 | return self.app(environ, start_response) 37 | 38 | 플라스크로 이것을 하려면 아래와 같이 하면 된다:: 39 | 40 | from flask import Flask 41 | 42 | app = Flask(__name__) 43 | app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app) 44 | -------------------------------------------------------------------------------- /docs/patterns/requestchecksum.rst: -------------------------------------------------------------------------------- 1 | 요청한 내용에 대한 체크섬 2 | ========================= 3 | 4 | 코드의 여러 부분이 요청 데이터로 5 | Various pieces of code can consume the request data and preprocess it. 6 | For instance JSON data ends up on the request object already read and 7 | processed, form data ends up there as well but goes through a different 8 | code path. This seems inconvenient when you want to calculate the 9 | checksum of the incoming request data. This is necessary sometimes for 10 | some APIs. 11 | 12 | Fortunately this is however very simple to change by wrapping the input 13 | stream. 14 | 15 | The following example calculates the SHA1 checksum of the incoming data as 16 | it gets read and stores it in the WSGI environment:: 17 | 18 | import hashlib 19 | 20 | class ChecksumCalcStream(object): 21 | 22 | def __init__(self, stream): 23 | self._stream = stream 24 | self._hash = hashlib.sha1() 25 | 26 | def read(self, bytes): 27 | rv = self._stream.read(bytes) 28 | self._hash.update(rv) 29 | return rv 30 | 31 | def readline(self, size_hint): 32 | rv = self._stream.readline(size_hint) 33 | self._hash.update(rv) 34 | return rv 35 | 36 | def generate_checksum(request): 37 | env = request.environ 38 | stream = ChecksumCalcStream(env['wsgi.input']) 39 | env['wsgi.input'] = stream 40 | return stream._hash 41 | 42 | To use this, all you need to do is to hook the calculating stream in 43 | before the request starts consuming data. (Eg: be careful accessing 44 | ``request.form`` or anything of that nature. ``before_request_handlers`` 45 | for instance should be careful not to access it). 46 | 47 | Example usage:: 48 | 49 | @app.route('/special-api', methods=['POST']) 50 | def special_api(): 51 | hash = generate_checksum(request) 52 | # Accessing this parses the input stream 53 | files = request.files 54 | # At this point the hash is fully constructed. 55 | checksum = hash.hexdigest() 56 | return 'Hash was: %s' % checksum 57 | -------------------------------------------------------------------------------- /docs/patterns/streaming.rst: -------------------------------------------------------------------------------- 1 | 컨텐트 스트리밍하기 2 | ===================== 3 | 4 | 종종 여러분은 클라이언트로 메모리에 유지하고 싶은 양보다 훨씬 더 큰, 5 | 엄청난 양의 데이터를 전송하기를 원한다. 여러분이 그 데이터를 바로 생성하고 6 | 있을 때, 파일시스템으로 갔다오지 않고 어떻게 클라이언트로 그것을 전송하는가? 7 | 8 | 답은 바로 생성기(generators)와 직접 응답이다. 9 | 10 | 기본 사용법 11 | ----------- 12 | 13 | 이것은 많은 CSV 데이터를 즉각 생성하는 기초적인 뷰 함수이다. 데이터를 생성하는 14 | 생성기를 사용하는 내부(inner) 함수를 갖고 그 함수를 호출하면서 응답 객체에 15 | 그 함수를 넘기는것이 그 기법이다:: 16 | 17 | from flask import Response 18 | 19 | @app.route('/large.csv') 20 | def generate_large_csv(): 21 | def generate(): 22 | for row in iter_all_rows(): 23 | yield ','.join(row) + '\n' 24 | return Response(generate(), mimetype='text/csv') 25 | 26 | 각 ``yield`` 표현식은 브라우져에 직접 전송된다. 어떤 WSGI 미들웨어는 27 | 스트리밍을 깰수도 있지만, 프로파일러를 가진 디버그 환경과 여러분이 활성화 28 | 시킨 다른 것들을 조심하도록 유의하라. 29 | 30 | 템플릿에서 스트리밍 31 | ------------------- 32 | 33 | 진자2 템플릿 엔진은 또한 부분 단위로 템플릿을 뿌려주는 것을 지원한다. 이 기능은 34 | 꽤 일반적이지 않기 때문에 플라스크에 직접적으로 노출되지 않지만, 아래처럼 여러분이 35 | 쉽게 직접 구현할 수 있다:: 36 | 37 | from flask import Response 38 | 39 | def stream_template(template_name, **context): 40 | app.update_template_context(context) 41 | t = app.jinja_env.get_template(template_name) 42 | rv = t.stream(context) 43 | rv.enable_buffering(5) 44 | return rv 45 | 46 | @app.route('/my-large-page.html') 47 | def render_large_template(): 48 | rows = iter_all_rows() 49 | return Response(stream_template('the_template.html', rows=rows)) 50 | 51 | 여기서의 기법은 어플리케이션의 진자2 환경에서 템플릿 객체를 얻고 문자열 대신 52 | 스트림 객체를 반환하는 :meth:`~jinja2.Template.render` 대신 53 | :meth:`~jinja2.Template.stream` 를 호출하는 것이다. 플라스크 템플릿 렌더 함수를 54 | 지나치고 템플릿 객체 자체를 사용하고 있기 때문에 55 | :meth:`~flask.Flask.update_template_context` 를 호출하여 렌더 컨텍스트를 갱신하도록 56 | 보장해야한다. 그리고 나서 스트림을 순환하면서 템플릿을 해석한다. 매번 여러분은 yield 57 | 를 호출하기 때문에 서버는 클라이언트로 내용을 밀어내어 보낼 것이고 여러분은 58 | ``rv.enable_buffering(size)`` 을 가지고 템플릿 안에 몇가지 항목을 버퍼링하기를 원할지도 59 | 모른다. ``5`` 가 보통 기본값이다. 60 | 61 | 컨텍스트를 가진 스트리밍 62 | ------------------------ 63 | 64 | .. versionadded:: 0.9 65 | 66 | 여러분이 데이터를 스트리밍할 때, 요청 컨텍스트는 그 함수가 호출된 순간 이미 67 | 종료된다는 것에 주목해라. 플라스크 0.9 는 생성기가 수행하는 동안 요청 컨텍스트를 68 | 유지하게 해주는 조력자를 제공한다:: 69 | 70 | from flask import stream_with_context, request, Response 71 | 72 | @app.route('/stream') 73 | def streamed_response(): 74 | def generate(): 75 | yield 'Hello ' 76 | yield request.args['name'] 77 | yield '!' 78 | return Response(stream_with_context(generate())) 79 | 80 | 81 | :func:`~flask.stream_with_context` 함수 없다면 여러분은 그 시점에 :class:`RuntimeError` 82 | 를 얻을 것이다. 83 | -------------------------------------------------------------------------------- /docs/patterns/templateinheritance.rst: -------------------------------------------------------------------------------- 1 | .. _template-inheritance: 2 | 3 | 템플릿 상속 4 | =========== 5 | 6 | 진자(Jinja)의 가장 강력한 부분은 템플릿 상속 기능이다. 템플릿 상속은 여러분의 사이트에 7 | 대한 모든 일반적인 요소들을 포함한 기본 "스켈레톤(skeleton)" 템플릿을 생성하도록 하고 8 | 자식 템플릿은 기본 템플릿을 오버라이드(override)할 수 있는 **blocks** 을 정의한다. 9 | 10 | 복잡해 보이지만 꽤 간단하다. 예제로 시작하는게 이해하는데 가장 쉽다. 11 | 12 | 13 | 기본 템플릿 14 | ----------- 15 | 16 | 우리가 ``layout.html`` 이라 부를 이 팀플릿은 간단한 두개의 칼럼을 가진 페이지로 17 | 사용할 간단한 HTML 스켈레톤 문서를 정의한다. 내용의 빈 블럭을 채우것이 "자식" 18 | 템플릿의 일이다: 19 | 20 | .. sourcecode:: html+jinja 21 | 22 | 23 | 24 | 25 | {% block head %} 26 | 27 | {% block title %}{% endblock %} - My Webpage 28 | {% endblock %} 29 | 30 | 31 |

{% block content %}{% endblock %}
32 | 37 | 38 | 39 | 이 예제에서, ``{% block %}`` 태그는 자식 템플릿이 채울 수 있는 네개의 블럭을 40 | 정의한다. `block` 태그가 하는 전부는 템플릿 엔진에 자식 템플릿이 템플릿의 `block` 41 | 태그를 오버라이드할 수 도 있다라고 알려준다. 42 | 43 | 자식 템플릿 44 | ----------- 45 | 46 | 자식 템플릿은 아래와 같이 보일 수도 있다: 47 | 48 | .. sourcecode:: html+jinja 49 | 50 | {% extends "layout.html" %} 51 | {% block title %}Index{% endblock %} 52 | {% block head %} 53 | {{ super() }} 54 | 57 | {% endblock %} 58 | {% block content %} 59 |

Index

60 |

61 | Welcome on my awesome homepage. 62 | {% endblock %} 63 | 64 | ``{% extends %}`` 태그가 여기서 핵심이다. 이 태그는 템플릿 엔진에게 이 템플릿이 65 | 다른 템플릿을 "확장(extends)" 한다라고 알려준다. 템플릿 시스템이 이 템플릿을 66 | 검증할 때, 가장 먼저 부모 템플릿을 찾는다. 그 확장 태그가 템플릿에서 가장 먼저 67 | 있어야 한다. 부모 템플릿에 정의된 블럭의 내용을 보여주려면 ``{{ super() }}`` 를 68 | 사용하면 된다. 69 | -------------------------------------------------------------------------------- /docs/python3.rst: -------------------------------------------------------------------------------- 1 | .. _python3-support: 2 | 3 | Python 3 Support 4 | ================ 5 | 6 | Flask and all of its dependencies support Python 3 so you can in theory 7 | start working on it already. There are however a few things you should be 8 | aware of before you start using Python 3 for your next project. 9 | 10 | Requirements 11 | ------------ 12 | 13 | If you want to use Flask with Python 3 you will need to use Python 3.3 or 14 | higher. 3.2 and older are *not* supported. 15 | 16 | In addition to that you need to use the latest and greatest versions of 17 | `itsdangerous`, `Jinja2` and `Werkzeug`. 18 | 19 | API Stability 20 | ------------- 21 | 22 | Some of the decisions made in regards to unicode and byte untilization on 23 | Python 3 make it hard to write low level code. This mainly affects WSGI 24 | middlewares and interacting with the WSGI provided information. Werkzeug 25 | wraps all that information in high-level helpers but some of those were 26 | specifically added for the Python 3 support and are quite new. 27 | 28 | A lot of the documentation out there on using WSGI leaves out those 29 | details as it was written before WSGI was updated to Python 3. While the 30 | API for Werkzeug and Flask on Python 2.x should not change much we cannot 31 | guarantee that this won't happen on Python 3. 32 | 33 | Few Users 34 | --------- 35 | 36 | Python 3 currently has less than 1% of the users of Python 2 going by PyPI 37 | download stats. As a result many of the problems you will encounter are 38 | probably hard to search for on the internet if they are Python 3 specific. 39 | 40 | Small Ecosystem 41 | --------------- 42 | 43 | The majority of the Flask extensions, all of the documentation and the 44 | vast majority of the PyPI provided libraries do not support Python 3 yet. 45 | Even if you start your project with knowing that all you will need is 46 | supported by Python 3 you don't know what happens six months from now. If 47 | you are adventurous you can start porting libraries on your own, but that 48 | is nothing for the faint of heart. 49 | 50 | Recommendations 51 | --------------- 52 | 53 | Unless you are already familiar with the differences in the versions we 54 | recommend sticking to current versions of Python until the ecosystem 55 | caught up. 56 | 57 | The majority of the upgrade pain is in the lower-level libararies like 58 | Flask and Werkzeug and not in the actual high-level application code. For 59 | instance all of the Flask examples that are in the Flask repository work 60 | out of the box on both 2.x and 3.x and did not require a single line of 61 | code changed. 62 | -------------------------------------------------------------------------------- /docs/shell.rst: -------------------------------------------------------------------------------- 1 | .. _shell: 2 | 3 | 쉘에서 작업하기 4 | ====================== 5 | 6 | .. versionadded:: 0.3 7 | 8 | 많은 사람들이 파이썬을 좋아하는 이유 중 한가지는 바로 대화식 쉘이다. 9 | 그것은 기본적으로 여러분이 실시간으로 파이썬 명령을 싱행하고 결과를 실시간으로 10 | 즉시 받아 볼 수 있다. Flask 자체는 대화식 쉘과 함께 제공되지 않는다. 왜냐하면 11 | Flask는 특정한 선행 작업이 필요하지 않고, 단지 여러분의 어플리케이션에서 불러오기만 하면 12 | 시작할 수 있기 때문이다. 13 | 14 | 15 | 하지만, 쉘에서 좀 더 많은 즐거운 경험을 얻을 수 있는 몇 가지 유용한 헬퍼들이 있다. 16 | 대화식 콘솔 세션에서의 가장 중요한 문제는 여러분이 직접 브라우저에서 처럼 :data:`~flask.g`, :data:`~flask.request` 를 발생 시킬 수 없고, 그 밖의 다른 것들도 가능하지 않다. 하지만 테스트 해야 할 코드가 그것들에게 종속관계에 있다면 여러분은 어떻게 할 것인가? 17 | 18 | 19 | 이 장에는 몇가지 도움이 되는 함수가 있다. 20 | 이 함수들은 대화식 쉘에서의 사용뿐만 아니라, 단위테스트와 같은 그리고 요청 컨텍스트를 21 | 위조해야 하는 상황에서 또한 유용하다는 것을 염두해 두자. 22 | 23 | 24 | 일반적으로 여러분이 :ref:`request-context` 를 먼저 읽기를 권장한다. 25 | 26 | 27 | 요청 컨텍스트 생성하기 28 | -------------------------- 29 | 30 | 쉘에서 적절한 요청 컨텍스트를 생성하는 가장 쉬운 방법은 :class:`~flask.ctx.RequestContext`: 를 우리에게 생성해주는 :attr:`~flask.Flask.test_request_context` 메소드를 사용하는 것이다.: 31 | 32 | >>> ctx = app.test_request_context() 33 | 34 | 일반적으로 여러분은 `with` 구문을 사용하여 이 요청 객체를 활성화 하겠지만, 35 | 쉘에서는 :meth:`~flask.ctx.RequestContext.push` 와 :meth:`~flask.ctx.RequestContext.pop` 를 36 | 직접 다루는 방법이 더 쉽다: 37 | 38 | 39 | >>> ctx.push() 40 | 41 | 여러분이 `pop` 을 호출하는 그 시점까지 request 객체를 사용하여 작업 할 수 있다. 42 | : 43 | 44 | >>> ctx.pop() 45 | 46 | 47 | 48 | 요청하기 전/후에 발사하기(Firing) 49 | --------------------------- 50 | 51 | 단지 요청 컨텍스트를 생성만 하면, 일반적으로 요청전에 실행되는 코드를 실행할 필요가 없다. 52 | 이것은 만약 여러분이 before-request 콜백에서 데이터베이스 연결을 하거나 , 혹은 현재 사용자가 :data:`~flask.g` 객체에 저장하지 않을 경우에 발생할 수 있다.. 53 | 54 | 그러나 이것은 단지 :meth:`~flask.Flask.preprocess_request` 를 호출하여 쉽게 수행 할 수 있다: 55 | 56 | >>> ctx = app.test_request_context() 57 | >>> ctx.push() 58 | >>> app.preprocess_request() 59 | 60 | 다음을 염두 해 두어야 한다. 61 | 이 경우에 :meth:`~flask.Flask.preprocess_request` 함수는 응답(response) 객체를 리턴할 것이고, 이것은 그냥 무시해도 된다. 62 | 63 | 64 | 요청을 종료시키기 위해서, 여러분은 사후 요청 함수 ( :meth:`~flask.Flask.process_response` 에 의해 트리거되는)가 응답 객체에서 사용 전에 약간의 트릭을 사용해야 한다: 65 | 66 | >>> app.process_response(app.response_class()) 67 | 68 | >>> ctx.pop() 69 | 70 | 컨텍스트가 열리게 되면 :meth:`~flask.Flask.teardown_request` 로 등록된 함수가 71 | 자동으로 호출된다. 그래서 이것은 자동으로 요청 컨텍스트 (데이터 베이스 연결과 같은)에 72 | 필요한 자원을 해제 할 수 있는 완벽한 장소이다.. 73 | 74 | 75 | 76 | 쉘 경험을 더욱 향상시키기 77 | -------------------------------------- 78 | 79 | 여러분이 만약 쉘에서의 실험적인 아이디어를 실험하기 좋아한다면, 80 | 본인 스스로 여러분의 대화형 세션으로 불러올 모듈을 만들 수 있다. 81 | 여기에 또한 여러분은 데이터베이스를 초기화 하거나 테이블을 삭제하는등의 좀 더 유용한 도우미 메소드등을 정의 할 수 있다. 82 | 83 | 84 | 단지 모듈에 이렇게 삽입하면 된다 (`shelltools` 처럼 불러온다.) : 85 | 86 | 87 | >>> from shelltools import * 88 | -------------------------------------------------------------------------------- /docs/tutorial/css.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-css: 2 | 3 | 스텝 7: 스타일 추가하기 4 | ==================== 5 | 6 | 이제 모든것들이 작동한다. 이제 약간의 스타일을 어플리케이션에 추가해볼 시간이다. 7 | 전에 생성해 두었던 `static` 폴더에 `style.css` 이라고 불리는 스타일시트를 생성해서 추가해 보자: 8 | 9 | 10 | .. sourcecode:: css 11 | 12 | body { font-family: sans-serif; background: #eee; } 13 | a, h1, h2 { color: #377BA8; } 14 | h1, h2 { font-family: 'Georgia', serif; margin: 0; } 15 | h1 { border-bottom: 2px solid #eee; } 16 | h2 { font-size: 1.2em; } 17 | 18 | .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; 19 | padding: 0.8em; background: white; } 20 | .entries { list-style: none; margin: 0; padding: 0; } 21 | .entries li { margin: 0.8em 1.2em; } 22 | .entries li h2 { margin-left: -1em; } 23 | .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } 24 | .add-entry dl { font-weight: bold; } 25 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 26 | margin-bottom: 1em; background: #fafafa; } 27 | .flash { background: #CEE5F5; padding: 0.5em; 28 | border: 1px solid #AACBE2; } 29 | .error { background: #F0D6D6; padding: 0.5em; } 30 | 31 | 다음 섹션에서 계속 :ref:`tutorial-testing`. 32 | -------------------------------------------------------------------------------- /docs/tutorial/dbcon.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-dbcon: 2 | 3 | 스텝 4: 데이터베이스 커넥션 요청하기 4 | ------------------------------------ 5 | 6 | 이제 우리는 어떻게 데이터베이스 커넥션을 생성할 수 있고 스크립트에서 어떻게 사용되는지 알고 있다. 7 | 하지만 어떻게 하면 좀더 근사하게 커넥션 요청을 할 수 있을까? 8 | 우리는 우리의 모든 함수에서 데이터베이스 커넥션을 필요로 한다. 9 | 그러므로 요청이 오기전에 커넥션을 초기화 하고 사용이 끝난 후 종료시키는 것이 10 | 합리적이다. 11 | 12 | Flask에서는 :meth:`~flask.Flask.before_request` , 13 | :meth:`~flask.Flask.after_request` 그리고 :meth:`~flask.Flask.teardown_request` 14 | 데코레이터(decorators)를 이용할 수 있다.:: 15 | 16 | @app.before_request 17 | def before_request(): 18 | g.db = connect_db() 19 | 20 | @app.teardown_request 21 | def teardown_request(exception): 22 | g.db.close() 23 | 24 | 파라미터가 없는 :meth:`~flask.Flask.before_request` 함수는 리퀘스트가 실행되기 전에 25 | 호출되는 함수이다. :meth:`~flask.Flask.after_request` 함수는 리퀘스트가 실행된 다음에 26 | 호출되는 함수이며 클라이언트에게 전송된 응답(reponse)를 파리미터로 넘겨주어야 한다. 27 | 이 함수들은 반드시 사용된 응답(response)객체 혹은 새로운 응답(respone)객체를 리턴하여야 한다. 28 | 그러나 이 함수들은 예외가 발생할 경우 반드시 실행됨을 보장하지 않는다. 29 | 이 경우 예외상황은 :meth:`~flask.Flask.teardown_request` 으로 전달된다. 30 | 이 함수들은 응답객체가 생성된 후 호출된다. 이 함수들은 request객체를 수정할 수 없으며, 31 | 리턴 값들은 무시된다. 만약 리퀘스트가 진행중에 예외사항이 발생 했을 경우 해당 리퀘스트는 32 | 다시 각 함수들에게로 전달되며 그렇지 않을 경우에는 `None` 이 전달된다. 33 | 34 | 35 | 우리는 현재 사용중인 데이터베이스 커넥션을 특별하게 저장한다. 36 | Flask 는 :data:`~flask.g` 라는 특별한 객체를 우리에게 제공한다. 이 객체는 37 | 각 함수들에 대해서 오직 한번의 리퀘스트에 대해서만 유효한 정보를 저장하하고 있다. 38 | 쓰레드환경의 경우 다른 객체에서 위와 같이 사용 할경우 작동이 보장되지 않기 때문에 39 | 결코 사용해서는 안된다. 40 | 41 | 이 특별한 :data:`~flask.g` 객체는 보이지않는 뒷편에서 마법과 같은 어떤일을 수행하여 42 | 쓰레드환경에서도 위와같은 사용이 올바르게 작동하도록 해준다. 43 | 44 | 다음 섹션에서 계속 :ref:`tutorial-views`. 45 | 46 | .. hint:: 어느 곳에 이 소스코드를 위치시켜야 하나요? 47 | 48 | 만얀 당신이 이 튜토리얼을 따라서 여기까지 진행했다면, 아마도 당신은 49 | 이번 스텝과 다음스텝 어디에 코드를 작성해 넣어야 하는지 궁금할 수 있습니다. 50 | 논리적인 위치는 함수들이 함께 그룹핑되는 모듈 레벨의 위치 이고, 51 | 새로 만든 ``before_request`` 와 ``teardown_request`` 함수를 기존의 ``init_db` 52 | 함수 아래에 작성할 수 있다. 53 | (튜토리얼을 따라 한줄씩 작성한다.) 54 | 55 | 만약 현시점에서 각 부분들의 관계를 알고 싶다면, `예제 소스`_ 가 어떻게 56 | 구성되어 있는지 눈여겨 볼 필요가 있다. Flask에서는 하나의 Python 파일에 당신의 57 | 모든 어플리케이션 코드를 다 작성하여 넣는것도 가능하다. 58 | 물론 정말 그렇게 할 필요는 없다. 만약 당신의 어플리케이션이 :ref:`grows larger ` 59 | 점점 커져간다면 이것은 좋은 생각이 아니다. 60 | 61 | .. _예제 소스: 62 | http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ 63 | -------------------------------------------------------------------------------- /docs/tutorial/dbinit.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-dbinit: 2 | 3 | 스텝 3: 데이터베이스 생성하기 4 | ============================= 5 | 6 | Flaskr은 이전에 설명한 대로 데이터베이스를 사용하는 어플리케이션이고 7 | 좀더 정확하게는 관계형 데이터베이스 시스템에 의해 구동되는 어플리케이션이다. 8 | 이러한 시스템은 어떻게 데이터를 저장할지에 대한 정보를 가지고 있는 스키마가 필요하다. 9 | 그래서 처음으로 서버를 실행하기 전에 스키마를 생성하는 것이 중요하다. 10 | 11 | 이러한 스키마는 `schema.sql` 파일을 이용하여 `sqlite3` 명령어를 사용하여 12 | 다음과 같이 만들 수 있다.:: 13 | 14 | sqlite3 /tmp/flaskr.db < schema.sql 15 | 16 | 이방법에서의 단점은 sqlite3 명령어가 필요하다는 점인데, sqlite3 명령어는 모든 17 | 시스템들에서 필수적으로 설치되어 있는 것은 아니기 때문이다. 18 | 한가지 추가적인 문제는 데이터베이스 경로로 제공받은 어떤 경로들은 오류를 발생시킬 수도 있다는 것이다. 19 | 당신의 어플리케이션에 데이터베이스를 초기화 하는 함수를 추가하는 것은 좋은 생각이다. 20 | 21 | 만약 당신이 데이터베이스를 초기화 하는 함수를 추가하기 원한다면 22 | 먼저 contextlib 패키지에 있는 :func:`contextlib.closing` 함수를 import 해야한다. 23 | 만약 Python 2.5를 사용하고 싶다면 먼저 `with` 구문을 추가적으로 사용해야 하다. 24 | (`__future__` 를 반드시 제일 먼저 import 해야 한다.). 25 | 따라서, 다음의 라인들을 기존의 `flaskr.py` 파일에 추가한다. :: 26 | 27 | from __future__ import with_statement 28 | from contextlib import closing 29 | 30 | 다음으로 우리는 데이터베이스를 초기화 시키는 `init_db` 함수를 만들 수 있다. 31 | 이 함수에서 우리는 앞서 정의한 `connect_db` 함수를 사용할 수 있다. 32 | `flaskr.py` 파일의 `connect_db` 함수 아래에 다음의 내용을 추가 하자.:: 33 | 34 | def init_db(): 35 | with closing(connect_db()) as db: 36 | with app.open_resource('schema.sql') as f: 37 | db.cursor().executescript(f.read()) 38 | db.commit() 39 | 40 | 41 | :func:`~contextlib.closing` 함수는 `with` 블럭안에서 연결한 커넥션을 유지하도록 42 | 도와준다. :func:`~flask.Flask.open_resource` 는 어플리케이션 객체의 함수이며 43 | 영역 밖에서도 기능을 지원하며 `with` 블럭에서 직접적으로 사용할 수 있다. 44 | 이 함수를 통해서 리소스 경로(`flaskr` 의 폴더)의 파일을 열고 그 값을 읽을 수 있다. 45 | 우리는 이것을 이용하여 데이터베이스에 연결하는 스크립트를 실행시킬 것이다. 46 | 47 | 우리가 데이터베이스에 연결할 때 우리는 커서를 제공하는 커넥션 객체를 얻는다. 48 | (여기에서는 `db` 라고 부르려고 한다.) 커서에는 전체 스크립트를 실행하는 메소드를 가지고 있다. 49 | 마지막으로, 우리는 변경사항들을 커밋해야 한다. SQLite 3 이다 다른 트랜잭션 데이터베이스들은 50 | 명시적으로 커밋을 하도록 선언하지 않는 이상 진행하지 않는다. 51 | 52 | 이제 Python 쉘에서 다음 함수를 import 하여 실행시키면 데이터베이스 생성이 가능하다.:: 53 | 54 | >>> from flaskr import init_db 55 | >>> init_db() 56 | 57 | .. admonition:: Troubleshooting 58 | 59 | 만약 테이블을 찾을 수 없다는 예외사항이 발생하면 `init_db` 함수를 60 | 호출하였는지 확인하고 테이블 이름이 정확한지 확인하라. 61 | (예를들면 단수형, 복수형과 같은 실수..) 62 | 63 | 다음 섹션에서 계속된다. :ref:`tutorial-dbcon` 64 | -------------------------------------------------------------------------------- /docs/tutorial/folders.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-folders: 2 | 3 | 스텝 0: 폴더를 생성하기 4 | ============================ 5 | 6 | 어플리케이션 개발을 시작하기전에, 어플리케이션에서 사용할 폴더를 만들자 :: 7 | 8 | /flaskr 9 | /static 10 | /templates 11 | 12 | 13 | `flaskr` 폴더는 Python 패키지가 아니다. 단지 우리의 파일들을 저장할 장소이다. 14 | 우리는 이 폴더 안에 데이터베이스 스키마 뿐만 아니라 다른 앞으로 소개될 다른 15 | 스텝에 나오는 주요 모듈들 넣을 곳이다. `static` 폴더 내 파일들은 `HTTP` 를 16 | 통해 어플리케이션 사용자들이 이용할 수 있다. 이 폴더는 css와 javascript 17 | 파일들이 저장되는 곳이다. Flasks는 `templates` 폴더에서 `Jinja2`_ 템플릿을 찾을 것이다 18 | 19 | 20 | 21 | 계속해서 Step 1:데이타베이스 스키마를 보자 :ref:`tutorial-schema`. 22 | 23 | .. _Jinja2: http://jinja.pocoo.org/2/ 24 | -------------------------------------------------------------------------------- /docs/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial: 2 | 3 | 튜토리얼 4 | ======== 5 | 6 | 7 | 파이썬과 Flask로 어플리케이션을 개발하기를 원하는가? 8 | 여기서 예제를 가지고 그것을 배울 기회를 가질 수 있다. 9 | 이 튜토리얼에서는 우리는 간단한 마이크로 블로그 어플리케이션을 개발할 것이다. 10 | 텍스트만 입력가능한 한 명의 사용자만 지원하며 피드백이나 커멘트를 달 수 없다. 11 | 그러나 여러분이 시작하기에 필요한 모든 내용들이 있을 것이다. 12 | 우리는 Flask와 파이썬 범위에서 벗어난 데이타베이스로 SQLite를 사용할 것이다. 13 | 그 밖에 필요한 것들은 없다. 14 | 15 | 만약 여러분이 미리 또는 비교를 위해 모든 소스코드를 원한다면 `example source`_ 를 확인 16 | 하길 바란다. 17 | 18 | 19 | .. _example source: 20 | http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/ 21 | 22 | .. toctree:: 23 | :maxdepth: 2 24 | 25 | introduction 26 | folders 27 | schema 28 | setup 29 | dbinit 30 | dbcon 31 | views 32 | templates 33 | css 34 | testing 35 | -------------------------------------------------------------------------------- /docs/tutorial/introduction.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-introduction: 2 | 3 | Flaskr 소개하기 4 | ================== 5 | 6 | 우리는 우리의 블로깅 어플리케이션을 flaskr 이라고 부를 것이다. 7 | 웬지 덜 웹 2.0스러운 이름을 선택해야할 것 같은 느낌에서 자유로워 진것 같다. 8 | 기본적으로 우리는 flaskr을 통해서 다음 사항들을 하기를 원한다: 9 | 10 | 11 | 1.사용자가 지정한 자격증명 설정을 이용하여 로그인/로그아웃을 할 수 있게 한다. 12 | 사용자는 단한명만 지원한다. 13 | 14 | 2.사용자가 로그인하면 사용자는 제목과 내용을 몇몇 HTML과 텍스트로만 입력할 수 있다. 15 | 우리는 사용자를 신뢰하기 때문에 HTML에 대한 위험성 검증은 하지 않는다. 16 | 17 | 3.flaskr 페이지에서는 지금까지 등록된 모든 항목들을 시간의 역순으로 상단에 보여준다 18 | 최근것을 제일 위로)`(최근것을 제일 위로) 로그인한 사용자는 새로 글을 추가 할 수 있다. 19 | 20 | 21 | 이정도 규모의 어플리케이션에서 사용하기에는 SQLite3도 충분한 선택이다. 22 | 그러나 더 큰 규모의 어플리케이션을 위해서는 더 현명한 방법으로 데이타베이스 연결을 23 | 핸들링하고 다른 RDBMS를 사용이 가능한 `SQLAlchemy`_ 를 사용하는 것이 맞다. 24 | 만약 여러분의 데이타가 NoSQL에 더 적합하다면 인기있는 NoSQL 데이타베이스 중 하나를 25 | 고려하기를 원할 수도 있다. 26 | 27 | 아래는 최종 완성된 어플리케이션의 스크린샷이다.: 28 | 29 | .. image:: ../_static/flaskr.png 30 | :align: center 31 | :class: screenshot 32 | :alt: screenshot of the final application 33 | 34 | 계속해서 스텝 0 폴더 생성하기를 보자. :ref:`tutorial-folders`. 35 | 36 | .. _SQLAlchemy: http://www.sqlalchemy.org/ 37 | -------------------------------------------------------------------------------- /docs/tutorial/schema.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-schema: 2 | 3 | 스텝 1: 데이터베이스 스키마 4 | ======================= 5 | 6 | 먼저 우리는 데이터베이스 스키마를 생성해야 한다. 우리의 어플리케이션을 위해서는 7 | 단지 하나의 테이블만 필요하며 사용이 매우 쉬운 SQLite를 지원하기를 원한다. 8 | 다음의 내용을 `schema.sql` 이라는 이름의 파일로 방금 생성한 `flaskr` 폴더에 저장한다. 9 | 10 | 11 | .. sourcecode:: sql 12 | 13 | drop table if exists entries; 14 | create table entries ( 15 | id integer primary key autoincrement, 16 | title string not null, 17 | text string not null 18 | ); 19 | 20 | 이 스키마는 `entries` 라는 이름의 테이블로 구성되어 있으며 이 테이블의 21 | 각 row에는 `id`, `title`, `text` 컬럼으로 구성된다. `id` 는 자동으로 증가되는 22 | 정수이며 프라이머리 키(primary key) 이다. 나머지 두개의 컬럼은 null이 아닌 23 | 문자열(strings) 값을 가져야 한다. 24 | 25 | 26 | 계속해서 Step 2: 어플리케이션 셋업 코드를 보자. :ref:`tutorial-setup`. 27 | -------------------------------------------------------------------------------- /docs/tutorial/setup.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-setup: 2 | 3 | 스텝 2: 어플리케이션 셋업 코드 4 | ============================== 5 | 6 | 이제 우리는 데이터베이스 스키마를 가지고 있고 어플리케이션 모듈을 생성할 수 있다. 7 | 우리가 만들 어플리케이션을 `flaskr` 폴더안에 있는 `flaskr.py` 라고 부르자. 8 | 시작하는 사람들을 위하여 우리는 import가 필요한 모듈 뿐만 아니라 설정 영역도 추가할 것이다. 9 | 소규모 어플리케이션을 위해서는 우리가 여기에서 할 모듈 안에 설정을 직접 추가하는 것이 가능하다. 10 | 그러나 더 깔끔한 해결책은 설정을 `.ini` 또는 `.py` 로 분리하여 생성하여 로드하거나 그 파일로부터 11 | 값들을 import하는 것이다. 12 | 13 | 14 | 아래는 flaskr.py 파일 내용이다: 15 | 16 | 17 | In `flaskr.py`:: 18 | 19 | # all the imports 20 | import sqlite3 21 | from flask import Flask, request, session, g, redirect, url_for, \ 22 | abort, render_template, flash 23 | 24 | # configuration 25 | DATABASE = '/tmp/flaskr.db' 26 | DEBUG = True 27 | SECRET_KEY = 'development key' 28 | USERNAME = 'admin' 29 | PASSWORD = 'default' 30 | 31 | 32 | 다음으로 우리는 우리의 실제 어플리케이션을 생성하고 같은 파일의 설정을 가지고 33 | 어플리케이션을 초기화할 수 있다. `flaskr.py` 내용은 :: 34 | 35 | 36 | # create our little application :) 37 | app = Flask(__name__) 38 | app.config.from_object(__name__) 39 | 40 | :meth:`~flask.Config.from_object` 는 인자로 주어진 객체를 설정값을 읽어 오기 위해 살펴 볼 것이다. 41 | (만약 인자 값이 문자열이면 해당 객체를 임포트 할것이다.) 그리고나서 거기에 정의된 모든 대문자 42 | 변수들을 찾을 것이다. 우리의 경우, 우리가 위에서 몇 줄의 코드로 작성했던 설정이다. 43 | 여러분은 분리된 파일로도 설정값들을 이동시킬 수 있다. 44 | 45 | 일반적으로 설정 파일에서 설정값을 로드하는 것은 좋은 생각이다. 46 | 위에서 사용한 :meth:`~flask.Config.from_object` 대신 :meth:`~flask.Config.from_envvar` 47 | 를 사용하여 설정값을 로드할 수도 있다:: 48 | 49 | app.config.from_envvar('FLASKR_SETTINGS', silent=True) 50 | 51 | 위와 같은 방식으로 환경변수를 호출하여 설정값을 로드할 수도 있다. 52 | :envvar:`FLASKR_SETTINGS` 에 명시된 설정 파일이 로드되면 기본 설정값들은 덮어쓰기가 된다. 53 | silent 스위치는 해당 환경변수가 존재 하지 않아도 Flask가 작동하도록 하는 것이다. 54 | 55 | 클라이언트에서의 세션을 안전하게 보장하기 위해서는 `secret_key` 가 필요하다. 56 | secret_key는 추측이 어렵도록 가능한 복잡하게 선택하여야 한다. 57 | 디버그 플래그는 인터랙티브 디버거를 활성화 시키거나 비활성화 시키는 일을 한다. 58 | *운영시스템에서는 디버그 모드를 절대로 활성화 시키지 말아야 한다.* 59 | 왜냐하면 디버그 모드에서는 사용자가 서버의 코드를 실행할수가 있기 때문이다. 60 | 61 | 62 | 우리는 또한 명세화된 데이터베이스에 쉽게 접속할 수 있는 방법을 추가할 것이다. 63 | 이방법으로 Python 인터랙티브 쉘이나 스크립트에서 요청에 의해 커넥션을 64 | 얻기위해 사용할 수 있다. 이 방법을 뒤에서 좀더 편리하게 만들어 볼 것이다. 65 | 66 | 67 | :: 68 | 69 | def connect_db(): 70 | return sqlite3.connect(app.config['DATABASE']) 71 | 72 | 마지막으로 우리는 파일의 마지막에 단독 서버로 실행되는 애플리케이션을 위한 73 | 서버 실행 코드를 한줄 추가 하였다.:: 74 | 75 | if __name__ == '__main__': 76 | app.run() 77 | 78 | 여기까지 되어있으면 문제없이 어플리케이션을 시작할 수 있어야 한다. 79 | 다음 명령어로 실행이 가능하다:: 80 | 81 | python flaskr.py 82 | 83 | 서버가 접근가능한 주소로 실행되었다고 알려주는 메시지를 84 | 접할 수 있을 것이다. 85 | 86 | 우리가 아직 아무런 뷰(view)를 만들지 않았기 때문에 브라우저에서는 페이지를 87 | 찾을 수 없다는 404에러를 볼 수 있을 것이다. 이부분에 대해서는 좀 더 후에 88 | 살펴 보도록 할 것이다. 먼저 살펴봐야 할 것은 데이터베이스가 작동되는지 확인하는 것이다. 89 | 90 | 91 | .. admonition:: 외부에서 접근가능한 서버 92 | 93 | 당신의 서버를 외부에 공개하고 싶다면 다음 섹션을 참고 하라 94 | :ref:`externally visible server ` 95 | 96 | Continue with :ref:`tutorial-dbinit`. 97 | -------------------------------------------------------------------------------- /docs/tutorial/testing.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial-testing: 2 | 3 | 보너스: 어플리케이션 테스트 하기 4 | ============================== 5 | 6 | 이제 당신은 어플리케이션 개발을 끝마쳤고 모든것들이 예상한대로 작동한다. 7 | 미래에 어플리케이션을 수정하게될 경우를 대비해 테스트를 자동화하는 것은 8 | 나쁜 생각이 아니다. 위에서 소개한 어플리케이션은 유닛테스트를 어떻게 수행하는지에 9 | 대한 기본적인 예제를 가지고 있다. 이 문서의 :ref:`testing` 섹션을 참고하라. 10 | 해당 문서를 살펴보고 어떻게 쉽게 Flask 어플리케이션을 테스트 할 수있는지 알아보자 11 | 12 | -------------------------------------------------------------------------------- /examples/blueprintexample/blueprintexample.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from simple_page.simple_page import simple_page 3 | 4 | app = Flask(__name__) 5 | app.register_blueprint(simple_page) 6 | # Blueprint can be registered many times 7 | app.register_blueprint(simple_page, url_prefix='/pages') 8 | 9 | 10 | if __name__ == '__main__': 11 | app.run(debug=True) -------------------------------------------------------------------------------- /examples/blueprintexample/blueprintexample_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Blueprint Example Tests 4 | ~~~~~~~~~~~~~~ 5 | 6 | Tests the Blueprint example app 7 | """ 8 | import blueprintexample 9 | import unittest 10 | 11 | 12 | class BlueprintExampleTestCase(unittest.TestCase): 13 | 14 | def setUp(self): 15 | self.app = blueprintexample.app.test_client() 16 | 17 | def test_urls(self): 18 | r = self.app.get('/') 19 | self.assertEquals(r.status_code, 200) 20 | 21 | r = self.app.get('/hello') 22 | self.assertEquals(r.status_code, 200) 23 | 24 | r = self.app.get('/world') 25 | self.assertEquals(r.status_code, 200) 26 | 27 | #second blueprint instance 28 | r = self.app.get('/pages/hello') 29 | self.assertEquals(r.status_code, 200) 30 | 31 | r = self.app.get('/pages/world') 32 | self.assertEquals(r.status_code, 200) 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/examples/blueprintexample/simple_page/__init__.py -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/simple_page.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template, abort 2 | from jinja2 import TemplateNotFound 3 | 4 | simple_page = Blueprint('simple_page', __name__, 5 | template_folder='templates') 6 | 7 | @simple_page.route('/', defaults={'page': 'index'}) 8 | @simple_page.route('/') 9 | def show(page): 10 | try: 11 | return render_template('pages/%s.html' % page) 12 | except TemplateNotFound: 13 | abort(404) 14 | -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/templates/pages/hello.html: -------------------------------------------------------------------------------- 1 | {% extends "pages/layout.html" %} 2 | 3 | {% block body %} 4 | Hello 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/templates/pages/index.html: -------------------------------------------------------------------------------- 1 | {% extends "pages/layout.html" %} 2 | 3 | {% block body %} 4 | Blueprint example page 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/templates/pages/layout.html: -------------------------------------------------------------------------------- 1 | 2 | Simple Page Blueprint 3 |

4 |

This is blueprint example

5 |

6 | A simple page blueprint is registered under / and /pages 7 | you can access it using this urls: 8 |

12 |

13 | Also you can register the same blueprint under another path 14 |

18 | 19 | {% block body %}{% endblock %} 20 |
21 | -------------------------------------------------------------------------------- /examples/blueprintexample/simple_page/templates/pages/world.html: -------------------------------------------------------------------------------- 1 | {% extends "pages/layout.html" %} 2 | {% block body %} 3 | World 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /examples/flaskr/README: -------------------------------------------------------------------------------- 1 | / Flaskr / 2 | 3 | a minimal blog application 4 | 5 | 6 | ~ What is Flaskr? 7 | 8 | A sqlite powered thumble blog application 9 | 10 | ~ How do I use it? 11 | 12 | 1. edit the configuration in the flaskr.py file or 13 | export an FLASKR_SETTINGS environment variable 14 | pointing to a configuration file. 15 | 16 | 2. now you can run the flaskr.py file with your 17 | python interpreter and the application will 18 | greet you on http://localhost:5000/ 19 | 20 | ~ Is it tested? 21 | 22 | You betcha. Run the `flaskr_tests.py` file to see 23 | the tests pass. 24 | -------------------------------------------------------------------------------- /examples/flaskr/flaskr_tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Flaskr Tests 4 | ~~~~~~~~~~~~ 5 | 6 | Tests the Flaskr application. 7 | 8 | :copyright: (c) 2010 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import os 12 | import flaskr 13 | import unittest 14 | import tempfile 15 | 16 | 17 | class FlaskrTestCase(unittest.TestCase): 18 | 19 | def setUp(self): 20 | """Before each test, set up a blank database""" 21 | self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() 22 | flaskr.app.config['TESTING'] = True 23 | self.app = flaskr.app.test_client() 24 | flaskr.init_db() 25 | 26 | def tearDown(self): 27 | """Get rid of the database again after each test.""" 28 | os.close(self.db_fd) 29 | os.unlink(flaskr.app.config['DATABASE']) 30 | 31 | def login(self, username, password): 32 | return self.app.post('/login', data=dict( 33 | username=username, 34 | password=password 35 | ), follow_redirects=True) 36 | 37 | def logout(self): 38 | return self.app.get('/logout', follow_redirects=True) 39 | 40 | # testing functions 41 | 42 | def test_empty_db(self): 43 | """Start with a blank database.""" 44 | rv = self.app.get('/') 45 | assert b'No entries here so far' in rv.data 46 | 47 | def test_login_logout(self): 48 | """Make sure login and logout works""" 49 | rv = self.login(flaskr.app.config['USERNAME'], 50 | flaskr.app.config['PASSWORD']) 51 | assert b'You were logged in' in rv.data 52 | rv = self.logout() 53 | assert b'You were logged out' in rv.data 54 | rv = self.login(flaskr.app.config['USERNAME'] + 'x', 55 | flaskr.app.config['PASSWORD']) 56 | assert b'Invalid username' in rv.data 57 | rv = self.login(flaskr.app.config['USERNAME'], 58 | flaskr.app.config['PASSWORD'] + 'x') 59 | assert b'Invalid password' in rv.data 60 | 61 | def test_messages(self): 62 | """Test that messages work""" 63 | self.login(flaskr.app.config['USERNAME'], 64 | flaskr.app.config['PASSWORD']) 65 | rv = self.app.post('/add', data=dict( 66 | title='', 67 | text='HTML allowed here' 68 | ), follow_redirects=True) 69 | assert b'No entries here so far' not in rv.data 70 | assert b'<Hello>' in rv.data 71 | assert b'HTML allowed here' in rv.data 72 | 73 | 74 | if __name__ == '__main__': 75 | unittest.main() 76 | -------------------------------------------------------------------------------- /examples/flaskr/schema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists entries; 2 | create table entries ( 3 | id integer primary key autoincrement, 4 | title text not null, 5 | text text not null 6 | ); 7 | -------------------------------------------------------------------------------- /examples/flaskr/static/style.css: -------------------------------------------------------------------------------- 1 | body { font-family: sans-serif; background: #eee; } 2 | a, h1, h2 { color: #377BA8; } 3 | h1, h2 { font-family: 'Georgia', serif; margin: 0; } 4 | h1 { border-bottom: 2px solid #eee; } 5 | h2 { font-size: 1.2em; } 6 | 7 | .page { margin: 2em auto; width: 35em; border: 5px solid #ccc; 8 | padding: 0.8em; background: white; } 9 | .entries { list-style: none; margin: 0; padding: 0; } 10 | .entries li { margin: 0.8em 1.2em; } 11 | .entries li h2 { margin-left: -1em; } 12 | .add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; } 13 | .add-entry dl { font-weight: bold; } 14 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 15 | margin-bottom: 1em; background: #fafafa; } 16 | .flash { background: #CEE5F5; padding: 0.5em; 17 | border: 1px solid #AACBE2; } 18 | .error { background: #F0D6D6; padding: 0.5em; } 19 | -------------------------------------------------------------------------------- /examples/flaskr/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | Flaskr 3 | 4 |
5 |

Flaskr

6 |
7 | {% if not session.logged_in %} 8 | log in 9 | {% else %} 10 | log out 11 | {% endif %} 12 |
13 | {% for message in get_flashed_messages() %} 14 |
{{ message }}
15 | {% endfor %} 16 | {% block body %}{% endblock %} 17 |
18 | -------------------------------------------------------------------------------- /examples/flaskr/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Login

4 | {% if error %}

Error: {{ error }}{% endif %} 5 |

6 |
7 |
Username: 8 |
9 |
Password: 10 |
11 |
12 |
13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /examples/flaskr/templates/show_entries.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% if session.logged_in %} 4 |
5 |
6 |
Title: 7 |
8 |
Text: 9 |
10 |
11 |
12 |
13 | {% endif %} 14 |
    15 | {% for entry in entries %} 16 |
  • {{ entry.title }}

    {{ entry.text|safe }} 17 | {% else %} 18 |
  • Unbelievable. No entries here so far 19 | {% endfor %} 20 |
21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /examples/jqueryexample/jqueryexample.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | jQuery Example 4 | ~~~~~~~~~~~~~~ 5 | 6 | A simple application that shows how Flask and jQuery get along. 7 | 8 | :copyright: (c) 2010 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from flask import Flask, jsonify, render_template, request 12 | app = Flask(__name__) 13 | 14 | 15 | @app.route('/_add_numbers') 16 | def add_numbers(): 17 | """Add two numbers server side, ridiculous but well...""" 18 | a = request.args.get('a', 0, type=int) 19 | b = request.args.get('b', 0, type=int) 20 | return jsonify(result=a + b) 21 | 22 | 23 | @app.route('/') 24 | def index(): 25 | return render_template('index.html') 26 | 27 | 28 | if __name__ == '__main__': 29 | app.run() 30 | -------------------------------------------------------------------------------- /examples/jqueryexample/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 27 |

jQuery Example

28 |

29 | + 30 | = 31 | ? 32 |

calculate server side 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /examples/jqueryexample/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | jQuery Example 3 | 5 | 8 | {% block body %}{% endblock %} 9 | -------------------------------------------------------------------------------- /examples/minitwit/README: -------------------------------------------------------------------------------- 1 | 2 | / MiniTwit / 3 | 4 | because writing todo lists is not fun 5 | 6 | 7 | ~ What is MiniTwit? 8 | 9 | A SQLite and Flask powered twitter clone 10 | 11 | ~ How do I use it? 12 | 13 | 1. edit the configuration in the minitwit.py file or 14 | export an MINITWIT_SETTINGS environment variable 15 | pointing to a configuration file. 16 | 17 | 2. fire up a python shell and run this: 18 | 19 | >>> from minitwit import init_db; init_db() 20 | 21 | 3. now you can run the minitwit.py file with your 22 | python interpreter and the application will 23 | greet you on http://localhost:5000/ 24 | 25 | ~ Is it tested? 26 | 27 | You betcha. Run the `minitwit_tests.py` file to 28 | see the tests pass. 29 | -------------------------------------------------------------------------------- /examples/minitwit/schema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists user; 2 | create table user ( 3 | user_id integer primary key autoincrement, 4 | username text not null, 5 | email text not null, 6 | pw_hash text not null 7 | ); 8 | 9 | drop table if exists follower; 10 | create table follower ( 11 | who_id integer, 12 | whom_id integer 13 | ); 14 | 15 | drop table if exists message; 16 | create table message ( 17 | message_id integer primary key autoincrement, 18 | author_id integer not null, 19 | text text not null, 20 | pub_date integer 21 | ); 22 | -------------------------------------------------------------------------------- /examples/minitwit/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | {% block title %}Welcome{% endblock %} | MiniTwit 3 | 4 |

5 |

MiniTwit

6 | 17 | {% with flashes = get_flashed_messages() %} 18 | {% if flashes %} 19 |
    20 | {% for message in flashes %} 21 |
  • {{ message }} 22 | {% endfor %} 23 |
24 | {% endif %} 25 | {% endwith %} 26 |
27 | {% block body %}{% endblock %} 28 |
29 | 32 |
33 | -------------------------------------------------------------------------------- /examples/minitwit/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Sign In{% endblock %} 3 | {% block body %} 4 |

Sign In

5 | {% if error %}
Error: {{ error }}
{% endif %} 6 |
7 |
8 |
Username: 9 |
10 |
Password: 11 |
12 |
13 |
14 |
15 | {% endblock %} 16 | 17 | -------------------------------------------------------------------------------- /examples/minitwit/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Sign Up{% endblock %} 3 | {% block body %} 4 |

Sign Up

5 | {% if error %}
Error: {{ error }}
{% endif %} 6 |
7 |
8 |
Username: 9 |
10 |
E-Mail: 11 |
12 |
Password: 13 |
14 |
Password (repeat): 15 |
16 |
17 |
18 |
19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /examples/minitwit/templates/timeline.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %} 3 | {% if request.endpoint == 'public_timeline' %} 4 | Public Timeline 5 | {% elif request.endpoint == 'user_timeline' %} 6 | {{ profile_user.username }}'s Timeline 7 | {% else %} 8 | My Timeline 9 | {% endif %} 10 | {% endblock %} 11 | {% block body %} 12 |

{{ self.title() }}

13 | {% if g.user %} 14 | {% if request.endpoint == 'user_timeline' %} 15 |
16 | {% if g.user.user_id == profile_user.user_id %} 17 | This is you! 18 | {% elif followed %} 19 | You are currently following this user. 20 | Unfollow user. 22 | {% else %} 23 | You are not yet following this user. 24 | . 26 | {% endif %} 27 |
28 | {% elif request.endpoint == 'timeline' %} 29 |
30 |

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

31 |
32 |

34 |

35 |
36 | {% endif %} 37 | {% endif %} 38 |
    39 | {% for message in messages %} 40 |
  • 41 | {{ message.username }} 43 | {{ message.text }} 44 | — {{ message.pub_date|datetimeformat }} 45 | {% else %} 46 |

  • There's no message so far. 47 | {% endfor %} 48 |
49 | {% endblock %} 50 | -------------------------------------------------------------------------------- /examples/persona/persona.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, session, request, json, abort, g 2 | 3 | import requests 4 | 5 | 6 | app = Flask(__name__) 7 | app.config.update( 8 | DEBUG=True, 9 | SECRET_KEY='my development key', 10 | PERSONA_JS='https://login.persona.org/include.js', 11 | PERSONA_VERIFIER='https://verifier.login.persona.org/verify', 12 | ) 13 | app.config.from_envvar('PERSONA_SETTINGS', silent=True) 14 | 15 | 16 | @app.before_request 17 | def get_current_user(): 18 | g.user = None 19 | email = session.get('email') 20 | if email is not None: 21 | g.user = email 22 | 23 | 24 | @app.route('/') 25 | def index(): 26 | """Just a generic index page to show.""" 27 | return render_template('index.html') 28 | 29 | 30 | @app.route('/_auth/login', methods=['GET', 'POST']) 31 | def login_handler(): 32 | """This is used by the persona.js file to kick off the 33 | verification securely from the server side. If all is okay 34 | the email address is remembered on the server. 35 | """ 36 | resp = requests.post(app.config['PERSONA_VERIFIER'], data={ 37 | 'assertion': request.form['assertion'], 38 | 'audience': request.host_url, 39 | }, verify=True) 40 | if resp.ok: 41 | verification_data = json.loads(resp.content) 42 | if verification_data['status'] == 'okay': 43 | session['email'] = verification_data['email'] 44 | return 'OK' 45 | 46 | abort(400) 47 | 48 | 49 | @app.route('/_auth/logout', methods=['POST']) 50 | def logout_handler(): 51 | """This is what persona.js will call to sign the user 52 | out again. 53 | """ 54 | session.clear() 55 | return 'OK' 56 | 57 | 58 | if __name__ == '__main__': 59 | app.run() 60 | -------------------------------------------------------------------------------- /examples/persona/static/persona.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | /* convert the links into clickable buttons that go to the 3 | persona service */ 4 | $('a.signin').on('click', function() { 5 | navigator.id.request({ 6 | siteName: 'Flask Persona Example' 7 | }); 8 | return false; 9 | }); 10 | 11 | $('a.signout').on('click', function() { 12 | navigator.id.logout(); 13 | return false; 14 | }); 15 | 16 | /* watch persona state changes */ 17 | navigator.id.watch({ 18 | loggedInUser: $CURRENT_USER, 19 | onlogin: function(assertion) { 20 | /* because the login needs to verify the provided assertion 21 | with the persona service which requires an HTTP request, 22 | this could take a bit. To not confuse the user we show 23 | a progress box */ 24 | var box = $('
') 25 | .hide() 26 | .text('Please wait ...') 27 | .appendTo('body') 28 | .fadeIn('fast'); 29 | $.ajax({ 30 | type: 'POST', 31 | url: $URL_ROOT + '_auth/login', 32 | data: {assertion: assertion}, 33 | success: function(res, status, xhr) { window.location.reload(); }, 34 | error: function(xhr, status, err) { 35 | box.remove(); 36 | navigator.id.logout(); 37 | alert('Login failure: ' + err); 38 | } 39 | }); 40 | }, 41 | onlogout: function() { 42 | $.ajax({ 43 | type: 'POST', 44 | url: $URL_ROOT + '_auth/logout', 45 | success: function(res, status, xhr) { window.location.reload(); }, 46 | error: function(xhr, status, err) { 47 | alert('Logout failure: ' + err); 48 | } 49 | }); 50 | } 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /examples/persona/static/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/examples/persona/static/spinner.png -------------------------------------------------------------------------------- /examples/persona/static/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | background: #eee; 3 | } 4 | 5 | body { 6 | font-family: 'Verdana', sans-serif; 7 | font-size: 15px; 8 | margin: 30px auto; 9 | width: 720px; 10 | background: white; 11 | padding: 30px; 12 | } 13 | 14 | h1 { 15 | margin: 0; 16 | } 17 | 18 | h1, h2, a { 19 | color: #d00; 20 | } 21 | 22 | div.authbar { 23 | background: #eee; 24 | padding: 0 15px; 25 | margin: 10px -15px; 26 | line-height: 25px; 27 | height: 25px; 28 | vertical-align: middle; 29 | } 30 | 31 | div.signinprogress { 32 | position: fixed; 33 | top: 0; 34 | left: 0; 35 | right: 0; 36 | bottom: 0; 37 | background: rgba(255, 255, 255, 0.8) url(spinner.png) center center no-repeat; 38 | font-size: 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/persona/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Welcome{% endblock %} 3 | {% block body %} 4 |

Welcome

5 |

6 | This is a small example application that shows how to integrate 7 | Mozilla's persona signin service into a Flask application. 8 |

9 | The advantage of persona over your own login system is that the 10 | password is managed outside of your application and you get 11 | a verified mail address as primary identifier for your user. 12 |

13 | In this example nothing is actually stored on the server, it 14 | just takes over the email address from the persona verifier 15 | and stores it in a session. 16 | {% if g.user %} 17 |

18 | You are now logged in as {{ g.user }} 19 | {% else %} 20 |

21 | To sign in click the sign in button above. 22 | {% endif %} 23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /examples/persona/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | {% block title %}{% endblock %} | Flask Persona Example 3 | 4 | 5 | 6 | 14 | 15 | 16 |

17 |

Mozilla Persona Example

18 |
19 | {% if g.user %} 20 | Signed in as {{ g.user }} 21 | (Sign out) 22 | {% else %} 23 | Not signed in. 24 | {% endif %} 25 |
26 |
27 | {% block body %}{% endblock %} 28 | -------------------------------------------------------------------------------- /flask/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask 4 | ~~~~~ 5 | 6 | A microframework based on Werkzeug. It's extensively documented 7 | and follows best practice patterns. 8 | 9 | :copyright: (c) 2011 by Armin Ronacher. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | 13 | __version__ = '0.11-dev' 14 | 15 | # utilities we import from Werkzeug and Jinja2 that are unused 16 | # in the module but are exported as public interface. 17 | from werkzeug.exceptions import abort 18 | from werkzeug.utils import redirect 19 | from jinja2 import Markup, escape 20 | 21 | from .app import Flask, Request, Response 22 | from .config import Config 23 | from .helpers import url_for, flash, send_file, send_from_directory, \ 24 | get_flashed_messages, get_template_attribute, make_response, safe_join, \ 25 | stream_with_context 26 | from .globals import current_app, g, request, session, _request_ctx_stack, \ 27 | _app_ctx_stack 28 | from .ctx import has_request_context, has_app_context, \ 29 | after_this_request, copy_current_request_context 30 | from .module import Module 31 | from .blueprints import Blueprint 32 | from .templating import render_template, render_template_string 33 | 34 | # the signals 35 | from .signals import signals_available, template_rendered, request_started, \ 36 | request_finished, got_request_exception, request_tearing_down, \ 37 | appcontext_tearing_down, appcontext_pushed, \ 38 | appcontext_popped, message_flashed 39 | 40 | # We're not exposing the actual json module but a convenient wrapper around 41 | # it. 42 | from . import json 43 | 44 | # This was the only thing that flask used to export at one point and it had 45 | # a more generic name. 46 | jsonify = json.jsonify 47 | 48 | # backwards compat, goes away in 1.0 49 | from .sessions import SecureCookieSession as Session 50 | json_available = True 51 | -------------------------------------------------------------------------------- /flask/_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask._compat 4 | ~~~~~~~~~~~~~ 5 | 6 | Some py2/py3 compatibility support based on a stripped down 7 | version of six so we don't have to depend on a specific version 8 | of it. 9 | 10 | :copyright: (c) 2013 by Armin Ronacher. 11 | :license: BSD, see LICENSE for more details. 12 | """ 13 | import sys 14 | 15 | PY2 = sys.version_info[0] == 2 16 | _identity = lambda x: x 17 | 18 | 19 | if not PY2: 20 | text_type = str 21 | string_types = (str,) 22 | integer_types = (int, ) 23 | 24 | iterkeys = lambda d: iter(d.keys()) 25 | itervalues = lambda d: iter(d.values()) 26 | iteritems = lambda d: iter(d.items()) 27 | 28 | from io import StringIO 29 | 30 | def reraise(tp, value, tb=None): 31 | if value.__traceback__ is not tb: 32 | raise value.with_traceback(tb) 33 | raise value 34 | 35 | implements_to_string = _identity 36 | 37 | else: 38 | text_type = unicode 39 | string_types = (str, unicode) 40 | integer_types = (int, long) 41 | 42 | iterkeys = lambda d: d.iterkeys() 43 | itervalues = lambda d: d.itervalues() 44 | iteritems = lambda d: d.iteritems() 45 | 46 | from cStringIO import StringIO 47 | 48 | exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') 49 | 50 | def implements_to_string(cls): 51 | cls.__unicode__ = cls.__str__ 52 | cls.__str__ = lambda x: x.__unicode__().encode('utf-8') 53 | return cls 54 | 55 | 56 | def with_metaclass(meta, *bases): 57 | # This requires a bit of explanation: the basic idea is to make a 58 | # dummy metaclass for one level of class instantiation that replaces 59 | # itself with the actual metaclass. Because of internal type checks 60 | # we also need to make sure that we downgrade the custom metaclass 61 | # for one level to something closer to type (that's why __call__ and 62 | # __init__ comes back from type etc.). 63 | # 64 | # This has the advantage over six.with_metaclass in that it does not 65 | # introduce dummy classes into the final MRO. 66 | class metaclass(meta): 67 | __call__ = type.__call__ 68 | __init__ = type.__init__ 69 | def __new__(cls, name, this_bases, d): 70 | if this_bases is None: 71 | return type.__new__(cls, name, (), d) 72 | return meta(name, bases, d) 73 | return metaclass('temporary_class', None, {}) 74 | -------------------------------------------------------------------------------- /flask/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.ext 4 | ~~~~~~~~~ 5 | 6 | Redirect imports for extensions. This module basically makes it possible 7 | for us to transition from flaskext.foo to flask_foo without having to 8 | force all extensions to upgrade at the same time. 9 | 10 | When a user does ``from flask.ext.foo import bar`` it will attempt to 11 | import ``from flask_foo import bar`` first and when that fails it will 12 | try to import ``from flaskext.foo import bar``. 13 | 14 | We're switching from namespace packages because it was just too painful for 15 | everybody involved. 16 | 17 | :copyright: (c) 2011 by Armin Ronacher. 18 | :license: BSD, see LICENSE for more details. 19 | """ 20 | 21 | 22 | def setup(): 23 | from ..exthook import ExtensionImporter 24 | importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__) 25 | importer.install() 26 | 27 | 28 | setup() 29 | del setup 30 | -------------------------------------------------------------------------------- /flask/globals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.globals 4 | ~~~~~~~~~~~~~ 5 | 6 | Defines all the global objects that are proxies to the current 7 | active context. 8 | 9 | :copyright: (c) 2011 by Armin Ronacher. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | 13 | from functools import partial 14 | from werkzeug.local import LocalStack, LocalProxy 15 | 16 | 17 | def _lookup_req_object(name): 18 | top = _request_ctx_stack.top 19 | if top is None: 20 | raise RuntimeError('working outside of request context') 21 | return getattr(top, name) 22 | 23 | 24 | def _lookup_app_object(name): 25 | top = _app_ctx_stack.top 26 | if top is None: 27 | raise RuntimeError('working outside of application context') 28 | return getattr(top, name) 29 | 30 | 31 | def _find_app(): 32 | top = _app_ctx_stack.top 33 | if top is None: 34 | raise RuntimeError('working outside of application context') 35 | return top.app 36 | 37 | 38 | # context locals 39 | _request_ctx_stack = LocalStack() 40 | _app_ctx_stack = LocalStack() 41 | current_app = LocalProxy(_find_app) 42 | request = LocalProxy(partial(_lookup_req_object, 'request')) 43 | session = LocalProxy(partial(_lookup_req_object, 'session')) 44 | g = LocalProxy(partial(_lookup_app_object, 'g')) 45 | -------------------------------------------------------------------------------- /flask/logging.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.logging 4 | ~~~~~~~~~~~~~ 5 | 6 | Implements the logging support for Flask. 7 | 8 | :copyright: (c) 2011 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | 12 | from __future__ import absolute_import 13 | 14 | from logging import getLogger, StreamHandler, Formatter, getLoggerClass, DEBUG 15 | 16 | 17 | def create_logger(app): 18 | """Creates a logger for the given application. This logger works 19 | similar to a regular Python logger but changes the effective logging 20 | level based on the application's debug flag. Furthermore this 21 | function also removes all attached handlers in case there was a 22 | logger with the log name before. 23 | """ 24 | Logger = getLoggerClass() 25 | 26 | class DebugLogger(Logger): 27 | def getEffectiveLevel(x): 28 | if x.level == 0 and app.debug: 29 | return DEBUG 30 | return Logger.getEffectiveLevel(x) 31 | 32 | class DebugHandler(StreamHandler): 33 | def emit(x, record): 34 | StreamHandler.emit(x, record) if app.debug else None 35 | 36 | handler = DebugHandler() 37 | handler.setLevel(DEBUG) 38 | handler.setFormatter(Formatter(app.debug_log_format)) 39 | logger = getLogger(app.logger_name) 40 | # just in case that was not a new logger, get rid of all the handlers 41 | # already attached to it. 42 | del logger.handlers[:] 43 | logger.__class__ = DebugLogger 44 | logger.addHandler(handler) 45 | return logger 46 | -------------------------------------------------------------------------------- /flask/module.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.module 4 | ~~~~~~~~~~~~ 5 | 6 | Implements a class that represents module blueprints. 7 | 8 | :copyright: (c) 2011 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | 12 | import os 13 | 14 | from .blueprints import Blueprint 15 | 16 | 17 | def blueprint_is_module(bp): 18 | """Used to figure out if something is actually a module""" 19 | return isinstance(bp, Module) 20 | 21 | 22 | class Module(Blueprint): 23 | """Deprecated module support. Until Flask 0.6 modules were a different 24 | name of the concept now available as blueprints in Flask. They are 25 | essentially doing the same but have some bad semantics for templates and 26 | static files that were fixed with blueprints. 27 | 28 | .. versionchanged:: 0.7 29 | Modules were deprecated in favor for blueprints. 30 | """ 31 | 32 | def __init__(self, import_name, name=None, url_prefix=None, 33 | static_path=None, subdomain=None): 34 | if name is None: 35 | assert '.' in import_name, 'name required if package name ' \ 36 | 'does not point to a submodule' 37 | name = import_name.rsplit('.', 1)[1] 38 | Blueprint.__init__(self, name, import_name, url_prefix=url_prefix, 39 | subdomain=subdomain, template_folder='templates') 40 | 41 | if os.path.isdir(os.path.join(self.root_path, 'static')): 42 | self._static_folder = 'static' 43 | -------------------------------------------------------------------------------- /flask/signals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.signals 4 | ~~~~~~~~~~~~~ 5 | 6 | Implements signals based on blinker if available, otherwise 7 | falls silently back to a noop 8 | 9 | :copyright: (c) 2011 by Armin Ronacher. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | signals_available = False 13 | try: 14 | from blinker import Namespace 15 | signals_available = True 16 | except ImportError: 17 | class Namespace(object): 18 | def signal(self, name, doc=None): 19 | return _FakeSignal(name, doc) 20 | 21 | class _FakeSignal(object): 22 | """If blinker is unavailable, create a fake class with the same 23 | interface that allows sending of signals but will fail with an 24 | error on anything else. Instead of doing anything on send, it 25 | will just ignore the arguments and do nothing instead. 26 | """ 27 | 28 | def __init__(self, name, doc=None): 29 | self.name = name 30 | self.__doc__ = doc 31 | def _fail(self, *args, **kwargs): 32 | raise RuntimeError('signalling support is unavailable ' 33 | 'because the blinker library is ' 34 | 'not installed.') 35 | send = lambda *a, **kw: None 36 | connect = disconnect = has_receivers_for = receivers_for = \ 37 | temporarily_connected_to = connected_to = _fail 38 | del _fail 39 | 40 | # the namespace for code signals. If you are not flask code, do 41 | # not put signals in here. Create your own namespace instead. 42 | _signals = Namespace() 43 | 44 | 45 | # core signals. For usage examples grep the sourcecode or consult 46 | # the API documentation in docs/api.rst as well as docs/signals.rst 47 | template_rendered = _signals.signal('template-rendered') 48 | request_started = _signals.signal('request-started') 49 | request_finished = _signals.signal('request-finished') 50 | request_tearing_down = _signals.signal('request-tearing-down') 51 | got_request_exception = _signals.signal('got-request-exception') 52 | appcontext_tearing_down = _signals.signal('appcontext-tearing-down') 53 | appcontext_pushed = _signals.signal('appcontext-pushed') 54 | appcontext_popped = _signals.signal('appcontext-popped') 55 | message_flashed = _signals.signal('message-flashed') 56 | -------------------------------------------------------------------------------- /flask/testsuite/deprecations.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.testsuite.deprecations 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Tests deprecation support. 7 | 8 | :copyright: (c) 2011 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | 12 | import flask 13 | import unittest 14 | from flask.testsuite import FlaskTestCase, catch_warnings 15 | 16 | 17 | class DeprecationsTestCase(FlaskTestCase): 18 | """not used currently""" 19 | 20 | 21 | def suite(): 22 | suite = unittest.TestSuite() 23 | suite.addTest(unittest.makeSuite(DeprecationsTestCase)) 24 | return suite 25 | -------------------------------------------------------------------------------- /flask/testsuite/examples.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.testsuite.examples 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Tests the examples. 7 | 8 | :copyright: (c) 2011 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import os 12 | import unittest 13 | from flask.testsuite import add_to_path 14 | 15 | 16 | def setup_path(): 17 | example_path = os.path.join(os.path.dirname(__file__), 18 | os.pardir, os.pardir, 'examples') 19 | add_to_path(os.path.join(example_path, 'flaskr')) 20 | add_to_path(os.path.join(example_path, 'minitwit')) 21 | 22 | 23 | def suite(): 24 | setup_path() 25 | suite = unittest.TestSuite() 26 | try: 27 | from minitwit_tests import MiniTwitTestCase 28 | except ImportError: 29 | pass 30 | else: 31 | suite.addTest(unittest.makeSuite(MiniTwitTestCase)) 32 | try: 33 | from flaskr_tests import FlaskrTestCase 34 | except ImportError: 35 | pass 36 | else: 37 | suite.addTest(unittest.makeSuite(FlaskrTestCase)) 38 | return suite 39 | -------------------------------------------------------------------------------- /flask/testsuite/static/index.html: -------------------------------------------------------------------------------- 1 |

Hello World!

2 | -------------------------------------------------------------------------------- /flask/testsuite/subclassing.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | flask.testsuite.subclassing 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Test that certain behavior of flask can be customized by 7 | subclasses. 8 | 9 | :copyright: (c) 2011 by Armin Ronacher. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | import flask 13 | import unittest 14 | from logging import StreamHandler 15 | from flask.testsuite import FlaskTestCase 16 | from flask._compat import StringIO 17 | 18 | 19 | class FlaskSubclassingTestCase(FlaskTestCase): 20 | 21 | def test_suppressed_exception_logging(self): 22 | class SuppressedFlask(flask.Flask): 23 | def log_exception(self, exc_info): 24 | pass 25 | 26 | out = StringIO() 27 | app = SuppressedFlask(__name__) 28 | app.logger_name = 'flask_tests/test_suppressed_exception_logging' 29 | app.logger.addHandler(StreamHandler(out)) 30 | 31 | @app.route('/') 32 | def index(): 33 | 1 // 0 34 | 35 | rv = app.test_client().get('/') 36 | self.assert_equal(rv.status_code, 500) 37 | self.assert_in(b'Internal Server Error', rv.data) 38 | 39 | err = out.getvalue() 40 | self.assert_equal(err, '') 41 | 42 | 43 | def suite(): 44 | suite = unittest.TestSuite() 45 | suite.addTest(unittest.makeSuite(FlaskSubclassingTestCase)) 46 | return suite 47 | -------------------------------------------------------------------------------- /flask/testsuite/templates/_macro.html: -------------------------------------------------------------------------------- 1 | {% macro hello(name) %}Hello {{ name }}!{% endmacro %} 2 | -------------------------------------------------------------------------------- /flask/testsuite/templates/context_template.html: -------------------------------------------------------------------------------- 1 |

{{ value }}|{{ injected_value }} 2 | -------------------------------------------------------------------------------- /flask/testsuite/templates/escaping_template.html: -------------------------------------------------------------------------------- 1 | {{ text }} 2 | {{ html }} 3 | {% autoescape false %}{{ text }} 4 | {{ html }}{% endautoescape %} 5 | {% autoescape true %}{{ text }} 6 | {{ html }}{% endautoescape %} 7 | -------------------------------------------------------------------------------- /flask/testsuite/templates/mail.txt: -------------------------------------------------------------------------------- 1 | {{ foo}} Mail 2 | -------------------------------------------------------------------------------- /flask/testsuite/templates/nested/nested.txt: -------------------------------------------------------------------------------- 1 | I'm nested 2 | -------------------------------------------------------------------------------- /flask/testsuite/templates/simple_template.html: -------------------------------------------------------------------------------- 1 |

{{ whiskey }}

2 | -------------------------------------------------------------------------------- /flask/testsuite/templates/template_filter.html: -------------------------------------------------------------------------------- 1 | {{ value|super_reverse }} -------------------------------------------------------------------------------- /flask/testsuite/templates/template_test.html: -------------------------------------------------------------------------------- 1 | {% if value is boolean %} 2 | Success! 3 | {% endif %} 4 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | from blueprintapp.apps.admin import admin 5 | from blueprintapp.apps.frontend import frontend 6 | app.register_blueprint(admin) 7 | app.register_blueprint(frontend) 8 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/flask/testsuite/test_apps/blueprintapp/apps/__init__.py -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template 2 | 3 | admin = Blueprint('admin', __name__, url_prefix='/admin', 4 | template_folder='templates', 5 | static_folder='static') 6 | 7 | 8 | @admin.route('/') 9 | def index(): 10 | return render_template('admin/index.html') 11 | 12 | 13 | @admin.route('/index2') 14 | def index2(): 15 | return render_template('./admin/index.html') 16 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css: -------------------------------------------------------------------------------- 1 | /* nested file */ 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt: -------------------------------------------------------------------------------- 1 | Admin File 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | Hello from the Admin 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template 2 | 3 | frontend = Blueprint('frontend', __name__, template_folder='templates') 4 | 5 | 6 | @frontend.route('/') 7 | def index(): 8 | return render_template('frontend/index.html') 9 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html: -------------------------------------------------------------------------------- 1 | Hello from the Frontend 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/config_module_app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import flask 3 | here = os.path.abspath(os.path.dirname(__file__)) 4 | app = flask.Flask(__name__) 5 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/config_package_app/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import flask 3 | here = os.path.abspath(os.path.dirname(__file__)) 4 | app = flask.Flask(__name__) 5 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flask_broken/__init__.py: -------------------------------------------------------------------------------- 1 | import flask.ext.broken.b 2 | import missing_module 3 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flask_broken/b.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/flask/testsuite/test_apps/flask_broken/b.py -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flask_newext_package/__init__.py: -------------------------------------------------------------------------------- 1 | ext_id = 'newext_package' 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flask_newext_package/submodule.py: -------------------------------------------------------------------------------- 1 | def test_function(): 2 | return 42 3 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flask_newext_simple.py: -------------------------------------------------------------------------------- 1 | ext_id = 'newext_simple' 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flaskext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/flask/testsuite/test_apps/flaskext/__init__.py -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flaskext/oldext_package/__init__.py: -------------------------------------------------------------------------------- 1 | ext_id = 'oldext_package' 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flaskext/oldext_package/submodule.py: -------------------------------------------------------------------------------- 1 | def test_function(): 2 | return 42 3 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/flaskext/oldext_simple.py: -------------------------------------------------------------------------------- 1 | ext_id = 'oldext_simple' 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/importerror.py: -------------------------------------------------------------------------------- 1 | # NoImportsTestCase 2 | raise NotImplementedError 3 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg -------------------------------------------------------------------------------- /flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | app = flask.Flask(__name__) 4 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | app = flask.Flask(__name__) 4 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/main_app.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | # Test Flask initialization with main module. 4 | app = flask.Flask('__main__') 5 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | from moduleapp.apps.admin import admin 5 | from moduleapp.apps.frontend import frontend 6 | app.register_module(admin) 7 | app.register_module(frontend) 8 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liks79/flask/4af8d04f8d9bef2099f8f64fdf8253077770c264/flask/testsuite/test_apps/moduleapp/apps/__init__.py -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Module, render_template 2 | 3 | 4 | admin = Module(__name__, url_prefix='/admin') 5 | 6 | 7 | @admin.route('/') 8 | def index(): 9 | return render_template('admin/index.html') 10 | 11 | 12 | @admin.route('/index2') 13 | def index2(): 14 | return render_template('./admin/index.html') 15 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/admin/static/css/test.css: -------------------------------------------------------------------------------- 1 | /* nested file */ 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/admin/static/test.txt: -------------------------------------------------------------------------------- 1 | Admin File 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/admin/templates/index.html: -------------------------------------------------------------------------------- 1 | Hello from the Admin 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/frontend/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Module, render_template 2 | 3 | 4 | frontend = Module(__name__) 5 | 6 | 7 | @frontend.route('/') 8 | def index(): 9 | return render_template('frontend/index.html') 10 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/moduleapp/apps/frontend/templates/index.html: -------------------------------------------------------------------------------- 1 | Hello from the Frontend 2 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/path/installed_package/__init__.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | app = flask.Flask(__name__) 4 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/subdomaintestmodule/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Module 2 | 3 | 4 | mod = Module(__name__, 'foo', subdomain='foo') 5 | -------------------------------------------------------------------------------- /flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt: -------------------------------------------------------------------------------- 1 | Hello Subdomain 2 | -------------------------------------------------------------------------------- /run-tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys, os 3 | sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 4 | from flask.testsuite import main 5 | main() 6 | -------------------------------------------------------------------------------- /scripts/testproj/templates/index.html: -------------------------------------------------------------------------------- 1 | {{ url_for('static', filename='test.css') }} 2 | {{ url_for('foo.static', filename='test.css') }} 3 | -------------------------------------------------------------------------------- /scripts/testproj/test.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, Module, render_template, url_for 2 | 3 | 4 | mod = Module(__name__) 5 | mod2 = Module(__name__, 'testmod2') 6 | mod3 = Module(__name__, name='somemod', subdomain='meh') 7 | 8 | 9 | @app.after_request 10 | def after_request(response): 11 | g.db.close() 12 | return response 13 | 14 | 15 | @app.route('/') 16 | def index_foo(): 17 | x1 = url_for('somemod.index') 18 | x2 = url_for('.index') 19 | return render_template('test/index.html') 20 | 21 | 22 | @mod.route('/') 23 | def index(): 24 | x1 = url_for('somemod.index') 25 | x2 = url_for('.index') 26 | return render_template('test/index.html') 27 | 28 | 29 | @mod2.route('/') 30 | def mod2_index(): 31 | return render_template('testmod2/index.html') 32 | 33 | 34 | @mod3.route('/') 35 | def mod3_index(): 36 | return render_template('something-else/index.html') 37 | 38 | 39 | app = Flask(__name__) 40 | app.register_module(mod) 41 | app.register_module(mod2) 42 | 43 | 44 | def handle_404(error): 45 | return 'Testing', 404 46 | app.error_handlers[404] = handle_404 47 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_date = true 3 | 4 | [aliases] 5 | release = egg_info -RDb '' 6 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py26, py27, pypy, py33 3 | 4 | [testenv] 5 | deps = blinker 6 | commands = python run-tests.py [] 7 | --------------------------------------------------------------------------------