mirror of https://github.com/mitsuhiko/flask.git
Browse Source
new readme readme as setup.py long_description links in changes git in authors add travis osx env break out docs build in travis remove python_requires for nowpull/2624/head
David Lord
7 years ago
16 changed files with 310 additions and 653 deletions
@ -1,40 +1,12 @@
|
||||
Flask is written and maintained by Armin Ronacher and |
||||
various contributors: |
||||
Flask is developed and maintained by the Pallets team and community |
||||
contributors. It was created by Armin Ronacher. The core maintainers |
||||
are: |
||||
|
||||
Development Lead |
||||
```````````````` |
||||
- David Lord (davidism) |
||||
- Adrian Mönnich (ThiefMaster) |
||||
- Armin Ronacher (mitsuhiko) |
||||
- Marcus Unterwaditzer (untitaker) |
||||
|
||||
- Armin Ronacher <armin.ronacher@active-4.com> |
||||
A full list of contributors is available from git with:: |
||||
|
||||
Patches and Suggestions |
||||
``````````````````````` |
||||
|
||||
- Adam Byrtek |
||||
- Adam Zapletal |
||||
- Ali Afshar |
||||
- Chris Edgemon |
||||
- Chris Grindstaff |
||||
- Christopher Grebs |
||||
- Daniel Neuhäuser |
||||
- Dan Sully |
||||
- David Lord @davidism |
||||
- Edmond Burnett |
||||
- Florent Xicluna |
||||
- Georg Brandl |
||||
- Hsiaoming Yang @lepture |
||||
- Jeff Widman @jeffwidman |
||||
- Joshua Bronson @jab |
||||
- Justin Quick |
||||
- Kenneth Reitz |
||||
- Keyan Pishdadian |
||||
- Marian Sigler |
||||
- Martijn Pieters |
||||
- Matt Campell |
||||
- Matthew Frazier |
||||
- Michael van Tellingen |
||||
- Ron DuPlain |
||||
- Sebastien Estienne |
||||
- Simon Sapin |
||||
- Stephane Wirtel |
||||
- Thomas Schranz |
||||
- Zhao Xiaohong |
||||
git shortlog -sne |
||||
|
@ -1,33 +1,31 @@
|
||||
Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS |
||||
for more details. |
||||
Copyright © 2010 by the Pallets team. |
||||
|
||||
Some rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms of the software as well |
||||
as documentation, with or without modification, are permitted provided |
||||
that the following conditions are met: |
||||
Redistribution and use in source and binary forms of the software as |
||||
well as documentation, with or without modification, are permitted |
||||
provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following |
||||
disclaimer in the documentation and/or other materials provided |
||||
with the distribution. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* The names of the contributors may not be used to endorse or |
||||
promote products derived from this software without specific |
||||
prior written permission. |
||||
* Neither the name of the copyright holder nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT |
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
||||
DAMAGE. |
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, |
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
||||
THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
SUCH DAMAGE. |
||||
|
@ -1,49 +0,0 @@
|
||||
|
||||
|
||||
// Flask // |
||||
|
||||
web development, one drop at a time |
||||
|
||||
|
||||
~ What is Flask? |
||||
|
||||
Flask is a microframework for Python based on Werkzeug |
||||
and Jinja2. It's intended for getting started very quickly |
||||
and was developed with best intentions in mind. |
||||
|
||||
~ Is it ready? |
||||
|
||||
It's still not 1.0 but it's shaping up nicely and is |
||||
already widely used. Consider the API to slightly |
||||
improve over time but we don't plan on breaking it. |
||||
|
||||
~ What do I need? |
||||
|
||||
All dependencies are installed by using `pip install Flask`. |
||||
We encourage you to use a virtualenv. Check the docs for |
||||
complete installation and usage instructions. |
||||
|
||||
~ Where are the docs? |
||||
|
||||
Go to http://flask.pocoo.org/docs/ for a prebuilt version |
||||
of the current documentation. Otherwise build them yourself |
||||
from the sphinx sources in the docs folder. |
||||
|
||||
~ Where are the tests? |
||||
|
||||
Good that you're asking. The tests are in the |
||||
tests/ folder. To run the tests use the |
||||
`pytest` testing tool: |
||||
|
||||
$ pytest |
||||
|
||||
Details on contributing can be found in CONTRIBUTING.rst |
||||
|
||||
~ Where can I get help? |
||||
|
||||
Either use the #pocoo IRC channel on irc.freenode.net or |
||||
ask on the mailinglist: http://flask.pocoo.org/mailinglist/ |
||||
|
||||
See http://flask.pocoo.org/community/ for more resources. |
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
Flask |
||||
===== |
||||
|
||||
Flask is a lightweight `WSGI`_ web application framework. It is designed |
||||
to make getting started quick and easy, with the ability to scale up to |
||||
complex applications. It began as a simple wrapper around `Werkzeug`_ |
||||
and `Jinja`_ and has become one of the most popular Python web |
||||
application frameworks. |
||||
|
||||
Flask offers suggestions, but doesn't enforce any dependencies or |
||||
project layout. It is up to the developer to choose the tools and |
||||
libraries they want to use. There are many extensions provided by the |
||||
community that make adding new functionality easy. |
||||
|
||||
|
||||
Installing |
||||
---------- |
||||
|
||||
Install and update using `pip`_: |
||||
|
||||
.. code-block:: text |
||||
|
||||
pip install -U Flask |
||||
|
||||
|
||||
A Simple Example |
||||
---------------- |
||||
|
||||
.. code-block:: python |
||||
|
||||
from flask import Flask |
||||
|
||||
app = Flask(__name__) |
||||
|
||||
@app.route('/') |
||||
def hello(): |
||||
return 'Hello, World!' |
||||
|
||||
.. code-block:: none |
||||
|
||||
$ FLASK_APP=hello.py flask run |
||||
* Running on http://localhost:5000/ |
||||
|
||||
|
||||
Links |
||||
----- |
||||
|
||||
* Website: https://www.palletsprojects.com/p/flask/ |
||||
* Releases: https://pypi.org/project/Flask/ |
||||
* Code: https://github.com/pallets/flask |
||||
* Issue tracker: https://github.com/pallets/flask/issues |
||||
* Test status: |
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/flask |
||||
* Windows: https://ci.appveyor.com/project/pallets/flask |
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/flask |
||||
|
||||
.. _WSGI: https://wsgi.readthedocs.io |
||||
.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/ |
||||
.. _Jinja: https://www.palletsprojects.com/p/jinja/ |
||||
.. _pip: https://pip.pypa.io/en/stable/quickstart/ |
@ -1,309 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
Flask Extension Tests |
||||
~~~~~~~~~~~~~~~~~~~~~ |
||||
|
||||
Tests the Flask extensions. |
||||
|
||||
:copyright: (c) 2015 by Ali Afshar. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
import os |
||||
import sys |
||||
import shutil |
||||
import urllib2 |
||||
import tempfile |
||||
import subprocess |
||||
import argparse |
||||
|
||||
from flask import json |
||||
|
||||
from setuptools.package_index import PackageIndex |
||||
from setuptools.archive_util import unpack_archive |
||||
|
||||
flask_svc_url = 'http://flask.pocoo.org/extensions/' |
||||
|
||||
|
||||
# OS X has awful paths when using mkstemp or gettempdir(). I don't |
||||
# care about security or clashes here, so pick something that is |
||||
# actually memorable. |
||||
if sys.platform == 'darwin': |
||||
_tempdir = '/private/tmp' |
||||
else: |
||||
_tempdir = tempfile.gettempdir() |
||||
tdir = _tempdir + '/flaskext-test' |
||||
flaskdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) |
||||
|
||||
|
||||
# virtualenv hack *cough* |
||||
os.environ['PYTHONDONTWRITEBYTECODE'] = '' |
||||
|
||||
|
||||
RESULT_TEMPATE = u'''\ |
||||
<!doctype html> |
||||
<title>Flask-Extension Test Results</title> |
||||
<style type=text/css> |
||||
body { font-family: 'Georgia', serif; font-size: 17px; color: #000; } |
||||
a { color: #004B6B; } |
||||
a:hover { color: #6D4100; } |
||||
h1, h2, h3 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; } |
||||
h1 { font-size: 30px; margin: 15px 0 5px 0; } |
||||
h2 { font-size: 24px; margin: 15px 0 5px 0; } |
||||
h3 { font-size: 19px; margin: 15px 0 5px 0; } |
||||
textarea, code, |
||||
pre { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', |
||||
'Bitstream Vera Sans Mono', monospace!important; font-size: 15px; |
||||
background: #eee; } |
||||
pre { padding: 7px 15px; line-height: 1.3; } |
||||
p { line-height: 1.4; } |
||||
table { border: 1px solid black; border-collapse: collapse; |
||||
margin: 15px 0; } |
||||
td, th { border: 1px solid black; padding: 4px 10px; |
||||
text-align: left; } |
||||
th { background: #eee; font-weight: normal; } |
||||
tr.success { background: #D3F5CC; } |
||||
tr.failed { background: #F5D2CB; } |
||||
</style> |
||||
<h1>Flask-Extension Test Results</h1> |
||||
<p> |
||||
This page contains the detailed test results for the test run of |
||||
all {{ 'approved' if approved }} Flask extensions. |
||||
<h2>Summary</h2> |
||||
<table class=results> |
||||
<thead> |
||||
<tr> |
||||
<th>Extension |
||||
<th>Version |
||||
<th>Author |
||||
<th>License |
||||
<th>Outcome |
||||
{%- for iptr, _ in results[0].logs|dictsort %} |
||||
<th>{{ iptr }} |
||||
{%- endfor %} |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
{%- for result in results %} |
||||
{% set outcome = 'success' if result.success else 'failed' %} |
||||
<tr class={{ outcome }}> |
||||
<th>{{ result.name }} |
||||
<td>{{ result.version }} |
||||
<td>{{ result.author }} |
||||
<td>{{ result.license }} |
||||
<td>{{ outcome }} |
||||
{%- for iptr, _ in result.logs|dictsort %} |
||||
<td><a href="#{{ result.name }}-{{ iptr }}">see log</a> |
||||
{%- endfor %} |
||||
</tr> |
||||
{%- endfor %} |
||||
</tbody> |
||||
</table> |
||||
<h2>Test Logs</h2> |
||||
<p>Detailed test logs for all tests on all platforms: |
||||
{%- for result in results %} |
||||
{%- for iptr, log in result.logs|dictsort %} |
||||
<h3 id="{{ result.name }}-{{ iptr }}"> |
||||
{{ result.name }} - {{ result.version }} [{{ iptr }}]</h3> |
||||
<pre>{{ log }}</pre> |
||||
{%- endfor %} |
||||
{%- endfor %} |
||||
''' |
||||
|
||||
|
||||
def log(msg, *args): |
||||
print('[EXTTEST] ' + (msg % args)) |
||||
|
||||
|
||||
class TestResult(object): |
||||
|
||||
def __init__(self, name, folder, statuscode, interpreters): |
||||
intrptr = os.path.join(folder, '.tox/%s/bin/python' |
||||
% interpreters[0]) |
||||
self.statuscode = statuscode |
||||
self.folder = folder |
||||
self.success = statuscode == 0 |
||||
|
||||
def fetch(field): |
||||
try: |
||||
c = subprocess.Popen([intrptr, 'setup.py', |
||||
'--' + field], cwd=folder, |
||||
stdout=subprocess.PIPE) |
||||
return c.communicate()[0].strip() |
||||
except OSError: |
||||
return '?' |
||||
self.name = name |
||||
self.license = fetch('license') |
||||
self.author = fetch('author') |
||||
self.version = fetch('version') |
||||
|
||||
self.logs = {} |
||||
for interpreter in interpreters: |
||||
logfile = os.path.join(folder, '.tox/%s/log/test.log' |
||||
% interpreter) |
||||
if os.path.isfile(logfile): |
||||
self.logs[interpreter] = open(logfile).read() |
||||
else: |
||||
self.logs[interpreter] = '' |
||||
|
||||
|
||||
def create_tdir(): |
||||
try: |
||||
shutil.rmtree(tdir) |
||||
except Exception: |
||||
pass |
||||
os.mkdir(tdir) |
||||
|
||||
|
||||
def package_flask(): |
||||
distfolder = tdir + '/.flask-dist' |
||||
c = subprocess.Popen(['python', 'setup.py', 'sdist', '--formats=gztar', |
||||
'--dist', distfolder], cwd=flaskdir) |
||||
c.wait() |
||||
return os.path.join(distfolder, os.listdir(distfolder)[0]) |
||||
|
||||
|
||||
def get_test_command(checkout_dir): |
||||
if os.path.isfile(checkout_dir + '/Makefile'): |
||||
return 'make test' |
||||
return 'python setup.py test' |
||||
|
||||
|
||||
def fetch_extensions_list(): |
||||
req = urllib2.Request(flask_svc_url, headers={'accept':'application/json'}) |
||||
d = urllib2.urlopen(req).read() |
||||
data = json.loads(d) |
||||
for ext in data['extensions']: |
||||
yield ext |
||||
|
||||
|
||||
def checkout_extension(name): |
||||
log('Downloading extension %s to temporary folder', name) |
||||
root = os.path.join(tdir, name) |
||||
os.mkdir(root) |
||||
checkout_path = PackageIndex().download(name, root) |
||||
|
||||
unpack_archive(checkout_path, root) |
||||
path = None |
||||
for fn in os.listdir(root): |
||||
path = os.path.join(root, fn) |
||||
if os.path.isdir(path): |
||||
break |
||||
log('Downloaded to %s', path) |
||||
return path |
||||
|
||||
|
||||
tox_template = """[tox] |
||||
envlist=%(env)s |
||||
|
||||
[testenv] |
||||
deps= |
||||
%(deps)s |
||||
distribute |
||||
py |
||||
commands=bash flaskext-runtest.sh {envlogdir}/test.log |
||||
downloadcache=%(cache)s |
||||
""" |
||||
|
||||
|
||||
def create_tox_ini(checkout_path, interpreters, flask_dep): |
||||
tox_path = os.path.join(checkout_path, 'tox-flask-test.ini') |
||||
if not os.path.exists(tox_path): |
||||
with open(tox_path, 'w') as f: |
||||
f.write(tox_template % { |
||||
'env': ','.join(interpreters), |
||||
'cache': tdir, |
||||
'deps': flask_dep |
||||
}) |
||||
return tox_path |
||||
|
||||
|
||||
def iter_extensions(only_approved=True): |
||||
for ext in fetch_extensions_list(): |
||||
if ext['approved'] or not only_approved: |
||||
yield ext['name'] |
||||
|
||||
|
||||
def test_extension(name, interpreters, flask_dep): |
||||
checkout_path = checkout_extension(name) |
||||
log('Running tests with tox in %s', checkout_path) |
||||
|
||||
# figure out the test command and write a wrapper script. We |
||||
# can't write that directly into the tox ini because tox does |
||||
# not invoke the command from the shell so we have no chance |
||||
# to pipe the output into a logfile. The /dev/null hack is |
||||
# to trick py.test (if used) into not guessing widths from the |
||||
# invoking terminal. |
||||
test_command = get_test_command(checkout_path) |
||||
log('Test command: %s', test_command) |
||||
f = open(checkout_path + '/flaskext-runtest.sh', 'w') |
||||
f.write(test_command + ' &> "$1" < /dev/null\n') |
||||
f.close() |
||||
|
||||
# if there is a tox.ini, remove it, it will cause troubles |
||||
# for us. Remove it if present, we are running tox ourselves |
||||
# afterall. |
||||
|
||||
create_tox_ini(checkout_path, interpreters, flask_dep) |
||||
rv = subprocess.call(['tox', '-c', 'tox-flask-test.ini'], cwd=checkout_path) |
||||
return TestResult(name, checkout_path, rv, interpreters) |
||||
|
||||
|
||||
def run_tests(extensions, interpreters): |
||||
results = {} |
||||
create_tdir() |
||||
log('Packaging Flask') |
||||
flask_dep = package_flask() |
||||
log('Running extension tests') |
||||
log('Temporary Environment: %s', tdir) |
||||
for name in extensions: |
||||
log('Testing %s', name) |
||||
result = test_extension(name, interpreters, flask_dep) |
||||
if result.success: |
||||
log('Extension test succeeded') |
||||
else: |
||||
log('Extension test failed') |
||||
results[name] = result |
||||
return results |
||||
|
||||
|
||||
def render_results(results, approved): |
||||
from jinja2 import Template |
||||
items = results.values() |
||||
items.sort(key=lambda x: x.name.lower()) |
||||
rv = Template(RESULT_TEMPATE, autoescape=True).render(results=items, |
||||
approved=approved) |
||||
fd, filename = tempfile.mkstemp(suffix='.html') |
||||
os.fdopen(fd, 'w').write(rv.encode('utf-8') + '\n') |
||||
return filename |
||||
|
||||
|
||||
def main(): |
||||
parser = argparse.ArgumentParser(description='Runs Flask extension tests') |
||||
parser.add_argument('--all', dest='all', action='store_true', |
||||
help='run against all extensions, not just approved') |
||||
parser.add_argument('--browse', dest='browse', action='store_true', |
||||
help='show browser with the result summary') |
||||
parser.add_argument('--env', dest='env', default='py25,py26,py27', |
||||
help='the tox environments to run against') |
||||
parser.add_argument('--extension=', dest='extension', default=None, |
||||
help='tests a single extension') |
||||
args = parser.parse_args() |
||||
|
||||
if args.extension is not None: |
||||
only_approved = False |
||||
extensions = [args.extension] |
||||
else: |
||||
only_approved = not args.all |
||||
extensions = iter_extensions(only_approved) |
||||
|
||||
results = run_tests(extensions, [x.strip() for x in args.env.split(',')]) |
||||
filename = render_results(results, only_approved) |
||||
if args.browse: |
||||
import webbrowser |
||||
webbrowser.open('file:///' + filename.lstrip('/')) |
||||
print('Results written to {}'.format(filename)) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
Loading…
Reference in new issue